(1)了解和掌握图像处理工具 Matlab ,熟悉基于 Matlab 的图像处理函数,并为下一步编程进行图像处理打下基础。
(2)理解色彩的概念,掌握图像代数运算,几何变换方法。
1.灰度线性变换就是将图像中所有点的灰度按照线性灰度变换函数进行变换。
2.直方图均衡化通过点运算将输入图像转换为在每一级上都有相等像素点数的输出图像。
3.图像算术运算:两幅输入图像之间进行的点对点的加、减、乘、除运算后得到输出图像的过程。
4.图像插值是一种基本的图像处理方法,它可以为数字图像增加或减少像素的数目。
当图像被放大时,像素会相应地增加,该像素增加的过程实际就是插值程序自动选择信息较好的像素作为新的像素以弥补空白像素空间的过程。虽然经过插值后图像可以变得更平滑、干净,但由于新增加的像素也仅仅只是原始像素的某种组合而已,所以图像的插值运算并不会增加新的图像信息。
代码:
%1.主程序
clear,clc,close all;
ImageOrigin=im2double(imread('lotus1.bmp'));
figure,imshow(ImageOrigin),title('原图');
DBImage=DBfilt(ImageOrigin); %双边滤波
SkinImage1=FirstFilter(ImageOrigin); %%初步过滤
SkinArea=SecondFilter(SkinImage1); %%YCgCr空间范围肤色检测
SkinFuse=Fuse(ImageOrigin,DBImage,SkinArea);%图像融合
SkinBeautify=Sharp(SkinFuse); %图像锐化
Meibai=MB(SkinBeautify);
代码:
%2.图像平滑
function Out=DBfilt(In)
[height,width,c] = size(In);
win=15; % 定义双边滤波窗口宽度
sigma_s=6; sigma_r=0.1; % 双边滤波的两个标准差参数
[X,Y] = meshgrid(-win:win,-win:win);
Gs = exp(-(X.^2+Y.^2)/(2*sigma_s^2));%计算邻域内的空间权值
Out=zeros(height,width,c);
for k=1:c
for j=1:height
for i=1:width
temp=In(max(j-win,1):min(j+win,height),max(i-win,1):min(i+win,width),k);
Gr = exp(-(temp-In(j,i,k)).^2/(2*sigma_r^2));%计算灰度邻近权值
% W为空间权值Gs和灰度权值Gr的乘积
W = Gr.*Gs((max(j-win,1):min(j+win,height))-j+win+1,(max(i-win,1):min(i+win,width))-i+win+1);
Out(j,i,k)=sum(W(:).*temp(:))/sum(W(:));
end
end
end
figure,imshow(Out),title('双边滤波');
end
代码:
%3.皮肤区域分割
%3.1基于RGB空间的非肤色像素初步过滤
function Out=FirstFilter(In)
Out=In;
[height,width,c] = size(In);
IR=In(:,:,1); IG=In(:,:,2);IB=In(:,:,3);
for j=1:height
for i=1:width
if (IR(j,i)<160/255 && IG(j,i)<160/255 && IB(j,i)<160) && (IR(j,i)>IG(j,i) && IG(j,i)>IB(j,i))
Out(j,i,:)=0;
end
if IR(j,i)+IG(j,i)>500/255
Out(j,i,:)=0;
end
if IR(j,i)<70/255 && IG(j,i)<40/255 && IB(j,i)<20/255
Out(j,i,:)=0;
end
end
end
figure,imshow(Out);title('非肤色初步过滤');
end
代码:
%3.2基于YCgCr空间范围肤色分割
function Out=SecondFilter(In)
IR=In(:,:,1); IG=In(:,:,2);IB=In(:,:,3);
[height,width,c] = size(In);
Out=zeros(height,width);
for i=1:width
for j=1:height
R=IR(j,i); G=IG(j,i); B=IB(j,i);
Cg=(-81.085)*R+(112)*G+(-30.915)*B+128;
Cr=(112)*R+(-93.786)*G+(-18.214)*B+128;
if Cg>=85 && Cg<=135 && Cr>=-Cg+260 && Cr<=-Cg+280
Out(j,i)=1;
end
end
end
Out=medfilt2(Out,[3 3]);
figure,imshow(Out),title('YCgCr空间范围肤色检测');
end
代码:
%4.图像融合
function Out=Fuse(ImageOrigin,DBImage,SkinArea)
Skin=zeros(size(ImageOrigin));
Skin(:,:,1)=SkinArea;
Skin(:,:,2)=SkinArea;
Skin(:,:,3)=SkinArea;
Out=DBImage.*Skin+double(ImageOrigin).*(1-Skin);
figure,imshow(Out);title('肤色与背景图像融合');
end
代码:
%5.图像锐化
function Out=Sharp(In)
H=[0 -1 0;-1 4 -1;0 -1 0]; %Laplacian锐化模板
Out(:,:,:)=imfilter(In(:,:,:),H);
Out=Out/3+In;
% imwrite(Out,'man4.jpg');
figure,imshow(Out),title('Laplacia锐化图像');
end
皮肤的亮白处理采用白平衡法
美白主要分为两个阶段
(1)近白色点的检测,作为参考白点
(2)根据近白点算出RGB调整比例
YCrCb空间介绍
YCrCb又称YUV,主要用于优化彩色视频信号的传输,使其向后兼容老式黑白电视。
Y分量表示图像的亮度成分
Cr分量表示图像红色部分与亮度值之间的差异
Cb分量表示图像蓝色部分与亮度值之间的差异
以lena图为例,分别展示YCrCb三通道的实际分离效果
代码:
im = imread('face10.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:x
for j=1:y
b1=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;
end
end
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:x
for j=1:y
if tst(i,j)<mn
tst(i,j)=0;
else
tst(i,j)=1;
end
end
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),title('皮肤亮白处理');
代码:
%1.主程序
clear,clc,close all;
ImageOrigin=im2double(imread('lotus1.bmp'));
figure,imshow(ImageOrigin),title('原图');
DBImage=DBfilt(ImageOrigin); %双边滤波
SkinImage1=FirstFilter(ImageOrigin); %%初步过滤
SkinArea=SecondFilter(SkinImage1); %%YCgCr空间范围肤色检测
SkinFuse=Fuse(ImageOrigin,DBImage,SkinArea);%图像融合
SkinBeautify=Sharp(SkinFuse); %图像锐化
Meibai=MB(SkinBeautify);
%2.图像平滑
function Out=DBfilt(In)
[height,width,c] = size(In);
win=15; % 定义双边滤波窗口宽度
sigma_s=6; sigma_r=0.1; % 双边滤波的两个标准差参数
[X,Y] = meshgrid(-win:win,-win:win);
Gs = exp(-(X.^2+Y.^2)/(2*sigma_s^2));%计算邻域内的空间权值
Out=zeros(height,width,c);
for k=1:c
for j=1:height
for i=1:width
temp=In(max(j-win,1):min(j+win,height),max(i-win,1):min(i+win,width),k);
Gr = exp(-(temp-In(j,i,k)).^2/(2*sigma_r^2));%计算灰度邻近权值
% W为空间权值Gs和灰度权值Gr的乘积
W = Gr.*Gs((max(j-win,1):min(j+win,height))-j+win+1,(max(i-win,1):min(i+win,width))-i+win+1);
Out(j,i,k)=sum(W(:).*temp(:))/sum(W(:));
end
end
end
figure,imshow(Out),title('双边滤波');
end
%3.皮肤区域分割
%3.1基于RGB空间的非肤色像素初步过滤
function Out=FirstFilter(In)
Out=In;
[height,width,c] = size(In);
IR=In(:,:,1); IG=In(:,:,2);IB=In(:,:,3);
for j=1:height
for i=1:width
if (IR(j,i)<160/255 && IG(j,i)<160/255 && IB(j,i)<160) && (IR(j,i)>IG(j,i) && IG(j,i)>IB(j,i))
Out(j,i,:)=0;
end
if IR(j,i)+IG(j,i)>500/255
Out(j,i,:)=0;
end
if IR(j,i)<70/255 && IG(j,i)<40/255 && IB(j,i)<20/255
Out(j,i,:)=0;
end
end
end
figure,imshow(Out);title('非肤色初步过滤');
end
%3.2基于YCgCr空间范围肤色分割
function Out=SecondFilter(In)
IR=In(:,:,1); IG=In(:,:,2);IB=In(:,:,3);
[height,width,c] = size(In);
Out=zeros(height,width);
for i=1:width
for j=1:height
R=IR(j,i); G=IG(j,i); B=IB(j,i);
Cg=(-81.085)*R+(112)*G+(-30.915)*B+128;
Cr=(112)*R+(-93.786)*G+(-18.214)*B+128;
if Cg>=85 && Cg<=135 && Cr>=-Cg+260 && Cr<=-Cg+280
Out(j,i)=1;
end
end
end
Out=medfilt2(Out,[3 3]);
figure,imshow(Out),title('YCgCr空间范围肤色检测');
end
%4.图像融合
function Out=Fuse(ImageOrigin,DBImage,SkinArea)
Skin=zeros(size(ImageOrigin));
Skin(:,:,1)=SkinArea;
Skin(:,:,2)=SkinArea;
Skin(:,:,3)=SkinArea;
Out=DBImage.*Skin+double(ImageOrigin).*(1-Skin);
figure,imshow(Out);title('肤色与背景图像融合');
end
%5.图像锐化
function Out=Sharp(In)
H=[0 -1 0;-1 4 -1;0 -1 0]; %Laplacian锐化模板
Out(:,:,:)=imfilter(In(:,:,:),H);
Out=Out/3+In;
% imwrite(Out,'man4.jpg');
figure,imshow(Out),title('Laplacia锐化图像');
end
%6.皮肤亮白处理
function Out=MB(SkinBeautify)
%im = imread('face9.jpg');
Out=rgb2ycbcr(SkinBeautify);%将图片的RGB值转换成YCbCr值%
YY=Out(:,:,1);
Cb=Out(:,:,2);
Cr=Out(:,:,3);
[x y z]=size(SkinBeautify);
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:x
for j=1:y
b1=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;
end
end
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:x
for j=1:y
if tst(i,j)<mn
tst(i,j)=0;
else
tst(i,j)=1;
end
end
end
R=SkinBeautify(:,:,1);
G=SkinBeautify(:,:,2);
B=SkinBeautify(:,:,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三信道%
SkinBeautify(:,:,1)=SkinBeautify(:,:,1)*Rgain;
SkinBeautify(:,:,2)=SkinBeautify(:,:,2)*Ggain;
SkinBeautify(:,:,3)=SkinBeautify(:,:,3)*Bgain;
figure,imshow(Out),title('皮肤美化');
end
肤色检测
肤色是人类皮肤重要特征之一,在检测人脸或手等目标时常采用肤色检测的方法,将相关区域从图像中分割出来。
肤色检测方法:
肤色检测方法有很多,但无论是基于不同的色彩空间还是不同的肤色模型,其根本出发点在于肤色分布的聚集性,即肤色的颜色分量一般聚集在某个范围内。通过大量的肤色样本进行统计,找出肤色颜色分量的聚集范围或用特殊的分布模型去模拟肤色分布,进而实现对任意像素颜色的判别。
本例主要采用肤色颜色分量分布范围的方法,简要介绍肤色模型的概念。
不同彩色空间肤色分布范围
肤色模型
肤色模型是根据大量样本的统计数据建立以确定肤色的分布规律,进而判断像素的色彩是否属于肤色或与肤色相似程度的模型。常用的有阙值模型、高斯模型和椭圆模型。
1)阈值模型
國值模型是用数学表达式明确肤色分布范围的建模方法。这类方法依据肤色分布范围进行检测,判断简单、明确、快捷,但需要选择合适的颜色空间及合适的参数。
2)高斯肤色模型
利用高斯函数模拟肤色在CbCr色度空间的分布
为色度向量的均值和协方差矩阵,可通过多种方式获取,数值略有区别,本例选择
得到肤色分布的概率图后,确定阈值T,如果p>T,则对应像素点为肤色点﹔反之,为非像素点。可以看出,肤色检测的精确度依赖于阈值的选择
在下面示例中,不讨论最佳阈值的确定,采用固定阈值的方法,实施效果因不同图像而异;
3)椭圆模型
将图像从RGB转换到YCbCr彩色空间,并进行非线性分段色彩变换,变换后肤色的CbCr分布近似椭圆,经实验可确定椭圆表达式的参数。对于待判断的颜色,经同样的变换,若在椭圆内,则可以判断其为肤色,否则为非肤色;
检测出的肤色区域存在不连续、噪声大的特点,往往需要利用滤波等方法,修正肤色区域,建议在后续学习过滤波方法后,改进相应的程序。
代码:
clear,clc,close all;
Image=imread('lotus1.bmp');
figure,imshow(Image),title('原图');
r=double(Image(:,:,1)); % 提取红色分量并转化为高精度
g=double(Image(:,:,2));
b=double(Image(:,:,3));
[N,M]=size(r); % 提取矩阵r的大小 NxM
miu=[117.4361 156.5599]'; % 高斯肤色模型均值
sigma=[160.1301 12.1430;12.1430 299.4574]; % 高斯肤色模型协方差矩阵
cbcr=zeros(2,1); % 生成 2x1矩阵
SkinCbCrG=zeros(N,M); % 生成所有值为0的 NxM矩阵用于存放处理后图像
SkinRGB=zeros(N,M);
SkinHSV=zeros(N,M);
SkinCbCr=zeros(N,M);
thresh=0.35; % 肤色概率二值化阙值
for i=1:M % 循环图像每一个像素点 列循环
for j=1:N % 行循环
R=r(j,i); % 将图像红色分量中(j,i)点值赋值给R
G=g(j,i);
B=b(j,i);
if (R>95 && G>40 && B>20 && (R-G)>15 && R-B>15) || ... % RGB空间肤色检测
(R>220 && G>210 && B>170 && R-B<=15 && R>B && G>B) % 符合RGB肤色检测条件的像素点值置1则为白色,其他不符合条件的像素点为0黑色
SkinRGB(j,i)=1;
end
maxRGB=max(max(R,G),B); % 取三分量中同一点最大值
minRGB=min(min(R,G),B); % 取三分量中同一点最小值
C=maxRGB-minRGB; % 取最大差值
V=maxRGB; % 最大值赋值给参数V
if V==0 % 比较最大值是否等于零
S=0;
else
S=C/V; % 最大值不等于零则 C最大差值/V最大值
end
if maxRGB==R % 如果该点最大值==红色分量值;作如下处理
H=60*mod((G-B)/C,6);
elseif maxRGB==G % 如果该点最大值==绿色分量值;作如下处理
H=60*((B-R)/C+2);
elseif maxRGB==B % 如果该点最大值==蓝色分量值;作如下处理
H=60*((R-G)/C+4);
end % 符合HSV肤色检测 将该点值置1
if ((H>=0 && H<=25) || (H>=335 && H<=360)) && (S>=0.2 && S<=0.6) && V>=0.4
SkinHSV(j,i)=1; % 优化 HSV 效果增强?如何改?为什么这样改?
end
R=R/255;G=G/255;B=B/255; % RGB 转 YCrCb 公式
Cb=224*(-0.1687*R-0.3313*G+0.5*B)+128;
Cr=224*(0.5*R-0.4187*G-0.0813*B)+128;
if Cb>=77 && Cb<=127 && Cr>=133 && Cr<=173 % 符合 YCrCb肤色检测 将该点值置1
SkinCbCr(j,i)=1;
end
cbcr= [Cb Cr]'; % YCbCr空间基于高斯模型的肤色检测
p=exp(-0.5*((cbcr-miu)')*(inv(sigma))*(cbcr-miu)); % 高斯模型函数
if p>thresh % p > 阙值0.35 值置1
SkinCbCrG(j,i)=1;
end
end
end
figure,imshow(SkinRGB),title('RGB空间肤色检测');
figure,imshow(SkinHSV),title('HSV空间肤色检测');
figure,imshow(SkinCbCr),title('YCbCr空间范围肤色检测');
figure,imshow(SkinCbCrG),title('YCbCr空间高斯模型肤色检测');
%imwrite(SkinRGB,'skinrgb3.jpg');
%imwrite(SkinHSV,'skinhsv3.jpg');
%imwrite(SkinCbCr,'skincbcr3.jpg');
%imwrite(SkinCbCrG,'skinCbCrG3.jpg');
结果:
从运行结果可以看出,利用各个彩色空间肤色分布范围能够检测出肤色,HSV空间检测的结果比较零散。总体来讲,基于肤色分布范围的检测方法的准确率不高;基于高斯模型的检测结果相对较好,若采用动态阈值方法﹐会进一步提高检测准确性;
在人脸检测中也常常用到YCrCb空间,因为一般的图像都是基于RGB空间的,在RGB空间里人脸的肤色受亮度影响相当大,所以肤色点很难从非肤色点中分离出来,也就是说在此空间经过处理后,肤色点是离散的点,中间嵌有很多非肤色,这为肤色区域标定(人脸标定、眼睛等)带来了难题。如果把RGB转为YCrCb空间的话,可以忽略Y(亮度)的影响,因为该空间受亮度影响很小,肤色会产生很好的类聚。这样就把三维的空间降为二维的CrCb,肤色点会形成一定得形状,如:人脸的话会看到一个人脸的区域,手臂的话会看到一条手臂的形态,对处理模式识别很有好处,根据经验某点的CrCb值满足:133≤Cr≤173,77≤Cb≤127 那么该点被认为是肤色点,其他的就为非肤色点。