皮肤检测及对检测到皮肤单独校色 (基于自动白平衡)

2024-06-08 18:32

本文主要是介绍皮肤检测及对检测到皮肤单独校色 (基于自动白平衡),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原理见前几篇博客,修改修改可以做美颜的程序直接贴代码:

/*对照片中的皮肤单独进行较色,然后塞进原始图片作为输出*/
/*包含皮肤的检测、皮肤的校正两步*/
/*单张照片测试效果不错,但对于一百多张照片,结果还是有偏差,这种单独校正然后再用于贴图的方法 行不通*/
/*时间:2015.8.24*/
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/face.hpp>
#include <opencv2/imgproc/imgproc.hpp>  
#include <iostream>  
#include <vector>  using namespace std;  
using namespace cv;  
double baidianave(Mat frame,int n)
{  int a[256];for (int i=0;i<256;i++){a[i]=0;}double sum=0;double ave;for (int i=0;i<n;i++){int d=frame.at<double>(0,i);a[d]++;}int n0=255;for (int k=255;k>0;k--){sum+=a[k];if (sum>frame.rows*frame.cols/25){break;}n0--;}sum=0;for (int i=n0;i<256;i++){sum+=a[i]*i;}ave=sum/(frame.rows*frame.cols/25);return ave;
}
double baidianave(Mat frame)
{ int a[256];
//cvZero(a);for (int i=0;i<256;i++){a[i]=0;}double sum=0;double ave;for (int i=0;i<frame.rows;i++){for (int j=0;j<frame.cols;j++){int d=(int)frame.at<uchar>(i,j);a[d]++;}}int n0=255;for (int k=255;k>0;k--){sum+=a[k];if (sum>frame.rows*frame.cols/25){break;}n0--;}sum=0;for (int i=n0;i<256;i++){sum+=a[i]*i;}ave=sum/(frame.rows*frame.cols/25);return ave;}Mat input_image;  
Mat output_mask;  
Mat output_image;  
Mat mask;  int main(int argc,char *argv[])  
{  if (2 != argc) {cout << "Please enter the image list!" <<endl;return -1;}vector<string>  file_names;FILE *file_list =  fopen(argv[1],"r");char buf[255];memset(&buf,0,sizeof(buf));while(fgets(buf,255,file_list)){if(buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0';file_names.push_back(string(buf));}fclose(file_list);int count = file_names.size();Mat skinCrCbHist = Mat::zeros(Size(256, 256), CV_8UC1);  ellipse(skinCrCbHist, Point(113, 155.6), Size(25,12), -20, 0.0, 360.0, Scalar(255, 255, 255), -1);  Mat element = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1) );  for(int  i=0; i<count; i++){  string img_nm = file_names[i];string img_mask = "mask" + img_nm;int pos = img_nm.rfind('.');string img_fmt = img_nm.substr(pos+1);if("jpg" != img_fmt){cout << "Unknown format: " << img_fmt << endl;continue;}input_image=imread(img_nm,1);  if(input_image.empty())  return 0;  Mat ycrcb_image;  output_mask = Mat::zeros(input_image.size(), CV_8UC1);  cvtColor(input_image, ycrcb_image, CV_BGR2YCrCb); CvScalar s;s.val[0]=0;s.val[1]=0;s.val[2]=255;for(int i = 0; i < input_image.rows; i++) {  uchar* p = (uchar*)output_mask.ptr<uchar>(i);  Vec3b* ycrcb = (Vec3b*)ycrcb_image.ptr<Vec3b>(i);  for(int j = 0; j < input_image.cols; j++)  {  if(skinCrCbHist.at<uchar>(ycrcb[j][1], ycrcb[j][2]) > 0)  {// input_image.at<Vec3b>(i,j)[2]=255;p[j] = 255;  }}  }     // imwrite("test.jpg",input_image);morphologyEx(output_mask,output_mask,MORPH_CLOSE,element);   vector< vector<Point> > contours;   vector< vector<Point> > filterContours; vector< Vec4i > hierarchy;   contours.clear();    hierarchy.clear();   filterContours.clear();  findContours(output_mask, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);    for (size_t i = 0; i < contours.size(); i++)   {  if (fabs(contourArea(Mat(contours[i]))) > 2000&&fabs(arcLength(Mat(contours[i]),true))>500) filterContours.push_back(contours[i]);  }  output_mask.setTo(0);  drawContours(output_mask, filterContours, -1, Scalar(255,0,0), CV_FILLED);     input_image.copyTo(output_image, output_mask);  Mat tempimage=Mat::zeros(input_image.size(), CV_8UC3); threshold(output_mask,output_mask,20, 255, THRESH_BINARY);cvtColor(output_mask,output_mask,CV_GRAY2BGR);Mat frame=Mat::zeros(input_image.size(), CV_8UC3); output_image.copyTo(frame);// imshow("frame",frame);// waitKey(0);//cout<<frame.rows<<"  "<<frame.cols<<endl;// cvShowImage("处理前图像",frame);int heightyiban=frame.rows;int widthyiban=frame.cols;double Ysum=0;//Y的总和double Cbsum[4]={0,0,0.0};//图像分成四部分,每部分Cb的总和double Crsum[4]={0,0,0,0};//图像分成四部分,每部分Cr的总和double Mb[4],Db[4];//图像分成四部分,每部分Cb的均值和均方差double Mr[4],Dr[3];//Cr的均值和均方差  Mat imageYCrCb =  Mat::zeros(frame.size(), CV_8UC3);Mat imageCb = Mat::zeros(frame.size(), CV_8UC1);Mat imageCr = Mat::zeros(frame.size(), CV_8UC1);Mat imageY = Mat::zeros(frame.size(), CV_8UC1);// imageYCrCb = cvCreateImage(cvGetSize(frame),8,3);   // imageCb = cvCreateImage(cvGetSize(frame),8,1);  // imageCr = cvCreateImage(cvGetSize(frame),8,1); // imageY = cvCreateImage(cvGetSize(frame),8,1); cvtColor(frame,imageYCrCb,CV_BGR2YCrCb); std::vector<cv::Mat>ybr(imageYCrCb.channels());split(imageYCrCb,ybr);// namedWindow("test",0);// imshow("test",ybr[2]);// waitKey(0);//分成三个通道,,,// imageY,imageCr,imageCbMat imageb=Mat::zeros(frame.size(), CV_8UC1);Mat imagec=Mat::zeros(frame.size(), CV_8UC1);ybr[1].copyTo(imageb);ybr[2].copyTo(imagec);Mat  savg,sfangcha;//全局scalar 变量用来放平均值和方差meanStdDev(ybr[2],savg,sfangcha);// cvAvgSdv(imageb,&savg,&sfangcha,NULL);// cout<<savg.at<double>(0)<<endl;// cout<<sfangcha.at<double>(0)<<endl;Mb[0]=savg.at<double>(0);cout<<"Mb:  "<<Mb[0]<<endl;Db[0]=sfangcha.at<double>(0);//求出第一部分cb的均值和均方差cout<<"Db:  "<<Db[0]<<endl;// cvAvgSdv(imagec,&savg,&sfangcha,NULL);meanStdDev(ybr[1],savg,sfangcha);Mr[0]=savg.at<double>(0);cout<<"Mr:  "<<Mr[0]<<endl;Dr[0]=sfangcha.at<double>(0);;//求出第一部分cr的均值和均方差cout<<"Dr:  "<<Dr[0]<<endl;double b[4],c[4];for (int i=0;i<1;i++){if (Mb[i]<0)//计算mb+db*sign(mb){ b[i]=Mb[i]+Db[i]*(-1);}elseb[i]=Mb[i]+Db[i];}for (int i=0;i<4;i++){if (Mr[i]<0)//计算1.5*mr+dr*sign(mb);{c[i]=1.5*Mr[i]+Dr[i]*(-1);}elsec[i]=1.5*Mr[i]+Dr[i];}double Ymax=baidianave(ybr[0]);//下面是对第一部分进行白点的选择Mat Bbaidian=Mat::zeros(1,6000000,CV_64FC1);Mat Gbaidian=Mat::zeros(1,6000000,CV_64FC1);Mat Rbaidian=Mat::zeros(1,6000000,CV_64FC1);//CvScalar s1;int n1=0;cout<<"b[0]:   "<<b[0]<<"  c[0]:  "<<c[0]<<endl;for (int i=0;i<heightyiban;i++){for (int j=0;j<widthyiban;j++){// input_image.at<Vec3b>(i,j)[2]=255if (((ybr[2].at<uchar>(i,j)-b[0])<(1.5*Db[0]))&&((ybr[1].at<uchar>(i,j)-c[0])<(1.5*Dr[0]))){double d1=frame.at<Vec3b>(i,j)[0];Bbaidian.at<double>(0,n1)=d1;double d2=frame.at<Vec3b>(i,j)[1];Gbaidian.at<double>(0,n1)=d2;double d3=frame.at<Vec3b>(i,j)[2];Rbaidian.at<double>(0,n1)=d3;n1++;}}}// cout<<"n1:  "<<n1<<endl;double Bave1=baidianave(Bbaidian,n1);double Gave1=baidianave(Gbaidian,n1);double Rave1=baidianave(Rbaidian,n1);cout<<"Bave1:  "<<Bave1<<"    Gave1:  "<<Gave1<<"      Rave1:   "<<Rave1<<"  Ymax:  "<<Ymax<<endl;Ymax=Ymax;double Bgain1=Ymax/(Bave1);double Ggain1=Ymax/(Gave1);double Rgain1=Ymax/(Rave1);// CvScalar s1;// cout<<Bgain1<<"  "<<Ggain1<<"  "<<Rgain1<<endl; // int count_out=0;for (int i=0;i<heightyiban;i++){for (int j=0;j<widthyiban;j++){int tb=Bgain1*frame.at<Vec3b>(i,j)[0];int tg=Ggain1*frame.at<Vec3b>(i,j)[1];int tr=Rgain1*frame.at<Vec3b>(i,j)[2];if (tb>255){tb=255;// count_out++;}if (tg>255){tg=255;// count_out++;}if (tr>255){tr=255;// count_out++;}frame.at<Vec3b>(i,j)[0]=tb;frame.at<Vec3b>(i,j)[1]=tg;frame.at<Vec3b>(i,j)[2]=tr;}}// cout<<count_out<<endl;imwrite("frame.jpg",frame);        // cout<<"Finish!"<<endl;imwrite("img_nm1.jpg",input_image);     for(int i = 0; i < input_image.rows; i++) {  uchar* p = (uchar*)output_mask.ptr<uchar>(i);  uchar* p2 = (uchar*)input_image.ptr<uchar>(i);  uchar* p3 = (uchar*)frame.ptr<uchar>(i);  for(int j = 0; j < 3*input_image.cols; )  {  if(p[j] != 0)  {// cout<<"p:  "<<i<<"   "<<j<<"  "<<float(p[j])<<endl;// input_image.at<Vec3b>(i,j)[2]=255;p2[j]=0;p2[j] = p3[j++];  // cout<<"B:   "<<int (p2[j-1])<<"  ";p2[j]=0;p2[j] = p3[j++];  // cout<<"G:  "<<int (p2[j-1])<<"  ";p2[j]=0;p2[j] = p3[j++];  // cout<<"R:  "<<int (p2[j-1])<<endl;;// cout<<"p2:  "<<i<<"   "<<j<<"  "<<float(p2[j])<<endl;}elsej++;}  }// Mat tempimage=Mat::zeros(input_image.size(), CV_8UC3); // cvtColor(output_mask,tempimage,CV_GRAY2BGR);// imwrite("output_mask.jpg",output_mask); // imwrite("tempimage.jpg",tempimage);     imwrite(img_nm,input_image);     imwrite(img_mask,output_image);// imwrite(img_mask,output_mask);// namedWindow("input image",0);// // namedWindow("output mask",0);// namedWindow("output image",0);// imshow("input image", input_image);  // imshow("output image", output_image);  cout<<"Finish!"<<endl;// output_image.setTo(0);  // waitKey(0);}  return 0;  
} 


这篇关于皮肤检测及对检测到皮肤单独校色 (基于自动白平衡)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1042972

相关文章

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

烟火目标检测数据集 7800张 烟火检测 带标注 voc yolo

一个包含7800张带标注图像的数据集,专门用于烟火目标检测,是一个非常有价值的资源,尤其对于那些致力于公共安全、事件管理和烟花表演监控等领域的人士而言。下面是对此数据集的一个详细介绍: 数据集名称:烟火目标检测数据集 数据集规模: 图片数量:7800张类别:主要包含烟火类目标,可能还包括其他相关类别,如烟火发射装置、背景等。格式:图像文件通常为JPEG或PNG格式;标注文件可能为X

基于 YOLOv5 的积水检测系统:打造高效智能的智慧城市应用

在城市发展中,积水问题日益严重,特别是在大雨过后,积水往往会影响交通甚至威胁人们的安全。通过现代计算机视觉技术,我们能够智能化地检测和识别积水区域,减少潜在危险。本文将介绍如何使用 YOLOv5 和 PyQt5 搭建一个积水检测系统,结合深度学习和直观的图形界面,为用户提供高效的解决方案。 源码地址: PyQt5+YoloV5 实现积水检测系统 预览: 项目背景

JavaFX应用更新检测功能(在线自动更新方案)

JavaFX开发的桌面应用属于C端,一般来说需要版本检测和自动更新功能,这里记录一下一种版本检测和自动更新的方法。 1. 整体方案 JavaFX.应用版本检测、自动更新主要涉及一下步骤: 读取本地应用版本拉取远程版本并比较两个版本如果需要升级,那么拉取更新历史弹出升级控制窗口用户选择升级时,拉取升级包解压,重启应用用户选择忽略时,本地版本标志为忽略版本用户选择取消时,隐藏升级控制窗口 2.

基于51单片机的自动转向修复系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 单片机

Python3 BeautifulSoup爬虫 POJ自动提交

POJ 提交代码采用Base64加密方式 import http.cookiejarimport loggingimport urllib.parseimport urllib.requestimport base64from bs4 import BeautifulSoupfrom submitcode import SubmitCodeclass SubmitPoj():de

[数据集][目标检测]血细胞检测数据集VOC+YOLO格式2757张4类别

数据集格式:Pascal VOC格式+YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):2757 标注数量(xml文件个数):2757 标注数量(txt文件个数):2757 标注类别数:4 标注类别名称:["Platelets","RBC","WBC","sickle cell"] 每个类别标注的框数:

Temu官方宣导务必将所有的点位材料进行检测-RSL资质检测

关于饰品类产品合规问题宣导: 产品法规RSL要求 RSL测试是根据REACH法规及附录17的要求进行测试。REACH法规是欧洲一项重要的法规,其中包含许多对化学物质进行限制的规定和高度关注物质。 为了确保珠宝首饰的安全性,欧盟REACH法规规定,珠宝首饰上架各大电商平台前必须进行RSLReport(欧盟禁限用化学物质检测报告)资质认证,以确保产品不含对人体有害的化学物质。 RSL-铅,

Shell脚本实现自动登录服务器

1.登录脚本 login_server.sh #!/bin/bash# ReferenceLink:https://yq.aliyun.com/articles/516347#show all host infos of serverList.txtif [[ -f ./serverList.txt ]]thenhostNum=`cat ./serverList.txt | wc -l`e

Jenkins 通过 Version Number Plugin 自动生成和管理构建的版本号

步骤 1:安装 Version Number Plugin 登录 Jenkins 的管理界面。进入 “Manage Jenkins” -> “Manage Plugins”。在 “Available” 选项卡中搜索 “Version Number Plugin”。选中并安装插件,完成后可能需要重启 Jenkins。 步骤 2:配置版本号生成 打开项目配置页面。在下方找到 “Build Env