当前位置:   article > 正文

数字图像处理大作业实验报告

数字图像处理大作业

   

数字图像处理

期末大作业

班    级:数字媒体技术2020级1班

姓    名:快乐的小蓝

学    号:XXXXXXXXX

XXXX大学信息学院

目录

一、任务描述

二、设计思路

三、功能模块

1 人脸定位

1.1 算法原理

1.检测最大连通域

2.基于肤色的检测

3.使用matlab自带的工具人脸识别

1.2 算法实现(代码)

1.3 实验结果及对比分析

2 磨皮

2.1 算法原理

2.2 算法实现(代码块)

2.3 实验结果及分析

3 放大眼睛

3.1 算法原理

3.2 算法实现

3.3 效果分析

4 缩小鼻头

4.1 算法原理

4.2 算法实现(代码)

4.3 效果分析

5 瘦脸

5.1 算法原理

5.2 算法实现(代码)

5.3 效果分析

6 祛痘

6.1 算法原理

6.2 算法实现(代码)

6.3 实验结果及分析

7 素描效果

7.1 算法原理

7.2 算法实现

7.3 结果分析

8 油画效果

8.1 算法原理

8.2算法实现

8.3效果分析

9 毛玻璃效果

9.1 算法原理

9.2 算法实现

9.3 效果分析

10 浮雕效果

10.1 算法原理

10.2 算法实现

10.3 效果分析

11 图像旋转

11.1 算法原理

11.2 算法实现

11.3 效果分析

12 图像裁剪

12.1 算法原理

12.2 算法实现

12.3 效果分析

13 运动模糊

13.1 算法原理

13.2 算法实现

13.3 效果分析

14 图像翻转

14.1 算法原理

14.2 算法实现

14.3 效果分析

15 去除背景

15.1 算法原理

15.2 算法实现

15.3 效果分析

16 添加背景

16.1 算法原理

16.2 算法实现

16.3 效果分析

四、 创新点

人脸定位的实现,最大连通域、肤色检测、V-J算法

五、 心得体会


一、任务描述

选择了简易美图秀秀,使用matlab的appdesigner实现了功能交互界面,功能模块具体有定位人脸、磨皮、祛痘、大眼,缩小鼻翼等人脸处理功能。

二、设计思路

主要是参照美图秀秀和平时学习相关的算法,实现了一个基础版的美图秀秀,但是平时所学还不足以支撑起这样一个项目,所以我就根据自己要实现的功能,查阅了大量的资料和相关代码实现,进行了效果测试,以及代码的修改。

三、功能模块

1 人脸定位

1.1 算法原理

我在网上查了很多帖子,不涉及深度学习的算法主要有3种

1.检测最大连通域

原理:通过对图像进行形态学的处理,形成多个连通区域,默认最大的连通区域为人脸所在的区域。

缺陷:

1)有时候静态的图片,经过形态学处理之后,最大的连通域并不是人脸的部分,所以这个算法局限性比较大。

2)只能对图像中的一个人脸进行检测

2.基于肤色的检测

原理:肤色检测的方法有很多,但是无论是基于不同的色彩空间还是不同的肤色模型,其根本出发点在于肤色分布的聚集性,即肤色的分量一般聚集在某个范围内。不同的色彩空间肤色的分布范围不同。

1)RGB彩色空间

据统计资料,再均匀光照下,肤色分布范围在:R>95且G>40且B>20且max{R,G,B}-min{R,G,B}>15,且|R-G|>15且R>G且R>B

2)YCbCr彩色空间

据资料统计,肤色在YCbCr彩色空间的分布范围为77<=Cb<=127,133<=Cr<=173,下面就是使用的这个彩色空间进行基于肤色的人脸检测,并且肤色模型用的是阈值模型,而没有选择高斯模型

3)HSV彩色空间

HSV空间建立的肤色检测模型要求满足0度<H<=25度或335度<=H<=360度且0.2<=S=0.6且0.4<=V

缺陷:

  1. 如果图片背景或人的衣物与肤色相似,则定位不准确
  2. 有些加持了滤镜的人像图片,甚至检测不到肤色像素。

3.使用matlab自带的工具人脸识别

级联对象检测器使用Viola-Jones算法来检测人的面部,鼻子,眼睛,嘴巴或上半身。还可以使用Image Labeler训练自定义分类器以与此System对象一起使用。这个工具进行人脸定位比较准确,而且能实现嘴巴、鼻子、眼睛的轻松定位,在一张图片中可以定位出多个人脸。

这个工具用算法都比较复杂,根据在网上查阅的博文,我有了大致的认识,总结如下:

这个检测器用的算法是V-J算法,这个算法是以提出这个算法的两位大佬命名的,Viola和Jones。实质是,在AdaBoost算法的基础上,使用Haar-like小波特征(简称haar特征)和积分图的方法进行的人脸检测。首先来看AdaBoost算法,这个算法本质上是将多个弱分类器,组合成强的分类器。

  1. 初始化样本,假设样本数有N个,那么一开始每个样本的权重为1/N。
  2. 训练分类器,如果在分类的过程中,样本被分类为正样本,即这个样本分类是准确的,那么在下一次分类迭代中,就会降低这个正样本的权重,反之,如果是负样本,则提高权重,迭代N次,得到使样本分类的误差函数值最小的分类器,这样就得到了弱分类器,将多个弱分类器组合就得到强分类器。

那么AdaBoost的训练样本从何而来呢,那么就要说到Haar-like小波特征,虽然每个人都长的不一样,但是人脸都有一些固定的特征,比如眼睛部分比较暗,鼻子两侧的比较暗,但中间部分比脸颊亮,嘴巴部分也比较暗,根据这些特征,V-J用了四种矩形特征,用黑色部分的灰度值减去白色部分的灰度值,就产生了人脸的矩形特征。一幅24*24的图像就有160000个特征矩形,如果对这些特征矩形中所有像素点一次遍历求和,计算量非常大,这时候积分图就出现了。

积分图,表征为位于(i,j)位置的像素点的积分是左上方所有像素的和,如果知道某些像素点的积分,求某个区域的像素和,只需要进行简单的几次加减,不需要每次遍历。所以一张图,将每个像素点都表征为积分,将积分值存储在一个和原图像大小相同的矩阵中,求指定区域的像素和的时候,只需要找出对应位置的积分进行加减,就能得到这个区域的像素和,计算量大大减少了。

缺陷:有时候也会定位出不是嘴巴的部分,或者会将眼睛定位成嘴巴。

总的来说,按照效果排列:V-J算法>最大连通域>肤色检测。

1.2 算法实现(代码)

第一个是检测最大连通域的人脸检测代码:

检测最大连通区域

  1. rgb = Img;
  2. I = rgb2gray(rgb);%灰度化
  3. [n1,n2] = size(I);%获取图像矩阵大小
  4. %灰度图
  5. % figure,imshow(I),title('灰度图')
  6. tic
  7. avel=fspecial('average',3);
  8. I=filter2(avel,I)/255;
  9. % figure,imshow(I),title('均值滤波')
  10. BW = imbinarize(I);
  11. % figure,imshow(BW),title('二值化')
  12. B = ones(21);%结构元素
  13.  BW = -imerode(BW,B) + BW;
  14. % BW=imdilate(BW,B)-imerode(BW,B);
  15. % figure,imshow(BW),title('形态学边界提取')
  16.  BW = bwmorph(BW,'thicken');
  17. %  figure,imshow(BW),title('加粗边界')
  18. BW = ~(bwareaopen(~(BW), 50));%使用bwareaopen 函数删除包含的像素数少于50的对象
  19. % figure,imshow(BW),title('把空洞填了')
  20. %进行形态学运算
  21. B = strel('line',50,90);
  22. BW = imdilate(BW,B);
  23. BW = imerode(BW,B);
  24. %figure,imshow(BW),title('闭运算操作之后')
  25. B = strel('line',10,0);
  26. BW = imerode(BW,B);
  27.  figure,imshow(BW),title('闭操作之后再腐蚀')
  28. BW = gpuArray(BW);%%将数据载入gpu可以加速,电脑不一定支持
  29. %最小化背景
  30. %细分
  31. div = 10;
  32. r = floor(n1/div);%分成10块 行
  33. c = floor(n2/div);%分成10块 列
  34. x1 = 1;x2 = r;%对应行初始化
  35. s = r*c;%块面积
  36. %判断人脸是否处于图片四周,如果不是就全部弄黑
  37. for i=1:div
  38.     y1 = 1;y2 = c;%对应列初始化
  39.     for j=1:div
  40.         loc = find(BW(x1:x2,y1:y2)==0);%统计这一块黑色像素的位置
  41.         num = length(loc);
  42.         rate = num*100/s;%统计黑色像素占比
  43.         if (y2<=0.2*div*c||y2>=0.8*div*c)||(x1<=r||x2>=r*div)
  44.             if rate <=100
  45.                 BW(x1:x2,y1:y2) = 0;
  46.             end
  47.             imshow(BW)
  48.         else
  49.             if rate <=25
  50.                 BW(x1:x2,y1:y2) = 1;
  51.             end
  52.             %imshow(BW)
  53.         end%下一列
  54.         y1 = y1 + c;
  55.         y2 = y2 + c;
  56.     end%下一行
  57.     x1 = x1 + r;
  58.     x2 = x2 + r;
  59. end
  60. figure
  61. subplot(1,2,1)
  62. imshow(BW)
  63. title('最终处理')
  64. L = bwlabel(BW,8);%利用belabel函数对8连通域区间进行标号
  65. BB = regionprops(L,'BoundingBox');%得到矩形框,框出每一个连通域
  66. BB = cell2mat(struct2cell(BB));
  67. [s1,s2] = size(BB);
  68. BB = reshape(BB,4,s1*s2/4)';
  69. pickshape = BB(:,3)./BB(:,4);%
  70. shapeind = BB(0.3<pickshape&pickshape<3,:);%筛选掉尺寸比例不合格
  71. [~,arealind] = max(shapeind(:,3).*shapeind(:,4));
  72. subplot(1,2,2)
  73. imshow(rgb)
  74. hold on
  75. rectangle('Position',[shapeind(arealind,1),shapeind(arealind,2),shapeind(arealind,3),shapeind(arealind,3)],...
  76.     'EdgeColor','g','Linewidth',2)
  77. title('人脸检测')

第二个是基于YCbCr颜色空间的人脸检测

代码块:

  1. %肤色检测模型
  2. image = imread('person10.jpg');
  3. %三通道分离
  4. image_red = image(:,:,1);
  5. image_green = image(:,:,2);
  6. image_blue = image(:,:,3);
  7. [ROW,COL] = size(image_red);
  8. figure
  9. imshow(image);
  10. title('原图');
  11. YCbCr = rgb2ycbcr(image);%将 RGB 图像的红色、绿色和蓝色值转换为 YCbCr 图像的亮度 (Y) 和色度(Cb 和 Cr)值。
  12. Y = YCbCr(:,:,1);
  13. Cb = YCbCr(:,:,2);
  14. Cr = YCbCr(:,:,3);
  15. pic_gray = zeros(ROW,COL);%创建和原图大小相同的全零矩阵
  16. for i = 1:ROW
  17.     for j = 1:COL
  18.         if(Cb(i,j) > 77 && Cb(i,j) < 127 && Cr(i,j) > 133 && Cr(i,j) < 173)
  19.             pic_gray(i,j) = 255;
  20.         else
  21.             pic_gray(i,j) = 0;
  22.         end
  23.     end
  24. end
  25. figure
  26. imshow(pic_gray);
  27. title('肤色检测图');
  28. se = strel('square',20);
  29. erode = imerode(pic_gray,se);
  30. figure
  31. imshow(erode);
  32. title('形态学滤波');
  33. x_min = 1024;
  34. x_max = 0;
  35. y_min = 768;
  36. y_max = 0;
  37. for i = 1:ROW
  38.     for j = 1:COL
  39.         if(erode(i,j) > 0 && x_min > j)
  40.             x_min = j;
  41.         end
  42.         if(erode(i,j) > 0 && x_max < j)
  43.             x_max = j;
  44.         end
  45.     end
  46. end
  47. for i = 1:ROW
  48.     for j = 1:COL
  49.         if(erode(i,j) > 0 && y_min > i)
  50.             y_min = i;
  51.         end
  52.         if(erode(i,j) > 0 && y_max < i)
  53.             y_max = i;
  54.         end
  55.     end
  56. end
  57. for i = 1:ROW
  58.     for j = 1:COL
  59.         if(j == x_min && i >= y_min && i <= y_max)
  60.             image_test(i,j,1) = uint8(255);
  61.             image_test(i,j,2) = uint8(255);
  62.             image_test(i,j,3) = uint8(255);
  63.         elseif(j == x_max && i >= y_min && i <= y_max)
  64.             image_test(i,j,1) = uint8(255);
  65.             image_test(i,j,2) = uint8(255);
  66.             image_test(i,j,3) = uint8(255);
  67.         elseif(i == y_max && j >= x_min && j <= x_max)
  68.             image_test(i,j,1) = uint8(255);
  69.             image_test(i,j,2) = uint8(255);
  70.             image_test(i,j,3) = uint8(255);
  71.          elseif(i == y_min && j >= x_min && j <= x_max)
  72.             image_test(i,j,1) = uint8(255);
  73.             image_test(i,j,2) = uint8(255);
  74.             image_test(i,j,3) = uint8(255);
  75.         else
  76.             image_test(i,j,1) = image(i,j,1);
  77.             image_test(i,j,2) = image(i,j,2);
  78.             image_test(i,j,3) = image(i,j,3);
  79.         end
  80.     end
  81. end
  82. %subplot(2,2,4);
  83. figure
  84. imshow(image_test);
  85. title('头像检测');

第三个是利用matlab工具来进行人脸的定位

代码块:

  1. detector = vision.CascadeObjectDetector;%获取检测器
  2. %Read the input image
  3. I = imread('person.jpg');%读入图像
  4. face_dtect = step(detector,I);%人脸检测,返回人脸区域的位置向量
  5. figure
  6. imshow(I)%显示图像
  7.  hold on
  8. for i = 1:size(face_dtect,1)%检测器可能检测到多个
  9.     rectangle('Position',face_dtect(i,:),'LineWidth',1,'LineStyle','-','EdgeColor','m');%用矩形标注出人脸区域
  10. end
  11. title('人脸检测');

1.3 实验结果及对比分析

肤色检测:

结果分析:

对于背景和人物衣物颜色与肤色阈值不相近的图像来说,效果比较好,但是大部分测试图像定位都不准确,尤其是人脸区域很小,或者人物的衣物与背景和肤色阈值接近,效果就很差。

最大连通域:

  

结果分析:最大连通域默认整个图像的最大连通域就是人脸,所以对于人脸占图像比例大的图片,处理效果就很好(也不是越大越好,人脸尽量要完整),但是像第二张图片,整个小姑娘站的较远,且是侧身站的,人脸部分出现了较大的断裂,无法连通,所以检测出来的结果完全错误。但总体来说测试效果成功的概率比肤色检测好很多。

V-J算法:

结果分析:

这个算法人脸定位比较准确,甚至还可以定位五官和上半身。对正脸的图像准确率高一些,人脸部分可以比较小,但必须完整。上面的倒数两张图定位失败了,倒数第二张定位出了两张人脸,人物的衣服结构复杂,检测器把它也作为人脸了,最后一张直接没有检测出人脸,误差比较大,而且,我在测试检测五官的时候,我发现这个检测器在检测嘴巴的时候,往往将眼睛也标记出来了,但是检测鼻子比较精准。但是整体效果比前面两种算法好很多。

2 磨皮

2.1 算法原理

磨皮:实质上就是图像的平滑,根据目前的学到的平滑图像的算法,空域有高斯滤波、中值滤波、均值滤波,频域就是低通滤波器。我在测试的时候,发现这个滤波器会模糊五官和边界,效果很不理想。翻看教材,发现教材上使用了双边滤波进行人脸的磨皮。看书上的公式脑袋晕乎乎的,但是听了专业同学的讲解,发现这个算法也不难。

这算法是在高斯滤波上的改进,高斯滤波只考虑了位置对像素值的影响,即位置越近,对像素值的影响越大,所以这样会模糊掉边界等重要信息。而双边滤波,将位置和像素值看得同等重要,在平坦区域,像素的位置主导双边滤波的效果。在边缘区域,由于边缘两侧像素值相差很大,所以边缘另一侧的像素权重降低,几乎不会影响到边缘这一侧的像素,这就实现了保边的效果。

2.2 算法实现(代码块)

  1. %用双边滤波实现人脸美化的效果
  2. I = imread('person2.jpg');%读取图像
  3. figure(1)
  4. imshow(I),title('原图');%显示原图
  5. bfilt_rgb(I,15,6,0.1);%调用双边滤波函数,进行滤波处理
  6. %函数实现
  7. function g = bfilt_rgb(f,r,a,b)
  8. % f彩色图;r滤波半径;a全局方差;b局部方差
  9. [x,y] = meshgrid(-r:r);%创建二维网格坐标
  10. w1 = exp(-(x.^2+y.^2)/(2*a^2));%计算滤波内的空间权值
  11. f = im2double(f);%将uint8转换成double,方便后续处理
  12. h = waitbar(0,'Applying bilateral filter...');%设置进度条
  13. set(h,'Name','Bilateral Filter Progress');
  14. detector = vision.CascadeObjectDetector;%目标探测器
  15. facePart = step(detector,f);
  16. %获取脸部坐标
  17. X_min = facePart(1,1);%人脸区域的左下x坐标
  18. Y_min = facePart(1,2);%y坐标
  19. Width = facePart(1,3);%区域宽度
  20. Height = facePart(1,4);%区域高度
  21. %三通道分离
  22. fr = f(:,:,1);
  23. fg = f(:,:,2);
  24. fb = f(:,:,3);
  25. [m,n] = size(fr);%图像矩阵大小,方便后面像素的遍历
  26. fr_temp = padarray(fr,[r r],'symmetric');%镜像填充矩阵,方便处理边界像素
  27. fg_temp = padarray(fg,[r r],'symmetric');%镜像填充矩阵,方便处理边界像素
  28. fb_temp = padarray(fb,[r r],'symmetric');%镜像填充矩阵,方便处理边界像素
  29. [gr,gg,gb] = deal(zeros(size(fr)));%创建三个和原图像大小相同的全零矩阵
  30. for i = r+1+Y_min:Height+Y_min+r%对人脸部分进行双边滤波
  31.     for j = r+1+X_min:X_min+Width+r
  32.         temp1 = fr_temp(i-r:i+r,j-r:j+r);%三通道的滤波区域31X31的正方形
  33.         temp2 = fg_temp(i-r:i+r,j-r:j+r);
  34.         temp3 = fb_temp(i-r:i+r,j-r:j+r);
  35.         dr = temp1 - fr_temp(i,j);
  36.         dg = temp2 - fg_temp(i,j);
  37.         db = temp3 - fb_temp(i,j);
  38.         w2 = exp(-(dr.^2+dg.^2+db.^2)/(2*b^2));%求滤波内每个像素对目标像素的影响权值(基于像素值)
  39.         w = w1.*w2;%将两种权值相加,求得滤波范围内每个像素的最终权值
  40.         gr(i-r,j-r) = sum(sum(temp1.*w))/sum(w(:));%将权值与对应像素值相乘相加,再除以权值和,即求得该像素点经双边滤波后的像素值
  41.         gg(i-r,j-r) = sum(sum(temp2.*w))/sum(w(:));
  42.         gb(i-r,j-r) = sum(sum(temp3.*w))/sum(w(:));
  43.     end
  44.     waitbar((i-r)/n);%进度条
  45. end
  46. %将人脸部分赋黑,方便后面图像的叠加
  47. for m=X_min+2:X_min+Width
  48.     for n=Y_min+1:Height+Y_min
  49.         f(n,m,1)=0;
  50.         f(n,m,2)=0;
  51.         f(n,m,3)=0;
  52.     end
  53. end
  54. g = cat(3,gr,gg,gb);%串联数组,合并三通道
  55. result=imadd(g,f);
  56. figure(2)
  57. imshow(result),title('双边滤波');%显示处理图
  58. end

2.3 实验结果及分析:

效果分析:双边滤波既平滑了皮肤,又保留了五官部分,效果真的很好,就是处理速度慢一些。

3 放大眼睛

    1. 算法原理

首先是利用matlab工具箱的人脸检测器,检测出两只眼睛的位置向量,然后分别对两只眼睛进行放大处理:先根据每只眼睛的位置向量确定放大区域的中心坐标,然后设置放大区域的边长,遍历需要放大的区域,使用最邻近插值法,得到放大后的像素值,遍历完成之后,放大效果就实现了。

3.2 算法实现 

  1. %放大眼睛
  2. I = imread('person13.jpg');%读入图像
  3. I = im2double(I);%数据类型转化,以便后续处理
  4. %V-J算法检测眼睛
  5. detector = vision.CascadeObjectDetector;%调用检测器
  6. detector.ClassificationModel='LeftEyeCART';%调用眼睛检测器
  7. bboxes = detector(I);%检测眼睛,返回眼睛区域的位置向量
  8. %放大眼睛
  9. strength=20;%放大强度
  10. pointx=floor(bboxes(1,2)+(bboxes(1,3)/2));%根据检测器大致确定眼睛中心点
  11. pointy=floor(bboxes(1,1)+(bboxes(1,4)/2))+10;
  12. r=50;%放大区域边长
  13. left=pointy-r;
  14. right=pointy+r;
  15. top=pointx-r;
  16. bottom=pointx+r;
  17. space=r*r;%放大的正方形区域
  18. I1=I;%将原图缓存,存储处理后的图像
  19. for x=top:bottom%遍历放大区域的像素
  20.     offsetx=x-pointx;
  21.     for y=left:right
  22.         offsety=y-pointy;
  23.         xy=offsetx*offsetx+offsety*offsety;
  24.         if xy<=space
  25.             scale=1-xy/space;
  26.             scale=1-strength/100*scale;
  27.             %减少计算量,采用最邻近插值,利用四舍五入函数实现
  28.             posy=round(offsety*scale+pointy);%放大后的Y坐标值
  29.             posx=round(offsetx*scale+pointx);%放大后的X坐标值
  30.             %分别对三通道进行处理
  31.             I1(x,y,1)=I(posx,posy,1);
  32.             I1(x,y,2)=I(posx,posy,2);
  33.             I1(x,y,3)=I(posx,posy,3);
  34.         end
  35.     end
  36. end
  37. pointx=floor(bboxes(2,2)+(bboxes(2,3)/2));%对另一只眼睛进行同样的处理
  38. pointy=floor(bboxes(2,1)+(bboxes(2,4)/2));
  39. r=50;
  40. left=pointy-r;
  41. right=pointy+r;
  42. top=pointx-r;
  43. bottom=pointx+r;
  44. space=r*r;
  45. I2=I1;
  46. for x=top:bottom
  47.     offsetx=x-pointx;
  48.     for y=left:right
  49.         offsety=y-pointy;
  50.         xy=offsetx*offsetx+offsety*offsety;
  51.         if xy<=space
  52.             scale=1-xy/space;
  53.             scale=1-strength/100*scale;
  54.             posy=round(offsety*scale+pointy);
  55.             posx=round(offsetx*scale+pointx);
  56.             I2(x,y,1)=I1(posx,posy,1);
  57.             I2(x,y,2)=I1(posx,posy,2);
  58.             I2(x,y,3)=I1(posx,posy,3);
  59.         end
  60.     end
  61. end
  62. figure
  63. subplot(121),imshow(I2),title('放大眼部');
  64. subplot(122),imshow(I),title('原图');

3.3 效果分析

效果分析:因为这个功能主要是基于人眼的位置识别,所以人眼位置定位是否准确,直接影响了眼部增大功能的实现效果,对于有些人像图,甚至检测不到眼部,所以就根本不能使用该功能,还有些人像,会将嘴巴部分也识别成眼部,所以会导致嘴巴部分被放大,但是只要是能准确定位眼部的,处理效果就很不错。

4 缩小鼻头

4.1 算法原理

这个算法依旧是基于人脸检测V-J和区域放缩算法,并且步骤与眼睛放大大同小异。首先使用matlab定位到鼻子的位置,然后根据工具返回的位置向量确定鼻子的中心坐标,最后使用区域放大算法,只不过将强度改为负数,就达到了区域缩小的效果,即鼻头缩小术。

4.2 算法实现(代码)

  1. %瘦鼻
  2. I = imread('person25.jpg');
  3. detector = vision.CascadeObjectDetector;%检测器
  4. detector.ClassificationModel='Nose';
  5. detector.MergeThreshold=10;%增加合并阈值
  6. bboxes=detector(I);
  7. Nose=insertObjectAnnotation(I,'rectangle',bboxes,'Nose');%用矩形框标出鼻子定位的矩形区域
  8. figure(9);imshow(Nose);title('Nose'); %显示图像
  9. %区域图像缩小
  10. strength=-20;%缩小强度
  11. pointx=floor(bboxes(1,2)+(bboxes(1,3)/2));%根据检测器大致确定鼻子中心点
  12. pointy=floor(bboxes(1,1)+(bboxes(1,4)/2));
  13. r=50;%放大区域边长
  14. left=pointy-r;
  15. right=pointy+r;
  16. top=pointx-r;
  17. bottom=pointx+r;
  18. space=r*r;%缩小的正方形区域
  19. I1=I;%将原图缓存,存储处理后的图像
  20. for x=top:bottom%遍历缩小区域的像素
  21.     offsetx=x-pointx;
  22.     for y=left:right
  23.         offsety=y-pointy;
  24.         xy=offsetx*offsetx+offsety*offsety;
  25.         if xy<=space
  26.             scale=1-xy/space;
  27.             scale=1-strength/100*scale;
  28.             %减少计算量,采用最邻近插值,利用四舍五入函数实现
  29.             posy=round(offsety*scale+pointy);%放大后的Y坐标值
  30.             posx=round(offsetx*scale+pointx);%放大后的X坐标值
  31.             %分别对三通道进行处理
  32.             I1(x,y,1)=I(posx,posy,1);
  33.             I1(x,y,2)=I(posx,posy,2);
  34.             I1(x,y,3)=I(posx,posy,3);
  35.         end
  36.     end
  37. end
  38. figure
  39. imshow(I1);

4.3 效果分析

效果分析:这个功能几乎跟放大眼睛的功能相同,所以只要鼻子定位准确,鼻翼缩小的效果是很好的,但是对于定位不到鼻子的人像,就无法进行缩小处理了,而且我发现了一个神奇的现象,原来鼻头变小,会有视觉上放大眼睛的效果。

5 瘦脸

5.1 算法原理

这个算法主要是基于像素平移,我参考的是网上有一篇液化算法的帖子,里面给出了逆变换公式和算法实现的步骤,没有给出实现代码,所以,我一开始对这个算法理解不深的时候,根本无法写出实现的代码,但是后面我再次去看这个算法的时候,发现这个算法实际上就是像素平移,因为平移的像素到达目的位置的时候,由于根据变换公式算出来的坐标是双精度的,而图像的矩阵的坐标是正整数,所以平移的时候,无论用什么插值算法,都有可能出现像素的重叠或者缺失像素值的问题,所以采用逆变换,用目的位置来倒推原来的像素的位置,因为倒推出来也是双精度,所以对原来像素值邻近像素使用双线性插值算法,算出的像素值就是目的位置上的像素值,这样就实现了像素比较平滑的平移。算法实现之后,我用的是交互式选取圆形区域,然后再选取一个平移的圆心,目的是对脸部边缘的像素平滑平移,从而从视觉效果上实现瘦脸的效果,但实际上操作起来,一旦选取的区域与目的圆心的位置相距太远,就会产生畸变,导致脸部严重变形,我尝试了很多人脸图像,只有一张效果还不错,但是也是要经过很多次像素的不明显平移,才会看出比较明显的瘦脸效果。我一直在想怎么完善一下,但是时间好像不够了,就放弃了。

5.2 算法实现(代码)

  1. for cou =1:300
  2.     if cou==1
  3.         I = imread('C:\Users\leishen\Desktop\数字图像处理\期末大作业\测试效果\person7.jpg');%读入图片
  4.     else
  5.         I = imread('C:\Users\leishen\Desktop\数字图像处理\期末大作业\测试效果\person25.jpg');%读入修改之后的图片,以便继续进行瘦脸处理
  6.     end
  7.     figure
  8.     imshow(I);
  9.     h = drawcircle('Color','k','FaceAlpha',0.4);%交互式选取圆形区域
  10.     M = ginput(1);  %交互式选取坐标,即变化后的圆心的位置
  11.     [m,n,~] = size(I);%图像矩阵的大小
  12.     center = [floor(h.Center(2)),floor(h.Center(1))];%变形前的圆心
  13.     radius = h.Radius;%变形的圆半径
  14.     RGB_buff = I;
  15.     %遍历圆形选区的每一个像素
  16.     for i=1:m
  17.         for j=1:n
  18.             distant = sqrt((i-center(1)).^2+(j-center(2)).^2);%判断该像素点是否在选取的圆形区域内
  19.             if distant <= radius
  20.                 x = [i,j];%变形后的坐标
  21.                 U = x - ((radius^2 - (x - center).^2) / (radius^2 - (x - center).^2 + (M - center).^2))^2 * (M - center);%逆变换公式
  22.                 uu = floor(U);%舍弃小数部分,保留整数
  23.                 ab = U-uu;%这个数据用于后面双线性插值处理
  24.                 a = ab(1);
  25.                 b = ab(2);
  26.                 m1 = uu(1);
  27.                 n1 = uu(2);
  28.                 for k=1:3
  29.                 I(i,j,k)=(1-a)*(1-b)*RGB_buff(m1,n1,k)+a*(1-b)*RGB_buff(m1+1,n1,k)+(1-a)*b*RGB_buff(m1,n1,k)+a*b*RGB_buff(m1+1,n1+1,k);%双线性插值
  30.                 end     
  31.             end
  32.         end
  33.     end
  34.     figure
  35.     imshow(I);
  36.     
  37.     answer = questdlg('是否要继续调整', ...
  38.     '选择', ...
  39.     'YES','NO','NO');
  40.     
  41.     switch answer
  42.         case 'YES'
  43.             imwrite(I,'C:\Users\leishen\Desktop\数字图像处理\期末大作业\测试效果\person25.jpg');
  44.         case 'NO'
  45.             msgbox("退出调整");
  46.         break;
  47.     end
  48. end

5.3 效果分析

可以看到脸部的左边实现了较大的像素平移效果,所以从视觉上有了瘦脸的效果,但是仔细看,就会发现像素平移造成了图像的局部畸变和模糊。

6 祛痘

6.1 算法原理

这个实现原理比较简单,先交互式选取想要祛痘的区域,然后提取这个区域的左上角的第一个像素,用这个像素值-5到像素值+5范围的像素值,随机的填充选取的区域。然后为了减弱填充的边界,用了高斯滤波对脸部进行了高斯滤波的处理。

6.2 算法实现(代码)

  1. g=imread('person1.jpg');
  2. % n 为操作次数,默认为1,g为原图
  3. n=3;
  4. g2 = g;
  5. %得到原图像的大小
  6. [ M,N,~ ] = size( g );
  7. while( n ~=0 )
  8.     n = n - 1;
  9.     %进行交互选择处理区域
  10.     mask = roipoly( g2 );%roipoly函数--指定多边形感兴趣区域,将蒙版作为二进制图像返回,所以下面的乘法就可以得到原图像被提取的区域,因为0的部分乘以任何像素值都为0,1乘以原像
  11.     %素还是等于原像素
  12.     x1 = immultiply( mask,g2( :,:,1 ) );
  13.     x2 = immultiply( mask,g2( :,:,2 ) );
  14.     x3 = immultiply( mask,g2( :,:,3 ) );
  15.     x = cat( 3,x1,x2,x3 );%将x1和x2和x3沿第三维度串联起来,这里相当于三通道合并
  16. %  figure
  17. %  imshow(x);%原来x是交互时提取的区域
  18.     %预分配内存,f1,f2,f3存储三个通道的运算结果
  19.     f1 = zeros( M,N );
  20.     f2 = zeros( M,N );
  21.     f3 = zeros( M,N );
  22.     %跳出双重循环设置flag
  23.     flag = 0;
  24.     %找到第一个像素值不为0的点,得到该点像素值,作为采样后填充的像素
  25.     for i = 1:M
  26.         for j = 1:N
  27.             if( x1( i,j ) ~= 0 )
  28.                 r = x( i,j,: );
  29.                 flag = 1;%找到之后,跳出循环
  30.                 break
  31.             end
  32.             if( flag == 1 )
  33.                 break
  34.             end
  35.         end
  36.     end
  37.     
  38.     %随机产生填充图像,这就是填充痘印部分的图像
  39.     y = zeros(3,3,3);
  40.     y( :,:,1 ) = randi([r(1)-5,r(1)+5],[3,3]);%取像素值-5到像素值+5的范围的随机数组成一个3X3的矩阵
  41.     y( :,:,2 ) = randi([r(2)-5,r(2)+5],[3,3]);
  42.     y( :,:,3 ) = randi([r(3)-5,r(3)+5],[3 3]);
  43.     
  44.     %类型转换
  45.     y = double(y);
  46.     %对于三个通道分别进行处理,用采样得到的像素点取代原来的像素点
  47.     for i = 2:3:M-1
  48.         for j = 2:3:N-1
  49.             f1( i-1:i+1,j-1:j+1 ) = mask( i-1:i+1,j-1:j+1 ).* y( :,:,1 );
  50.             f2( i-1:i+1,j-1:j+1 ) = mask( i-1:i+1,j-1:j+1 ).* y( :,:,2 );
  51.             f3( i-1:i+1,j-1:j+1 ) = mask( i-1:i+1,j-1:j+1 ).* y( :,:,3 );
  52.         end
  53.     end
  54.     %将三个通道连接在一起
  55.     f = cat( 3,f1,f2,f3 );
  56.     %类型转换
  57.     f = uint8( f );
  58.     
  59.     %得到处理后图像,居然可以直接加减,那还学什么运算函数
  60.     a = g2 - x;
  61.     f = f + a;
  62.     g2 = f;
  63. end
  64. %图像滤波处理,将图像进行高斯滤波处理,平滑
  65. f = double(f);
  66. b = double( imguidedfilter( uint8( f ) ) ) - f + 128 ;
  67. t = imfilter( b, fspecial( 'gaussian',[5 5]) );
  68. f = ( f*50 + ( f+2*t-256 )*50 )/100;
  69. f = uint8(f);
  70. %显示图像
  71. subplot( 1,2,1 ),imshow( g ),title('原图');
  72. subplot( 1,2,2 ),imshow( f ),title('填充处理后图像');

6.3 实验结果及分析

结果分析:因为祛痘区域的像素是根据区域左上角第一个像素+5-5这个范围,进行随机填充的。可以看到,如果痘痘长到脸部死角的话,填充效果是很突兀的,就算是平坦区域,人脸和填充区域也没有很好的连接,填充区域比较突兀,尽管进行了高斯滤波,效果还是一般,但是对于没有高光的人脸,祛痘效果应该不错。

7 素描效果

7.1 算法原理

实质上就是纹理的一个提取过程,首先是分离三通道,随便选择一个通道进行处理,然后将这通道取反,再用高斯滤波对负片进行滤波处理,去除一些噪点,最后就是按照比例将正片和负片进行叠加,最后归一化之后,就得到了比较理想的素描效果。

7.2 算法实现(代码块)

  1. I = imread('person11.jpg');
  2. [height,width,~]=size(I);%获取图像矩阵的大小
  3. N=zeros(height,width);%创建两个全零矩阵
  4. G=zeros(height,width);  
  5. %分离三通道
  6. rc = I(:,:,1);
  7. gc = I(:,:,2);
  8. bc = I(:,:,3);
  9. %选择一个通道进行处理
  10. channel = gc;
  11. out=zeros(height,width);  
  12. spec=zeros(height,width,3);  
  13. %颜色取反
  14. for i=1:height
  15.     for j=1:width
  16.         N(i,j)=uint8(255-channel(i,j));
  17.     end  
  18. end   
  19. %高斯模糊
  20. gausize = 10;%滤波器大小,越大越模糊
  21. gausigma = 12; %越大越模糊
  22. GH = fspecial('gaussian', gausize, gausigma);%构建高斯滤波模板
  23. G = imfilter(N, GH);%滤波处理
  24. for i=1:height  
  25.     for j=1:width  
  26.         b=double(G(i,j));  
  27.         a=double(channel(i,j));  
  28.         temp=a+a*b/(256-b);%将滤波后的负片和正片相叠加
  29.         out(i,j)=uint8(min(temp,255));  
  30.     end  
  31. end  
  32. %模糊程度越高,得到的素描结果越清晰,框架纹理颜色越深
  33. figure
  34. subplot(121),imshow(out/255);%归一化处理并显示图像
  35. subplot(122),imshow(I);

7.3 结果分析

效果分析:图片越清晰,效果越好,因为这个处理主要是对纹理进行提取,进而实现了类似素描的效果。

8 油画效果

8.1 算法原理

定义一个矩形窗口,用这个窗口划过图像的每一个像素点(三通道分别处理),计算矩形内每一个像素点的灰度值,取这个区域里面最大的像素值作为当前像素点的值,这样就实现了简单的油画效果。

8.2算法实现(代码块)

  1. A=imread('person4.jpg');          
  2.          % 油画效果
  3. %创建12X12的窗口矩阵,窗口越大,丢失的信息就越多,效果就越明显
  4. m=12;
  5. n=12;
  6. Image=uint8(zeros([size(A,1)-m,size(A,2)-n,3]));
  7. figure
  8. imshow(Image);
  9. %计算每个RGB值的直方图
  10. for v=1:3
  11. for i=1:size(A,1)-m
  12.     for j=1:size(A,2)-n
  13.         mymask=A(i:i+m-1,j:j+n-1,v);
  14.         h=zeros(1,256);
  15.         for x=1:(m*n)
  16.             h(mymask(x)+1)=h(mymask(x)+1)+1;
  17.         end
  18.         [maxvalue,pos]=max(h);%记录最大值和最大值对应的位置
  19.         Image(i,j,v)=pos-1;%将最大值赋值给当前的像素
  20.     end
  21. end
  22. end
  23. figure
  24. subplot(121),imshow(Image);
  25. subplot(122),imshow(A);

8.3效果分析

效果分析:窗口越大,效果越明显,但是由于取的是最大值,所以有些地方突变很突兀,效果不是很理想,但基本实现了油画效果。

9 毛玻璃效果

9.1 算法原理

首先创建一个处理的窗口,可以自定义大小,然后用这个窗口滑动图像的每一个像素,随机取这个窗口的某个像素,赋值给当前滑过的像素,直至遍历所有像素,毛玻璃效果就完成了。

9.2 算法实现(代码块)

  1. A=imread('buiding1.jpg');%读入图像
  2. %定义一个6X7的矩形窗口
  3. m=6;                                                                  
  4. n=7;
  5. Image=uint8(zeros([size(A,1)-m,size(A,2)-n,3]));%存储窗口处理后的图像
  6. for i=1:size(A,1)-m
  7.     for j=1:size(A,2)-n
  8.         mymask=A(i:i+m-1,j:j+n-1,:);%将图像对应像素值赋值给窗口
  9. x2=ceil(rand(1)*m);%从窗口像素随机挑选一个像素,因为坐标必须为正整数,所以用ceil四舍五入为整数
  10. y2=ceil(rand(1)*n);
  11.         Image(i,j,:)=mymask(x2,y2,:);%将选出的像素值赋值给当前的像素
  12.     end
  13. end
  14. imshow(Image);%显示图像

9.3 效果分析

10 浮雕效果

10.1 算法原理

这个效果的实现比较简单,实质上就是提取图像的边界,然后突出边界。具体步骤就是对灰度图进行Sobel滤波,提取边界,然后再进行灰度转化。

10.2 算法实现(代码块)

  1. img=imread('building2.jpg');%读入图像
  2. f0=rgb2gray(img);%改为灰度图像
  3. f1=im2double(f1);
  4. h2=fspecial('sobel'); %进行sobel滤波
  5. g3=filter2(h2,f1,'same');
  6. K=mat2gray(g3); %将矩阵转换成灰度图
  7. figure
  8. imshow(K);

10.3 效果分析

效果分析:浮雕效果取决于边界提取的效果,所以灰度值变化大的图像,处理效果就很好,所以这个效果对建筑物等图片处理效果还可以,就贴了一张处理建筑物的图片。

11 图像旋转

11.1 算法原理

实质上就是矩阵的旋转,旋转轴是图像的中心,让图像的每一个坐标经过旋转公式计算出旋转后的坐标,但是计算出来的坐标是浮点数,坐标必须是正整数,所以必须取整,但是取整后,可能有些坐标上像素值会出现重叠,有些坐标上可能出现没有像素的情况,所以用变换后的坐标来确定变换前的坐标,然后用变换前坐标附近的像素点进行简单的线性插值,算出变换后坐标的像素值,遍历完图像之后,就得到了旋转后的图像。

11.2 算法实现(代码块)

  1. %图像旋转
  2. I = imread('person10.jpg');%读入图像
  3. I = im2double(I);
  4. I2=imrotate(I,-22);
  5. figure
  6. subplot(121),imshow(I2),title('顺时针旋转22度');%调用函数实现
  7. %自己写代码实现
  8. %旋转22度
  9. a = 22/180*pi;%角度转换成弧度
  10. Rotate = [cos(a) -sin(a);sin(a) cos(a)];%旋转变换矩阵
  11. [m,n,~] = size(I);%矩阵大小
  12. center = [m,n]/2;%旋转轴中心
  13. % 计算显示完整图像需要的画布大小
  14. hh = floor(m*sin(a)+n*cos(a))+1;
  15. ww = floor(m*cos(a)+n*sin(a))+1;
  16. c2 = [hh; ww] / 2;%旋转之后的轴中心
  17. res = zeros(size(I));%创建存储结果的全零矩阵
  18. for k=1:3%三个通道
  19.  for i=1:hh
  20.      for j=1:ww
  21.          R = Rotate*([i;j]-c2)+center;%变换公式
  22.          R1 = floor(R);%向负无穷舍入
  23.          ab = R-R1;%线性插值算法
  24.          a = ab(1);
  25.          b = ab(2);
  26.          m1 = R1(1);
  27.          n1 = R1(2);
  28.          if (R(1) >= 1 && R(1) <= m && R(2) >= 1 && R(2) <= n)
  29.              res(i, j, k) =(1-a)*(1-b)*I(m1,n1, k) + a*(1-b)*I(m1+1, n1, k)...
  30.                           + (1-a)*b*I(m1,n1+1,k)+ a*b*I(m1+1,n1+1, k);%简单线性插值
  31.          end
  32.      end
  33.  end
  34. end
  35.  subplot(122),imshow(res),title('顺时针旋转变化22');%显示图像

11.3 效果分析

对于自编程的函数实现旋转,存在图片的拉伸,和图片显示不完整等问题,算法实现还是有一定问题。

12 图像裁剪

12.1 算法原理

利用交互式函数提取裁剪的区域,然后根据返回的参数,显示裁剪后的图像。

12.2 算法实现(代码块)

  1. %交互式裁剪图像
  2. I =imread(‘person.jpg’);%读取图像
  3. [J,rect] = imcrop(I);调用函数交互式裁剪图像,J返回的是裁剪的区域,rect返回的是指定裁剪区域的四元素位置向量。
  4. I2 = imcrop(I,rect);%根据返回的位置向量裁剪图像并返回
  5. imshow(I2);%显示裁剪的图像

12.3 效果分析

效果分析:这个就是实现了交互式裁剪。

13 运动模糊

13.1 算法原理

利用matlab函数fspecial,通过设置运动位移参数和位移角度参数,得到运动仿真滤波器,然后利用滤波器进行图像滤波,得到运动模糊后的图像。

13.2 算法实现(代码块)

  1. %运动模糊
  2.             I = imread('buiding1.jpg');%读入图像
  3.             len=20;%设置运动位移为20个像素
  4.             theta=50;%设置运动角度为45度
  5.             psf = fspecial('motion',len,theta);%建立二维运动仿真滤波器psf
  6.             j = imfilter(I,psf,'circular','conv');%用滤波器产生退化图像
  7.             figure
  8.             subplot(121),imshow(j),title('运动模糊');%显示运动模糊图像
  9.             subplot(122),imshow(I),title('原图');%显示原图像

13.3 效果分析

14 图像翻转

14.1 算法原理

图像的翻转实质上就是矩阵上元素序列的反转,flip这个函数,如果里面只有需要翻转的图像I的话,默认翻转每一列每一行的元素序列,如果在后面加上维度1,就是翻转每一列的元素序列,就实现了上下翻转的效果,如果在后面加上维度2,就是翻转每一行的元素序列,就实现了左右翻转的效果。

14.2 算法实现(代码块)

  1. %图像翻转
  2. I = imread('person.jpg');
  3. res = flip(I,2);%左右翻转
  4. res1 = flip(I,1);%上下翻转
  5. figure,
  6. subplot(131),imshow(I),title('原图');
  7. subplot(132),imshow(res),title('左右翻转');
  8. subplot(133),imshow(res1),title('上下翻转');

14.3 效果分析

15 去除背景

15.1 算法原理

这个功能主要是依赖于matlab的交互式选取多边形感兴趣的区域,选取之后,对图像未选取的部分赋值为0,具体操作是:因为roipoly函数返回了一个二进制图像,选中的区域元素值为1,未选中的部分元素值为0,所以对图像三个通道分别乘以这个二进制图像,然后用cat函数实现三通道的合成,就得到了扣取的图像。

15.2 算法实现(代码块)

  1. %抠除背景
  2. %基于提取感兴趣区域扣除背景
  3. I = app.updateImg;
  4. g2=I;
  5. %进行交互选择处理区域
  6. mask = roipoly( g2 );%roipoly函数--指定多边形感兴趣区域,将蒙版作为二进制图像返回,所以下面的乘法就可以得到原图像被提取的区域,因为0的部分乘以任何像素值都为0,1乘以原像
  7. %素还是等于原像素
  8. app.mask=mask;
  9. x1 = immultiply( mask,g2( :,:,1 ) );
  10. x2 = immultiply( mask,g2( :,:,2 ) );
  11. x3 = immultiply( mask,g2( :,:,3 ) );
  12. x = cat( 3,x1,x2,x3 );%将x1和x2和x3沿第三维度串联起来,这里相当于三通道合并
  13. app.Bg=x;
  14. imshow(x,'parent',app.UIAxes),title('扣取的图像');

15.3 效果分析

效果分析:就是这种交互式的,想要抠出比较完美的对象,很繁琐,而且只能拉直线,扣取对象的边缘就会很生硬,并且很多多余部分。

16 添加背景

16.1 算法原理

这个功能主要是基于上一个去除背景的功能上实现的,因为这个功能实质上是图像的叠加,所以如果背景图小于扣取的图像,就会报错,所以我做了一个判断,如果选取的背景图片过于小,就弹出提示框,那么就只能重新选取背景图片。然后用图像的大小来裁剪背景图片,以便后面图片的加法,最后用背景图减去扣取的图像(利用乘法,让扣取的人像部分像素值为0),再利用图像的叠加,就得到了一个背景和前景的合成图。

16.2 算法实现(代码块)

  1. %创建文件选择对话框选择指定图像
  2. [file,path]=uigetfile('*.png');
  3. bg=imread(fullfile(path,file));%读取图像
  4. [M,N,~]=size(bg);
  5. [A,B,~]=size(app.Bg);
  6. %比较背景图和人像图的矩阵大小
  7. if(M<A|N<B)
  8. %弹出警告对话框
  9. msgbox("当前选择背景图过小,请重新选择!","警告",'non-modal');
  10. end
  11. %基于提取感兴趣区域扣除背景
  12. I = app.Bg;
  13. [M,N,~] = size(I);%获取图片的大小
  14. %按照图像裁剪背景图
  15. bg = imcrop(bg,[0,0,N,M]);
  16. mask=app.mask;
  17. % figure
  18. % imshow(bg),title('裁剪的图像');
  19. %用裁剪的图像减去扣取的图像
  20. b1 = immultiply( ~mask,bg( :,:,1 ) );
  21. b2 = immultiply( ~mask,bg( :,:,2 ) );
  22. b3 = immultiply( ~mask,bg( :,:,3 ) );
  23. b =cat(3,b1,b2,b3);
  24. %处理之后的背景图加上扣取的图像
  25. app.updateImg=b+I;
  26. imshow(b+I,'Parent',app.UIAxes);

16.3 效果分析

效果分析:因为在处理背景和人像的叠加的时候,我是根据人像图片的大小来裁剪的背景图,所以背景图总是无法显示完整,只能显示左上角的部分。而且背景图必须比人像的图片大,不然裁剪的时候,会出现数组越界,报错。

  • 创新点

人脸定位的实现,最大连通域、肤色检测、V-J算法

双边滤波进行磨皮效果的处理,有很好的保边效果

增大眼睛,主要是基于眼睛定位,然后进行局部图像的放大

缩小鼻翼,跟增大眼睛的原理大同小异,首先定位鼻子,然后进行局部图像缩小

瘦脸,虽然实现效果很差,但是根据公式写出来的算法,实现还是很成功的,可能就是需要对圆形区域每一个像素都进行一个连续的液化平移,但是没时间去实现了。

  • 心得体会

一开始学习这门课程,拿到教材之后,翻开书,我傻眼了,都是汉字,但是我就是看不懂。每次上完课,想拿出教材看看,看了几页就放弃了。到了这门课程后期,到形态学这一部分,我感觉可以用这些算法实现好多功能,所以在做大项目的时候,我又翻开了书,书上的代码和算法好像没有那么陌生了,有些算法甚至可以自己单独写出来了。

实现简易版的美图秀秀,我觉得首先得解决人脸定位问题,于是我开始查看相关算法,搜罗了几天,我总结了一下,主要有四种方法:最大连通域(默认最大连通域是人脸)、肤色检测(有很多颜色模型,教材上都有肤色的阈值范围,我采用的YCbCr颜色模型)、V-J算法(基于haar-like的特征提取)、还有就是深度学习(没涉及)。然后我将前三种算法,都找了20张比较清晰的人像样本进行测试,比较他们的优劣。毫无疑问,V-J算法效果远胜与其他两种,所以我就采用了matlab自带的人脸检测器(基于V-J算法)。然后我去看V-J算法,看了很多博文,下课之后,我又再次打开了讲解V-J算法的博文,这次搞懂了百分之八九十。

然后就是人脸磨皮,我一开始只想到了在空间域和频域的各种滤波,于是自己实现了一下,效果很差,五官几乎被磨平了。不知道哪次偶然翻开教材,发现教材上还有一种平滑滤波--双边滤波,不仅考虑了像素的位置,还考虑了像素的值,位置近但是灰度值差异大,这个算法就会降低这种像素值的权重,所以就实现了平滑保边的效果。于是我参照教材上的代码写了一遍,当然教材上是处理的灰度图,我就只能将彩色图的三通道分离,分别进行双边滤波之后,再次合成,虽然这个算法计算量很大,处理速度很慢,但是效果比其他的滤波都好。

再次就是眼部增大的功能,这个我一开始一直没有头绪,虽然matlab那个人脸定位可以定位眼部,但是有时候也不准确,比如定位嘴巴的时候,就会连眼睛也一起识别出来。我想,眼睛增大,实质上不就是图像的局部增大嘛?只要确定增大的范围,再进行插值,就可以实现了,于是我开始利用matlab进行单只眼睛的定位,很好笑的是,我明明只让它定位左眼,但是它返回了两只眼睛的位置向量,然后我就两只眼睛分别进行图像增大,插值我用的是最邻近插值,没有用双线性插值,这样计算量小一些,而且效果也不差。

缩小鼻翼,这个功能是在我睡觉的时候,突然想实现这么一个功能,我一开始想的是等比例缩小鼻子区域,结果实现之后,发现效果很差,鼻子都歪了,因为那个算法本身也是基于像素的间隔采样,然后线性插值,实现的图像的缩小。就会把鼻子区域缩小到原鼻子区域的左上角。后来,我发现放大眼睛的功能不就是这样的效果吗?只要把放大变成缩小就可以了,所以我就改了几行代码,效果很快就出来了。

再次,就是瘦脸的效果,我一开始完全没有头绪,搜索出来的算法全部都是python语言的,然后博主的讲解,我也没搞懂。这个契机又是专业同学的那次算法讲解,液化算法,虽然实质上就是像素的平移,但是我一直没找到逆变换的公式,因此这个算法我搁置了好久,每天都在全网搜索。最后,我终于看到一篇讲解液化算法的文章,博主讲的很清晰,虽然没有给代码,但是有了逆变换公式,我尝试自己写代码,其实也比较简单,先遍历选取的圆形区域的像素,然后再确定平移之后的圆心,就可以根据逆变换公式算出变换之后对应位置,所对应的变换之前的像素值,然后进行双线性插值,这个地方让我想起大二学的《计算机图形学》,以前还不知道这个算法有什么用,没想到这个学期排上了用场。虽然圆形区域的像素是如愿以偿的平移了,但是人脸像素在移动的时候,出现了很大的割裂。所以,尽管这个功能我花了很多时间,但是这个功能算是失败了。

除了每个功能的实现,还要考虑按钮之间的关系,怎么设置变量才能让整个软件流畅的运行,而不是随便一点就报错。我用了几个属性来保存变换之后的图像,这样处理的图片,就能接着处理了,但是在滤镜部分,那些效果不可能进行叠加,所以我设置了一个保存按钮,用于用户确认想要这个效果之后,进行效果图的保存,然后再进行后续处理,这些让我意识到,一个图像处理软件需要考虑的问题不仅仅每个功能模块的实现,还要根据用户的习惯,将某些功能模块关联在一起实现,而像滤镜类似的功能模块,则需要独立去实现。

参考博客:

(37条消息) 【数字图像处理】MATLAB实现图像旋转_Y_CanFly的博客-CSDN博客_图像旋转matlab

(37条消息) 积分图算法及代码实现(笔记)_molihong28的博客-CSDN博客

(37条消息) 数据挖掘领域十大经典算法之—AdaBoost算法(超详细附代码)_fuqiuai的博客-CSDN博客_adaboost算法

(37条消息) [Matlab]简单的人脸祛痘_ZJU_fish1996的博客-CSDN博客

(37条消息) 图像处理算法之瘦脸及放大眼睛_grafx的博客-CSDN博客_主流大眼瘦脸 算法

(37条消息) Vision.CascadeObjectDetector-VJ算法学习_雪山飞狐W的博客-CSDN博客_vision.cascadeobjectdetector

(37条消息) Viola-Jones人脸检测_通信程序猿的博客-CSDN博客

(37条消息) MATLAB基于CascadeObjectDetector的人脸、眼睛、鼻子、嘴巴、上半身检测(9个模型)_Ephemeroptera的博客-CSDN博客_vision.cascadeobjectdetector

图像变形算法:实现Photoshop液化工具箱中向前变形工具 - xiaotie - 博客园 (cnblogs.com)

(37条消息) MATLAB App Designer入门实战(一)_slandarer的博客-CSDN博客

(37条消息) MATLAB 图像处理 简单人脸检测(详细,你上你也行)_Kakaluotuo的博客-CSDN博客_matlab人脸检测

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/257554
推荐阅读
相关标签
  

闽ICP备14008679号