前言

上篇文章介绍了基于VC++的人脸美颜软件的具体原理和编程细节,其中提到了美白效果由于难度和时间关系,借用了另一套图像增强-非锐化掩蔽算法。本篇将着重介绍白平衡人脸美白算法,并给出基于MATLAB和C++的两种算法实现代码。

开发环境

Visual Studio 2012 + Opencv 2.4.9 +MFC框架
MATLAB R2016a

算法原理

白平衡法美白主要分为两个阶段
(1)近白色点的检测,作为参考白点
(2)根据近白点算出RGB调整比例

实现步骤

YCrCb空间介绍

YCrCb又称YUV,主要用于优化彩色视频信号的传输,使其向后兼容老式黑白电视。
Y分量表示图像的亮度成分
Cr分量表示图像红色部分与亮度值之间的差异
Cb分量表示图像蓝色部分与亮度值之间的差异
以lena图为例,分别展示YCrCb三通道的实际分离效果

Y分量

Cr分量

Cb分量

YCrCb的应用

(摘自百度百科)
在人脸检测中也常常用到YCrCb空间,因为一般的图像都是基于RGB空间的,在RGB空间里人脸的肤色受亮度影响相当大,所以肤色点很难从非肤色点中分离出来,也就是说在此空间经过处理后,肤色点是离散的点,中间嵌有很多非肤色,这为肤色区域标定(人脸标定、眼睛等)带来了难题。如果把RGB转为YCrCb空间的话,可以忽略Y(亮度)的影响,因为该空间受亮度影响很小,肤色会产生很好的类聚。这样就把三维的空间降为二维的CrCb,肤色点会形成一定得形状,如:人脸的话会看到一个人脸的区域,手臂的话会看到一条手臂的形态,对处理模式识别很有好处,根据经验某点的CrCb值满足:133≤Cr≤173,77≤Cb≤127 那么该点被认为是肤色点,其他的就为非肤色点。

参考白点检测

根据公式所计算得到的亮点矩阵Rl如下图所示,其中判别阈值Lu_min在180~190左右。

亮度矩阵Rl

RGB增益调整

原始图像经调整后的图像如下所示:

原始图像

调整后图像

MATLAB实现代码

im = imread('te.jpg');
im1=rgb2ycbcr(im);%将图片的RGB值转换成YCbCr值%
YY=im1(:,:,1);
Cb=im1(:,:,2);
Cr=im1(:,:,3);
[x y z]=size(im);
tst=zeros(x,y);
Mb=mean(mean(Cb));
Mr=mean(mean(Cr));
%计算Cb、Cr的均方差%
Tb = Cb-Mb;
Tr = Cr-Mr;
Db=sum(sum((Tb).*(Tb)))/(x*y);
Dr=sum(sum((Tr).*(Tr)))/(x*y);
%根据阀值的要求提取出near-white区域的像素点%
cnt=1;
for i=1:xfor j=1:yb1=Cb(i,j)-(Mb+Db*sign(Mb));b2=Cr(i,j)-(1.5*Mr+Dr*sign(Mr));if (b1<abs(1.5*Db) && b2<abs(1.5*Dr))Ciny(cnt)=YY(i,j);tst(i,j)=YY(i,j);cnt=cnt+1;endend
end
cnt=cnt-1;
iy=sort(Ciny,'descend');%将提取出的像素点从亮度值大的点到小的点依次排列%
nn=round(cnt/10);
Ciny2(1:nn)=iy(1:nn);%提取出near-white区域中10%的亮度值较大的像素点做参考白点%
%提取出参考白点的RGB三信道的值%
mn=min(Ciny2);
for i=1:xfor j=1:yif tst(i,j)<mntst(i,j)=0;elsetst(i,j)=1;endend
end
R=im(:,:,1);
G=im(:,:,2);
B=im(:,:,3);R=double(R).*tst;
G=double(G).*tst;
B=double(B).*tst;%计算参考白点的RGB的均值%
Rav=mean(mean(R));
Gav=mean(mean(G));
Bav=mean(mean(B));Ymax=double(max(max(YY)))*0.15;%计算出图片的亮度的最大值%%计算出RGB三信道的增益%
Rgain=Ymax/Rav;
Ggain=Ymax/Gav;
Bgain=Ymax/Bav;%通过增益调整图片的RGB三信道%
im(:,:,1)=im(:,:,1)*Rgain;
im(:,:,2)=im(:,:,2)*Ggain;
im(:,:,3)=im(:,:,3)*Bgain;imshow(im);

C++实现代码

 /*读取原始图片*/Mat src;int width = input_image.cols;int heigh = input_image.rows;input_image.copyTo(src);/*将图片从RGB空间转换至YCrCb空间*/Mat Y,Cr,Cb;Mat dst_YcrCb;vector<Mat> channels;cvtColor(src,dst_YcrCb,CV_BGR2YCrCb);split(dst_YcrCb,channels);Y = channels.at(0);Cr = channels.at(1);Cb = channels.at(2);/*分别计算Cr,Cb的平均值Mr,Mb*/double Mr,Mb;Mr = mean(Cr)[0];    //求Cr均值Mb = mean(Cb)[0];   //求Cb均值/*分别计算Cr,Cb的方差Dr,Db*/double Dr,Db;   Mat Tr,Tb;Tr = Cr - Mr;Tb = Cb - Mb;Db = sum(Tb.mul(Tb))[0]/(width*heigh);Dr = sum(Tr.mul(Tr))[0]/(width*heigh);/*设一个大小与图片相等的矩阵Rl,根据公式判断白色参考点Cb(i,j)-(Mb+Db) < 1.5*Db && Cr(i,j)-(1.5Mr+Dr) < 1.5*Dr若符合公式,把该点的亮度(Y分量)赋给Rl(i,j)若不符合公式,则该点的Rl(i,j)值为0*/Mat Rl(heigh,width,CV_8UC1,Scalar(0));Mat Ciny(1,width*heigh,CV_8UC1,Scalar(0));double b1,b2;int cnt = 0;for(int i = 0;i< heigh;i++){for(int j = 0;j< width;j++){b1 = Cb.at<uchar>(i,j) - (Mb + Db);b2 = Cr.at<uchar>(i,j) - (1.5 * Mr + Dr);if(b1 < 1.5*Db && b2 < 1.5*Dr){Ciny.at<uchar>(0,cnt) = Y.at<uchar>(i,j);Rl.at<uchar>(i,j) = Y.at<uchar>(i,j);cnt = cnt + 1;}}}/*提取参考白点中亮度较大的前10%,并选取其中的最小值Lu_min*/cv::sort(Ciny,Ciny,CV_SORT_DESCENDING);int nn = cvRound(cnt/10);   Mat Ciny2(1,nn,CV_8UC1,Scalar(0));for(int k = 0;k<nn;k++){Ciny2.at<uchar>(0,k) = Ciny.at<uchar>(0,k);}double maxx, minn;minMaxIdx(Ciny2, &minn, &maxx);/*调整Rl,若Rl(i,j)<Lu_min,Rl(i,j)=0,否则,Rl(i,j)=1*/for(int i = 0;i<heigh;i++){for(int j = 0;j<width;j++){if(Rl.at<uchar>(i,j) < minn){Rl.at<uchar>(i,j) = 0;}else{Rl.at<uchar>(i,j) = 255;}}}imshow("Rl",Rl);/*分别把R,G,B与Rl点乘,得到Rm,Gm,Bm*/Mat R,G,B;vector<Mat> channels_RGB;split(src,channels_RGB);R = channels_RGB.at(0);G = channels_RGB.at(1);B = channels_RGB.at(2);Mat Rm,Gm,Bm;Rm = R.mul(Rl/255.0);Gm = G.mul(Rl/255.0);Bm = B.mul(Rl/255.0);/*分别计算其均值,得到Rav,Gav,Bav*/double Rav,Bav,Gav;Rav = mean(Rm)[0];Gav = mean(Gm)[0];Bav = mean(Bm)[0];  /*Ymax = max(Y)*0.15,计算出图片中亮度最大值,其中Y为亮度值矩阵*/double Ymax;minMaxIdx(Y, NULL, &Ymax);Ymax = Ymax*0.15;/*计算调整增益*/double Rgain,Ggain,Bgain;Rgain = Ymax/Rav;Ggain = Ymax/Gav;Bgain = Ymax/Bav;/*调整RGB通道*/channels_RGB.at(0) = channels_RGB.at(0) * Rgain;channels_RGB.at(1) = channels_RGB.at(1) * Ggain;channels_RGB.at(2) = channels_RGB.at(2) * Bgain;/*合并RGB通道*/Mat output_image;merge(channels_RGB,output_image);imshow("in",input_image);

总结

1.将图片从RGB空间转换至YCrCb空间时使用到cvtColor函数

cvtColor(src,dst_YcrCb,CV_BGR2YCrCb);

该函数有CV_BGR2YCrCb和CV_RGB2YCrCb两种参数,使用时注意区别
另:opencv和matlab在处理彩色图像时,RGB通道的存储顺序是相反的
matlab的顺序是R,G,B,opencv的顺序是B,G,R

2.设置亮度矩阵Rl时的参数如下所示

Mat Rl(heigh,width,CV_8UC1,Scalar(0));

其中CV_8UC1表示图像的数据类型,8U为无符号整型8bit数据(uint8),C1表示1个通道

3.在对参考白点进行排序处理时,注意区别sort函数的命名空间是cv还是std

cv::sort(Ciny,Ciny,CV_SORT_DESCENDING);



4.C++代码中的这两段中,设置Rl(i,j)为255是为了查看亮度矩阵的检测效果,实际运行中去除这两步后,结果是一致的。

 for(int i = 0;i<heigh;i++){for(int j = 0;j<width;j++){if(Rl.at<uchar>(i,j) < minn){Rl.at<uchar>(i,j) = 0;}else{Rl.at<uchar>(i,j) = 255; // = 1}}}//imshow("Rl",Rl);
 Mat Rm,Gm,Bm;Rm = R.mul(Rl/255.0); //RlGm = G.mul(Rl/255.0);  //RlBm = B.mul(Rl/255.0)   //Rl

心得体会

关于人脸美颜软件的研究算是告一段落了,第一次听说这个题目还是在18年,据学长说他使用二维指针完成了美白算法,因为自己指针学的一直不好,所以潜意识里觉得美白算法很难。
去年自己做的时候,尝试不用二维指针写白平衡美白算法,但是在写判断参考白点的时候卡住,只能作罢,答辩的时候老师问用到的美白原理是什么,也是支支吾吾。
这次重写美白算法花了两天时间,总结下来,主要是由于对数据类型和基本矩阵运算函数不熟悉导致当时未能完成,比如遍历数组时用到的uchar类型和Vec3d类型,以及sum求和,mean求均值,sort排序等等。此外,搭界面写算法只花了三天时间,剩下时间都在带别人做和优化自己的界面上,花费了不少精力。
数字图像处理这门课如果好好学,还是很有意思的,当时熬了一个通宵连做了6份作业,而且大部分内容借用opencv库函数都能完成,所以上手难度并不大。
最后附上《数字图像处理(第三版)》(何东健著)的相关参考代码的的网盘链接。
链接: https://pan.baidu.com/s/13bDzqUxY26oyRqNJYNugMw 提取码: udnf

数字图像处理(3) — 基于白平衡的人脸美白算法相关推荐

  1. 数字图像处理(2) — 基于VC++环境的人脸美颜软件

    开发环境: VS2012+MFC+Opencv2.4.9 实验目的: 利用VC++实现人脸美化软件,要求: 1.具有人脸美化界面: 2.具有磨皮功能,参数可调: 3.具有美白功能,参数可调: 实验原理 ...

  2. 基于opencv-python的人脸识别算法

    基于opencv-python的人脸识别算法 文章目录 基于opencv-python的人脸识别算法 前言 一.opencv-python的安装与配置 二.实现步骤 1.引入库 2.调用opencv自 ...

  3. 基于MATLAB的人脸识别算法的研究

    基于MATLAB的人脸识别算法的研究 作者:lee神 现如今机器视觉越来越盛行,从智能交通系统的车辆识别,车牌识别到交通标牌的识别:从智能手机的人脸识别的性别识别:如今无人驾驶汽车更是应用了大量的机器 ...

  4. 基于matlab的人脸识别算法

    基于matlab的人脸识别算法 1. 主成分的数目的选取 前已指出,设有p个随机变量,便有p个主成分.由于总方差不增不减,C1,C2等前几个综合变量的方差较大,而Cp,Cp-1等后几个综合变量的方差较 ...

  5. 数字图像处理:基于MATLAB的车牌识别项目

    学过了数字图像处理,就进行一个综合性强的小项目来巩固一下知识吧.前阵子编写调试了一套基于MATLAB的车牌识别的项目的代码.今天又重新改进了一下代码,识别的效果好一点了,也精简了一些代码.这里没有使用 ...

  6. 数字图像处理-python基于opencv代码实现 反转变换、对数变换和幂律(伽马)变换

    本文主要介绍对<数字图像处理>第三章书中示例图片实现 反转变换.对数变换以及伽马变换的代码 若要获取更多数字图像处理,python,深度学习,机器学习,计算机视觉等高清PDF以及 更多有意 ...

  7. DeepMindVGG提出基于集合的人脸识别算法GhostVLAD,精度远超IJB-B数据集state-of-the-art...

    点击我爱计算机视觉标星,更快获取CVML新技术 在人脸识别应用中,很多场景能够获取某一个体的多幅人脸图像的集合(比如在监控视频中),使用人脸图像集来做识别,这个问题被称为基于模板的人脸识别(templ ...

  8. 实现人脸美白算法---OpenCV-Python开发指南(59)

    目录 人脸美白原理 实现人脸美白 人脸美白原理 人脸美白原理说透了,就是一种图像的颜色空间处理,所以我们需要通过颜色空间进行设计. 不过,我们先来参考以下PS对于图像美白的处理步骤: 首先,新建一个图 ...

  9. 基于matlab的人脸美白,人脸识别SDK的使用会对美颜功能造成怎样的影响

    有很多开发者在开发APP时考虑到给用户提供更好的美颜体验,都会选择使用人脸识别SDK.说实话现在哪个玩社交的平台不是拥有高质量美颜特效的?但要是想实现高质量的美颜功能可不是件简单事儿.所以本文来给大家 ...

最新文章

  1. 3.逆向分析Hello World!程序-下
  2. NTP-Windows 2008和win7下开启网络对时方法
  3. 论文代码解读 Hierarchical Reinforcement Learning for Scarce Medical Resource Allocation
  4. SAP FI新手常用代码
  5. Java 并发基础——线程安全性
  6. Elasticsearch5中安装Elasticsearch-head插件
  7. java-弹簧布局(自适应窗口)
  8. Crash的数字表格(HYSBZ-2154)
  9. 使用Thread包装类进行多线程操作
  10. 【人物志】美团技术委员会前端通道主席洪磊:爱折腾的斜杠青年
  11. PyCharm下载和安装
  12. Java开源项目管理工具大全
  13. ROC受试曲线AUC[TPR/ FPR/截断点/StratifiedKFold/KFold]
  14. js按钮确认删除提示
  15. tflearn教程_TFlearn 快速入门
  16. 超700万个NFT存储在星际文件系统网络上,总量超54TiB
  17. 【毕业设计】毕业设计的ppt中的模版相关设计和内容实现——为了将我的毕设整得好一些
  18. Android中Activity各种页面跳转并传值(Activity -> Activity)(Activity -> Fragment)(Activity -> Service)
  19. 天朝挖煤的题已经不会做了。。
  20. jsp标签jsp:useBean用法

热门文章

  1. C语言例题:输入某年某月某日,判断这一天是这一年的第几天?
  2. 解决vnc客户端不能拷贝粘贴
  3. PMP思维导图—项目经理的角色
  4. CSS实现首行缩进和悬挂缩进
  5. 微信备份到云服务器失败怎么回事,iCloud云备份失败是为什么呢?iCloud云备份启用失败如何解决...
  6. 如何选择第三方电子合同服务平台?
  7. Activiti6 流程模型图中文显示为方块□□
  8. pc二维码支付demo(支付宝/微信)
  9. 小新air15一键还原后,单击鼠标右键一直转圈
  10. 计算机科学与技术本科相当于计算机几级,软件工程的学生毕业后计算机等级算几级?...