期末大作业之Matlab美图秀秀【GUI界面】

一、任务描述
该项目是基于MATLAB+Python+opencv的美图秀秀工具包,且实现了GUI可视化界面。工具包括图像处理基础功能,如选择保存撤销图片、摄像头拍照、特征点定位、退出等;基本编辑功能,如裁剪、镜像、对比度、旋转、亮度、模糊、锐化等;人脸美化功能,如磨皮、美白、祛痘、大眼、口红、眉毛、腮红、瘦脸等;滤镜特效功能,如浮雕、素描、老照片、交叉冲印、油画、动漫、羽化等;且增加玩法功能,可实现一图转为九宫格图、图像合成、生成电子签名,以及证件照换底色、人脸表情识别、艺术字签名。
二、设计思路
该程序设计思路来源于图像处理类APP,如美图秀秀、醒图、美颜相机等,结合多种APP,归纳图像处理基础功能以及人脸美化功能,同时参考借鉴其创新玩法功能。此外,联系课堂所学知识,归纳可取功能点。最终,形成程序功能设计思维导图,如下所示:
在这里插入图片描述
三、功能模块

在这里给大家分享其中动漫滤镜、特征点定位、大眼、口红、眉毛、腮红、瘦脸、贴纸功能模块。

1 动漫滤镜

实现步骤
1.python调用百度API实现人像动漫化。
参考如下:https://blog.csdn.net/qq_37273544/article/details/104197205

2.将python程序打包exe。
安装pyinstaller:pip install pyinstaller
打包exe:pyinstaller 文件名.py

3.matlab调用Python程序,找到所生成图像途径并显示。

command = ‘exe路径’;
status = system(command);

实现效果
在这里插入图片描述
2 特征点定位

算法原理
使用Dlib模型思想,提取人脸特征点是用 68 个点包围每个部位。Dlib所采用的68个人脸关键点标注可以看下图,单边眉毛有5个关键点,从左边界到右边界均匀采样,共5×2=10个。眼睛分为6个关键点,分别是左右边界,上下眼睑均匀采样,共6×2=12个。嘴唇分为20个关键点,除了嘴角的2个,分为上下嘴唇。上下嘴唇的外边界,各自均匀采样5个点,上下嘴唇的内边界,各自均匀采样3个点,共20个。鼻子的标注增加了鼻梁部分4个关键点,而鼻尖部分则均匀采集5个,共9个关键点。脸部轮廓均匀采样了17个关键点。
在这里插入图片描述
原理参考资料:
https://blog.csdn.net/cungudafa/article/details/93493229

在本程序中,创建meanshapecmu.dat的Dilb特征点库,以及可使用鼠标进行交互式点击眼球中心、嘴唇中心,以及手动移动特征点坐标,从而提高定位精度。
在这里插入图片描述

主界面代码

global d1
global d2;
global picture;
set(handles.text7,‘string’,‘请选择一张照片!!’);
set(handles.text7,‘FontSize’,12);
[filename, pathname] = uigetfile({‘.jpg’;'.tif’;‘.bmp’;'.gif’},‘选择图片’); % 合成路径+文件名
if isequal(filename,0)||isequal(pathname,0)
warndlg(‘没有选中文件!’,‘警告’);
return
else
str = [pathname,filename];% 读取图片
d1=pathname;
d2=filename;
[X,Y]=Edit68Dilb(d1,d2,picture);

主函数代码

function [X,Y]=Edit68Dilb(d1,d2,image)
meanshape68 = load(‘meanshapecmu.dat’);
meyemouth = ([meanshape68([29,35,63],)]+[meanshape68([32,38,67],)])/2;
mtri= load(‘meantri.dat’);
pathname=d1;
filename=d2;
Aim=image;
[hei,wid]=size(Aim);
figure(2);imshow(Aim,[]);
landmarkfile = [filename(1:find(filename==‘.’)-1),‘.lmk’];
box=ones(1,4);
box(3:4)=[size(Aim,2)-1,size(Aim,1)-1];
if( isempty(dir( [pathname,landmarkfile] )) )
%标记一张新面孔
title(‘依次点击左眼、右眼和嘴唇中心 ‘);
%输入眼睛和嘴巴中心
inem = ginput(3);
bx=max(inem(:,1)) - min(inem(:,1));
by=max(inem(:,2)) - min(inem(:,2));
box=[max(1,inem(1,1)-bx),max(1,inem(1,2)-by),3bx,3by ];
inem = inem-[1;1;1]*box(1:2)+1;
T = CalcAffineCo(meyemouth,inem);
Xo = T(1)*meanshape68(:,1) + T(2)*meanshape68(:,2)+T(5);
Yo = T(3)meanshape68(:,1) + T(4)meanshape68(:,2)+T(6);
else
%加载.lmk并编辑
sh=load([pathname,landmarkfile]);
bx = max(sh(:,1))-min(sh(:,1)); bx = bx /4;
by = max(sh(:,2))-min(sh(:,2)); by = by /4;
box(1:2) = [ max(1,min(sh(:,1))-bx),max(1,min(sh(:,2))-by) ];
box(3:4) = [ min(wid,max(sh(:,1))+bx-box(1))-1,min(hei,max(sh(:,2))+by-box(2))-1 ];
Xo=sh(:,1)-box(1)+1;
Yo=sh(:,2)-box(2)+1;
end
im=imcrop(Aim,box);
figure(1);imshow(im,[]);
%Maximize(1);
hold on,
h1 = plot(Xo(1:17),Yo(1:17),‘w-’,Xo(18:27),Yo(18:27),‘w-’,Xo(49:68),Yo(49:68),‘w-’,‘Linewidth’,1);
h2 = plot(Xo,Yo,'
‘,‘Linewidth’,4);
%% 移动两个点
while 1
figure(1);hold on,
title(’!!调整位置(单击左键) OR 保存位置文件(单击右键)!!');
try
[xc,yc]=ginput(1);
catch
break
end
%选择最近的点
[val,ind]=min((xc-Xo).^2 + (yc-Yo).^2);
title('单击左键选择要调整的点,再单击左键选择要将此点调整到的位置;单击右键退出调整保存文件 ‘);
try
[xc,yc]=ginput(1);
catch
break
end
Xo(ind)=xc;
Yo(ind)=yc;
delete(h1);delete(h2);
h1 = plot(Xo(1:17),Yo(1:17),‘w-’,Xo(18:27),Yo(18:27),‘w-’,Xo(49:68),Yo(49:68),‘w-’,‘Linewidth’,1);
h2=plot(Xo,Yo,’
’,‘Linewidth’,4);
drawnow(‘expose’);
end
X = Xo+box(1)-1;
Y = Yo+box(2)-1;
landmarkfile=[filename(1:find(filename==’.‘)-1),’.lmk’];
fid = fopen( [pathname,landmarkfile], ‘w’);
fprintf(fid,‘%6.2f %6.2f\r\n’, [X,Y]');
fclose(fid);
figure(2);imshow(Aim,[]);
plotface(2,X,Y,mtri);
L=1;
for i=1:68
L=L+1;
text(X(i)+0.1,Y(i)+0.1,num2str(L-1)); %利用十个点的坐标添加对应标注
%适当增加一些距离,让文字和点分开会美观一些
end
figure(gcf);

实验结果
在这里插入图片描述
3 大眼

算法原理
获取鼠标点击眼球坐标,设为放大中心点坐标,以此点为圆心,r为放大半径向外扩圆,达到大眼效果。

算法设计

function J=bigger(I,pointx,pointy,r)
%I为原图像,pointx和pointy为放大中心点坐标,r为放大半径
im=I;
%分别得到放大区域的上下左右坐标
left=round(pointy-r);
right=round(pointy+r);
top=round(pointx-r);
bottom=round(pointx+r);
%放大区域面积
space = r * r;
strength=30; %放大强度
%原图像为彩色图像,要分成RGB三个分量进行处理
fr=im(:,:,1);
fg=im(:,:,2);
fb=im(:,:,3);
im2fr=fr;
im2fg=fg;
im2fb=fb;
%插值算法
for x=top:bottom
offsetx=x-pointx;
for y=left:right
offsety=y-pointy;
xy=offsetxoffsetx+offsetyoffsety;
if xy<=space
%等比例放大
scale=1-xy/space;
scale=1-strength/100scale;
%posy和posx为放大后坐标值
%采用最近邻插值算法
posy=round(offsety
scale+pointy);
posx=round(offsetx*scale+pointx);
im2fr(x,y)=fr(posx,posy);
im2fg(x,y)=fg(posx,posy);
im2fb(x,y)=fb(posx,posy);
end
end
end
%将RGB三个分量整合,得到彩色图像
J=cat(3,im2fr,im2fg,im2fb);

实验效果
在这里插入图片描述

4 口红

算法原理
获取嘴部关键点49-68坐标,进行函数拟合,对不同区域进行上色。
在这里插入图片描述

算法设计

a=picture;
G=rgb2gray(picture);
//获取嘴部特征点坐标
[col,row]=size(G);
X1=X(49:52);
Y1=Y(49:52);
X2=X(52:55);
Y2=Y(52:55);
X3=[X(49),X(61),X(62),X(63),X(64),X(65),X(55)];
Y3=[Y(49),Y(61),Y(62),Y(63),Y(64),Y(65),Y(55)];
X4=[X(49),X(61),X(68),X(67),X(66),X(65),X(55)];
Y4=[Y(49),Y(61),Y(68),Y(67),Y(66),Y(65),Y(55)];
X5=[X(49),X(55),X(56),X(57),X(58),X(59),X(60)];
Y5=[Y(49),Y(55),Y(56),Y(57),Y(58),Y(59),Y(60)];
p1=polyfit(X1,Y1,2);%二次函数拟合
p2=polyfit(X2,Y2,2);%二次函数拟合
p3=polyfit(X3,Y3,2);%二次函数拟合
p4=polyfit(X4,Y4,2);%二次函数拟合
p5=polyfit(X5,Y5,2);%二次函数拟合
% key = chuncolor;
//赋予不同颜色
switch get(handles.popupmenu6,‘Value’)
case 1
color=[255,48,48];
case 2
color=[255,69,0];
case 3
color=[255,105,180];
case 4
color=[255,0,0];
case 5
color=[244,100,80];
end
//遍历嘴部像素点涂色
for j=1:row
for i=1:col
if i>X(49) && i<X(52)
if (j<polyval(p3,i)&&j>polyval(p1,i)) ||(j<polyval(p5,i)&&j>polyval(p4,i))
picture(j,i,:)=color;
end
end
if i>X(52) && i<X(55)
if (j<polyval(p3,i)&&j>polyval(p2,i)) ||(j<polyval(p5,i)&&j>polyval(p4,i))
picture(j,i,:)=color;
end
end
end
end
picture=0.15.picture+a.(1-0.15);

实验结果
在这里插入图片描述

5 眉毛

算法原理
获取眉毛关键点18-27坐标,进行函数拟合,扩展上色。
在这里插入图片描述

算法设计

a=picture;
G=rgb2gray(picture);
//获取眉毛关键点18-27坐标
[col,row]=size(G);
eyebrowleftX=X(23:27);
eyebrowleftY=Y(23:27);
eyebrowrightX=X(18:22);
eyebrowrightY=Y(18:22);
p1=polyfit(eyebrowleftX,eyebrowleftY,2);%二次函数拟合
p2=polyfit(eyebrowrightX,eyebrowrightY,2);%二次函数拟合
key=get(handles.popupmenu7,‘value’);
//定义颜色
switch key
case 1
color=[139,69,19];
level=0.2;
case 2
color=[64,64,64];
level=0.2;
end
//遍历上色
for j=1:row
for i=1:col
if i>X(27) && i<X(27)+(X(23)-X(27))/7
if j>polyval(p1,i)-2&&j<polyval(p1,i)+2
picture(j,i,:)=color;
end
end
if i>X(27)+(X(23)-X(27))/7 && i<X(23)
if j>polyval(p1,i)-4&&j<polyval(p1,i)+4
picture(j,i,:)=color;
end
end
if i>X(22) && i<X(22)+(X(18)-X(22))/76
if j>polyval(p2,i)-4&&j<polyval(p2,i)+4
picture(j,i,:)=color;
end
end
if i>X(22)+(X(18)-X(22))/7
6 && i<X(18)
if j>polyval(p2,i)-2&&j<polyval(p2,i)+2
picture(j,i,:)=color;
end
end
end
end
picture=level.picture+a.(1-level);

实验结果
在这里插入图片描述

6 腮红

算法原理
获取人脸特征点坐标,取鼻子中心和颧骨点距离一半,即关键点组(43,2)和(43,16),再以此为圆心做一个圆,为腮红区域。
在这里插入图片描述

算法设计

a=picture;
G=rgb2gray(picture);
[col,row]=size(G);
R=(X(16)-X(2))/8;
facelisf=[(X(43)+X(2))/2-R/3,(Y(43)+Y(2))/2];
faceright=[(X(43)+X(16))/2+R/3,(Y(43)+Y(16))/2];
key=get(handles.popupmenu12,‘value’);
switch key
case 1
color=[255,48,48];
case 2
color=[255,69,0];
case 3
color=[255,105,180];
end
for num=1:10
a=picture;
for j=1:row
for i=1:col
if ((i-facelisf(1))2+(j-facelisf(2))2)<(R/10*(11-num))^2 || ((i-faceright(1))2+(j-faceright(2))2)<(R/10*(11-num))^2
picture(j,i,:)=color;
end
end
end
picture=0.01.picture+a.(1-0.01);

实验结果
在这里插入图片描述

7 瘦脸

算法原理
鼻子中心(关键点30)为收缩目标方向。
在这里插入图片描述

确定收缩区域圆心与半径,对于圆内的每个像素 ;收缩方向为该像素指向鼻子中心;距离圆心越近的点收缩力度越大;边缘处收缩力度为0。
在这里插入图片描述
在这里插入图片描述

主函数

global shoulian;
rm=shoulian;
spx=X(6);%306
spy=Y(6);
sp=[spy,spx];
fp =[spy-1,spx];
rm5=rm-1;s=0.7;
J=change(picture,sp,fp,rm5,s);
spx=(X(6)+X(5))/2;%306
spy=(Y(6)+Y(5))/2;
sp=[spy,spx];
fp =[spy-2,spx];
rm5=rm-1;s=0.6;
J=change(J,sp,fp,rm5,s);
spx=X(5);%98
spy=Y(5);
sp=[spy,spx];%起点坐标
fp =[spy-1,spx];%终点坐标
rm1=rm;s=0.75;%瘦脸参数
J=change(J,sp,fp,rm1,s);
spx=(X(4)+X(5))/2;%306
spy=(Y(4)+Y(5))/2;
sp=[spy,spx];
fp =[spy-2,spx];
rm5=rm-1;s=0.6;
J=change(J,sp,fp,rm5,s);
spx=X(4);%98
spy=Y(4);
sp=[spy,spx];%起点坐标
fp =[spy-2,spx];%终点坐标
rm1=rm;s=0.75;%瘦脸参数
J=change(J,sp,fp,rm1,s);
spx=(X(4)+X(3))/2;%306
spy=(Y(4)+Y(3))/2;
sp=[spy,spx];
fp =[spy-2,spx];
rm5=rm-1;s=0.6;
J=change(J,sp,fp,rm5,s);
spx=X(3);%127 143
spy=Y(3);
sp=[spy,spx];
fp =[spy-2,spx];
rm7=rm;s=0.75;
J=change(J,sp,fp,rm7,s);
spx=X(12);%303
spy=Y(12);
sp=[spy,spx];
fp =[spy-2,spx];
rm6=rm-1;s=0.6;
J=change(J,sp,fp,rm6,s);
spx=(X(12)+X(13))/2;%306
spy=(Y(12)+Y(13))/2;
sp=[spy,spx];
fp =[spy-2,spx];
rm5=rm-1;s=0.6;
J=change(J,sp,fp,rm5,s);
spx=X(13);%98
spy=Y(13);
sp=[spy,spx];%起点坐标
fp =[spy-2,spx];%终点坐标
rm1=rm;s=0.75;%瘦脸参数
J=change(J,sp,fp,rm1,s);
spx=(X(14)+X(13))/2;%306
spy=(Y(14)+Y(13))/2;
sp=[spy,spx];
fp =[spy-2,spx];
rm5=rm-1;s=0.6;
J=change(J,sp,fp,rm5,s);
spx=X(14);%269
spy=Y(14);
sp=[spy,spx];
fp =[spy-2,spx];
rm3=rm;s=0.75;
J=change(J,sp,fp,rm3,s);
spx=(X(14)+X(15))/2;%306
spy=(Y(14)+Y(15))/2;
sp=[spy,spx];
fp =[spy-2,spx];
rm5=rm-1;s=0.6;
J=change(J,sp,fp,rm5,s);
spx=X(15);%98
spy=Y(15);
sp=[spy,spx];%起点坐标
fp =[spy-2,spx];%终点坐标
rm1=rm;s=0.75;%瘦脸参数
J=change(J,sp,fp,rm1,s);

Change.m

%I为原图的rgb矩阵,sp为起点坐标,fp为矩阵的终点坐标,rm为半径,s为形变程度(0<s<1)
function J=change(I,sp,fp,rm,s);
J=I;
[ym xm]=size(rgb2gray(I));
%sp=[35 480];%起点
%fp=[1 40];%终点
%rm=100;%半径
%s=0.75;
p=sp;
zz=sp-fp;
z2=sqrt(zz(1)2+zz(2)2);
danwei=zz/z2;%单位向量
x1=1;x2=1;%表明迭代方向,负值代表递减迭代
if danwei(1)<0 x1=-1;end
if danwei(2)<0 x2=-1;end
for k=1:10 %迭代次数根据起点终点而定
yma=floor(min(p(1)+rm,ym));ymi=floor(max(1,p(1)-rm));
xma=floor(min(p(2)+rm,xm));xmi=floor(max(1,p(2)-rm));%四个边界值
sm1=ymi;sm2=yma;sn1=xmi;sn2=xma;ii=1;jj=1;
if x1<0 sm1=yma;sm2=ymi;ii=-1;end
if x2<0 sn1=xma;sn2=xmi;jj=-1;end
for i=sm1:ii:sm2%need
for j=sn1:jj:sn2%need
d2=(p(1)-i)2+(p(2)-j)2;
if d2 <= rm^2
ab=[p(1)-i,p(2)-j];
py=abs(abdanwei’);%平行于移动方向
px=sqrt(d2-py^2);%垂直于移动方向
fmn=5
(1-(1/rm)sqrt(spx2+(1-s)*py2))danwei+[i,j];
fm=fmn(1);fn=fmn(2);
if(fm<1||fm>ym||fn<1||fn>xm)
else
km=fm-floor(fm);kn=fn-floor(fn);
J(i,j,:)=(1-kn)
(kmJ(floor(fm)+1,j,:)+(1-km)J(floor(fm),j,:))+kn(kmJ(floor(fm)+1,j+1,:)+(1-km)J(floor(fm),j+1,:));
end
end
end
end
p=p+5
danwei;%实验测试发现取-5得到的效果为最佳
end

实验结果
在这里插入图片描述
8 贴纸

算法原理
同口红、眉毛、腮红等思想一样,定位关键点坐标后,将贴纸到定位到目的地位置。

算法设计

im = picture;
% 鼻子、耳朵、胡子占整个脸的比例
portion = X(15)-X(3);
portion1 = floor(portion/4); %鼻子的大小是脸(左右两边)的1/4 40
portion11 = floor(portion1/2);
portion12 = floor(portion1/2+1);
portion2 =floor(portion/3); %耳朵的大小是脸(左右两边)的1/3 60
portion21 = portion2+1;
portion3 = floor(portion/3); % 胡子应该是脸(左右两边)的1/3 60
portion31 = floor(portion3/2);
portion32 = portion3+1;
portion33 = portion31+1;

例如“狗鼻子”贴纸代码:

img = imread(’贴纸路径,为png图片’);
img = imresize(img,[portion1+1,portion1+1]);
//定位到鼻子中心点43处
biziX = floor(X(43));
biziY = floor(Y(43));
for row = biziY-portion11 : biziY+portion11
for col = biziX-portion11 : biziX+portion11
if img(row-(biziY-portion12),col-(biziX-portion12)) == 0
im(row,col,:) = im(row,col,:);
else
im(row,col,:) = img(row-(biziY-portion12),col-(biziX-portion12));
end
end
end

实验结果
在这里插入图片描述

本源码源码已上传至:

猜你喜欢

转载自blog.csdn.net/qq_52894587/article/details/128049115