更换底色最简单直接的方法就是遍历图像中每个像素值,并设置一个阈值,将阈值范围内的背景色替换为指定颜色,但该方法对于拍摄者衣服颜色非单一时的更换效果并不理想。
更换尺寸时若直接将原证件照进行imresize处理,可能会出现人像被拉伸或压缩的情况,这无疑会影响证件照的标准性和美观性。这些都并不利于制作标准证件照。
以下是结合二值化和数学形态学处理来抠取人像实现更换证件照底色的方法。
人像抠取效果如图:
%按钮-证件照制作
colorvalue = app.DropDown_photobackcolor.Value;%用户返回的证件照底色
sizevalue = app.DropDown_photobacksize.Value;%用户返回的证件照尺寸
%尺寸
switch sizevalue
case 2
disp("1寸");
br=413;
bc=295;
case 3
disp("2寸");
br=579;
bc=413;
case 4
disp("二代身份证");
br=531;
bc=413;
case 5
disp("小一寸");
br=378;
bc=260;
case 6
disp("大一寸");
br=567;
bc=390;
end
switch colorvalue
case 2
disp("红底");
Im=zeros(br,bc,3);
Im(:,:,1)=255;%红底
case 3
disp("白底");
Im=ones(br,bc,3)*255;%白底
% Im(:,:,1)=255;
case 4
disp("蓝底");
Im=zeros(br,bc,3);
Im(:,:,3)=255;%蓝底
end
%方法
input_image=app.Temp_Img;%可换原图像
%更换底色
%抠图
image=im2double(input_image);%转换成统一的double精度,方便计算
BW_RGB=im2bw(input_image,0.65);%显示RGB二值化结果
BW_R=im2bw(image(:,:,1),0.65);
judge=BW_R(2,2);
if judge~=0
BW_R=imcomplement(BW_R);
end
BW_B=im2bw(input_image(:,:,3),0.65);
judge2=BW_B(2,2);
if judge2==0
BW_B=imcomplement(BW_B);
end
BW_RGB_inverse=~BW_RGB;
BW_B_inverse=~BW_B;
BW_R_inverse=~BW_R; %将二值化结果取反
%根据以上二值化所得结果,从其中选取两个二值化图像合成想要的二值化像素图
BW=im2bw(BW_B_inverse+BW_R);
%多次测试,发现蓝色二值化取反结果与红色二值化结果合成图像最为完整
height=size(BW,1);%在底部添加一行全黑再填充空洞效果更好
BW(height,:)=255;
BW_fill1=imfill(BW,'holes'); %空洞填充函数:imfill(填洞)
N1=4;se1=strel('disk',N1); %设置膨胀算子
BW_dilate1=imdilate(BW_fill1,se1); %膨胀
N2=7;se2=strel('square',N2); %设置腐蚀算子
BW_erode1=imerode(BW_dilate1,se2); %腐蚀
[bw_r,bw_c,zz]=size(BW_erode1);
%用户选择的底色
switch colorvalue
case 2
disp("红底");
Im=zeros(bw_r,bw_c,3);
Im(:,:,1)=255;%红底
case 3
disp("白底");
Im=ones(bw_r,bw_c,3)*255;%白底
% Im(:,:,1)=255;
case 4
disp("蓝底");
Im=zeros(bw_r,bw_c,3);
Im(:,:,1)=67;%蓝底
Im(:,:,2)=142;%蓝底
Im(:,:,3)=219;%蓝底
end
Im=uint8(Im);
[a,b]=find(BW_erode1==1);
A=Im;
for i=1:size(a,1)
A(a(i),b(i),1)=input_image(a(i),b(i),1);
A(a(i),b(i),2)=input_image(a(i),b(i),2);
A(a(i),b(i),3)=input_image(a(i),b(i),3);
end
%更换尺寸
k_back=br/bc;%标准比例
k_front=bw_r/bw_c;%人像图片比例
if k_back<k_front %短长
newBW=imcrop(A,[1 1 bw_r bw_c*k_back]);%裁剪底部
else %宽短
disp(bw_r/k_back);
num=round(bw_c-bw_r/k_back);%一共需裁剪num列
newBW=imcrop(A,[num/2,0,bw_c-num,bw_r]);%左右两边同时裁
end
B=imresize(newBW,[br,bc]);
imshow(B,'Parent',app.UIAxes_2);
最终效果图如下: