MATLAB - 如何绘制面的边界?
MATLAB - How to plot the boundary of a face?
我使用 MATLAB 已经有几个星期了。但是我无法获得输入人脸图像的准确内边界。
我的代码涉及使用 Haar 级联来获得面部和鼻子周围的框。然后我用鼻框的中点作为鼻尖[nx, ny]
。从那以后,我尝试通过:
来获取面部的边界
- 正在将其转换为灰度
- 增加对比度
- 通过仅在以蓝色绘制的
[rows, cols]
范围掩码所限定的框中搜索来绘制人脸的 "Active Countour"。这个活动轮廓给出了脸部周围的粗略图像
- 由于边界开始超出面部,我想我需要 "erode" 图像
imerode
。接下来是 bwboundaries
。我还注释掉了使用 bwmorph
和 bwtraceboundaries
. 的替代方法
imgradient, imfilter
可能是不必要的,但我一直在玩弄它,看看一切会如何进行。当边界进入面部内部时,我想到用 imdilate
拨号图像。我不知道这样做是否是常见的做法,但边界是嗯,但是非常难看。
这是原始图像(没有标记):http://images.wisegeek.com/passport-photo.jpg
这是有丑陋边框的图片:
为此提供支持的代码:
clear all;
%Crop face part from Haar
I = imread('images/photo_1.jpg');
I = imresize(I,0.3);
face_detector = vision.CascadeObjectDetector;
nose_detector = vision.CascadeObjectDetector('Nose');
face_detector.MergeThreshold = 4;
nose_detector.MergeThreshold = 20;
fbox = step(face_detector, I); %holds coords of boxed image
nbox = step(nose_detector, I); %holds coords of boxed image
%find center of nose Haar box
nx = nbox(1) + nbox(3)/2;
ny = nbox(2) + nbox(4)/2;
%out = insertObjectAnnotation(I, 'rectangle',fbox, 'face', 'Color','cyan');
imshow(I);
hold on;
title('Original Image');
%plot tip of nose
plot(nx,ny, 'Marker','+','Color','red','MarkerSize',10);
factor = 20; %number of px before and after Haar boundary
rows = fbox(2)-factor:fbox(2)+fbox(4)+factor;
cols = fbox(1)-factor:fbox(1)+fbox(3)+factor;
%% Plot mask
mask = false(size(I(:,:,1)));
mask(rows, cols) = true;
visboundaries(mask, 'Color','b');
%%
I_gray = rgb2gray(I);
I_contrast = imadjust(I_gray);
f = fspecial('disk',1);
I_filtered = imfilter(I_contrast, f);
[Gmag, Gdir] = imgradient(I_filtered,'prewitt');
bw1 = activecontour(Gmag, mask, 600, 'edge');
se = strel('disk',15);
small_bw1 = imerode(bw1, true(60));
small_bw1 = imdilate(small_bw1,se);
small_boundary = bwboundaries(small_bw1);
% small_bw1 = bwmorph(bw1, 'thin', Inf);
% small_boundary = bwboundaries(small_bw1);
visboundaries(small_bw1,'Color','r');
title('Final is in red');
figure;
imshow(bw1), title('bw1');
%% Get Coordinates of face boundary
figure;
[B, L] = bwboundaries(bw1, 'noholes');
imshow(label2rgb(L, @jet, [.5 .5 .5]));
hold on;
for k = 1:length(B)
boundary = B{k};
plot(boundary(:,2), boundary(:,1), 'w', 'LineWidth', 2);
end;
这是我正在使用的一些示例图片:
- http://images.wisegeek.com/passport-photo.jpg
- http://thispix.com/wp-content/uploads/2015/06/passport-001.jpg
- http://www.srednja.hr/Photos/moda/makeup-for-life-phyllis-passport-picture.jpg
- http://www.naourmarket.com/public/img/agent_photos/passport2.jpg
最终objective是在脸部周围画一个完美的边界,但是没有头发。只有从 his/her 下巴到额头的皮肤部分应该被包围在边界内。任何建议,将不胜感激。
我扩展了您的代码以检测人脸,如下所示。
- 我是从使用
CascadeObjectDetector
检测鼻子和眼睛开始的。我将这些区域分别扩展到包括嘴巴和眉毛。这些区域被迫成为最终面部区域的一部分。
人脸边界的检测是通过对灰度图的二阶导数进行阈值化来完成的。尤其是下巴很难被正确检测到。通过应用大的腐蚀步骤突出显示下巴和颈部之间的边界。由于此步骤对面部区域的噪声敏感,因此首先通过应用小的膨胀和腐蚀步骤对图像进行非线性滤波。
人脸区域是用腐蚀后的图像来判断的,否则下巴和脖子的边界可能不清晰。之后,通过应用(反向)扩张步骤来撤消大腐蚀。
简单方法的结果相当不错,但并不完美。您可以通过迭代更改用于二阶导数的阈值来获得更好的结果。如果您从一个较大的阈值开始,颈部将包含在面部区域中。您可以通过假设鼻子区域和面部底部之间的某个最大距离来检测它。然后,您可以降低阈值,直到不再包括颈部。另一种使该方法更稳健的方法可能是标准化 LoG。
clear all;
close all;
I = imread('passport-001.jpg');
I = imresize(I,240/size(I, 1)); % resize all the images to the same size
nose_detector = vision.CascadeObjectDetector('Nose');
eye_detector = vision.CascadeObjectDetector('EyePairSmall');
nose_detector.MergeThreshold = 20;
nbox = step(nose_detector, I); % box around the nose
nbox = nbox(1,:); % guess the first box is correct
% extend the box to include the mouth
nbox(1) = nbox(1) - 0.1*nbox(3);
nbox(3) = 1.2*nbox(3);
nbox(4) = 1.5*nbox(4);
ebox = step(eye_detector, I); % box around the eyes
% extend the eye box to include the eyebrows
ebox(2) = ebox(2) - 0.5*ebox(4);
ebox(4) = 1.5*ebox(4);
%find center of nose Haar box
nx = nbox(1) + nbox(3)/2;
ny = nbox(2) + nbox(4)/2;
% plot the original image
figure
subplot(2,3,1);
imshow(I);
hold on;
title('Original Image');
% indicate the nose (with mouth) and eye regions
rectangle('Position',nbox,'EdgeColor', 'r')
rectangle('Position',ebox,'EdgeColor', 'r')
% create a filter for the detected parts of the face (eye, mouth and nose)
maskFilter = uint8(ones(size(I(:,:,1))));
maskFilter(nbox(2):(nbox(2)+nbox(4)), nbox(1):(nbox(1)+nbox(3))) = 0;
maskFilter(ebox(2):(ebox(2)+ebox(4)), ebox(1):(ebox(1)+ebox(3))) = 0;
% convert to grayscale
I_gray = rgb2gray(I);
% filter high frequency noise
I_gray = imfilter(I_gray, fspecial('gaussian', [3,3], 0.5));
% plot the filtered grayscale image
subplot(2,3,2); imshow(I_gray);
title('Gray');
% calculate second order derivatives (laplacian of gaussians)
f = fspecial('log',[5 5], 0.3);
I_filtered = imfilter(I_gray, f);
I_filtered = I_filtered.*maskFilter; % exclude the detected parts of the face
% plot the laplacian of gaussians
subplot(2,3,3); imshow(I_filtered);
title('LoG');
% apply thresshold to LoG
I_bin = I_filtered < 40;
seDiskNoise = strel('disk',1);
seDiskClose = strel('disk',10);
I_bin1 = imerode(imdilate(I_bin,seDiskNoise), seDiskNoise); % remove noise from the face
I_bin2 = imerode(I_bin1,seDiskClose); % close the boundaries of the face
I_bin3 = imdilate(I_bin2,seDiskClose); % reverse the erode (not used for processing)
subplot(2,3,4); imshow(I_bin1); title('LoG > 50');
subplot(2,3,5); imshow(I_bin2); title('eroded');
subplot(2,3,6); imshow(I_bin3); title('dilated');
CC = bwconncomp(I_bin2); % calculate the regions in the binary image
% search the region containing the nose
ni = sub2ind(size(I_gray), round(ny), round(nx));
for i=1:length(CC.PixelIdxList)
if any(CC.PixelIdxList{i}==ni)
iPhase = i;
end
end
% create a mask for the full face
maskFace = zeros(size(I_gray));
maskFace(CC.PixelIdxList{iPhase}) = 1;
% undo the erosion
maskFace = imdilate(maskFace, seDiskClose);
% visualise the face region
subplot(2,3,1);
visboundaries(maskFace,'Color','b');
% remove all the extrusions and inner regions of the face region
seDisk2 = strel('disk',20);
maskFace = imerode(imdilate(maskFace, seDisk2), seDisk2);
% draw the final face region in red
subplot(2,3,1);
visboundaries(maskFace,'Color','r');
title('Final is in red');
我使用 MATLAB 已经有几个星期了。但是我无法获得输入人脸图像的准确内边界。
我的代码涉及使用 Haar 级联来获得面部和鼻子周围的框。然后我用鼻框的中点作为鼻尖[nx, ny]
。从那以后,我尝试通过:
- 正在将其转换为灰度
- 增加对比度
- 通过仅在以蓝色绘制的
[rows, cols]
范围掩码所限定的框中搜索来绘制人脸的 "Active Countour"。这个活动轮廓给出了脸部周围的粗略图像 - 由于边界开始超出面部,我想我需要 "erode" 图像
imerode
。接下来是bwboundaries
。我还注释掉了使用bwmorph
和bwtraceboundaries
. 的替代方法
imgradient, imfilter
可能是不必要的,但我一直在玩弄它,看看一切会如何进行。当边界进入面部内部时,我想到用imdilate
拨号图像。我不知道这样做是否是常见的做法,但边界是嗯,但是非常难看。
这是原始图像(没有标记):http://images.wisegeek.com/passport-photo.jpg
这是有丑陋边框的图片:
为此提供支持的代码:
clear all;
%Crop face part from Haar
I = imread('images/photo_1.jpg');
I = imresize(I,0.3);
face_detector = vision.CascadeObjectDetector;
nose_detector = vision.CascadeObjectDetector('Nose');
face_detector.MergeThreshold = 4;
nose_detector.MergeThreshold = 20;
fbox = step(face_detector, I); %holds coords of boxed image
nbox = step(nose_detector, I); %holds coords of boxed image
%find center of nose Haar box
nx = nbox(1) + nbox(3)/2;
ny = nbox(2) + nbox(4)/2;
%out = insertObjectAnnotation(I, 'rectangle',fbox, 'face', 'Color','cyan');
imshow(I);
hold on;
title('Original Image');
%plot tip of nose
plot(nx,ny, 'Marker','+','Color','red','MarkerSize',10);
factor = 20; %number of px before and after Haar boundary
rows = fbox(2)-factor:fbox(2)+fbox(4)+factor;
cols = fbox(1)-factor:fbox(1)+fbox(3)+factor;
%% Plot mask
mask = false(size(I(:,:,1)));
mask(rows, cols) = true;
visboundaries(mask, 'Color','b');
%%
I_gray = rgb2gray(I);
I_contrast = imadjust(I_gray);
f = fspecial('disk',1);
I_filtered = imfilter(I_contrast, f);
[Gmag, Gdir] = imgradient(I_filtered,'prewitt');
bw1 = activecontour(Gmag, mask, 600, 'edge');
se = strel('disk',15);
small_bw1 = imerode(bw1, true(60));
small_bw1 = imdilate(small_bw1,se);
small_boundary = bwboundaries(small_bw1);
% small_bw1 = bwmorph(bw1, 'thin', Inf);
% small_boundary = bwboundaries(small_bw1);
visboundaries(small_bw1,'Color','r');
title('Final is in red');
figure;
imshow(bw1), title('bw1');
%% Get Coordinates of face boundary
figure;
[B, L] = bwboundaries(bw1, 'noholes');
imshow(label2rgb(L, @jet, [.5 .5 .5]));
hold on;
for k = 1:length(B)
boundary = B{k};
plot(boundary(:,2), boundary(:,1), 'w', 'LineWidth', 2);
end;
这是我正在使用的一些示例图片:
- http://images.wisegeek.com/passport-photo.jpg
- http://thispix.com/wp-content/uploads/2015/06/passport-001.jpg
- http://www.srednja.hr/Photos/moda/makeup-for-life-phyllis-passport-picture.jpg
- http://www.naourmarket.com/public/img/agent_photos/passport2.jpg
最终objective是在脸部周围画一个完美的边界,但是没有头发。只有从 his/her 下巴到额头的皮肤部分应该被包围在边界内。任何建议,将不胜感激。
我扩展了您的代码以检测人脸,如下所示。
- 我是从使用
CascadeObjectDetector
检测鼻子和眼睛开始的。我将这些区域分别扩展到包括嘴巴和眉毛。这些区域被迫成为最终面部区域的一部分。 人脸边界的检测是通过对灰度图的二阶导数进行阈值化来完成的。尤其是下巴很难被正确检测到。通过应用大的腐蚀步骤突出显示下巴和颈部之间的边界。由于此步骤对面部区域的噪声敏感,因此首先通过应用小的膨胀和腐蚀步骤对图像进行非线性滤波。
人脸区域是用腐蚀后的图像来判断的,否则下巴和脖子的边界可能不清晰。之后,通过应用(反向)扩张步骤来撤消大腐蚀。
简单方法的结果相当不错,但并不完美。您可以通过迭代更改用于二阶导数的阈值来获得更好的结果。如果您从一个较大的阈值开始,颈部将包含在面部区域中。您可以通过假设鼻子区域和面部底部之间的某个最大距离来检测它。然后,您可以降低阈值,直到不再包括颈部。另一种使该方法更稳健的方法可能是标准化 LoG。
clear all;
close all;
I = imread('passport-001.jpg');
I = imresize(I,240/size(I, 1)); % resize all the images to the same size
nose_detector = vision.CascadeObjectDetector('Nose');
eye_detector = vision.CascadeObjectDetector('EyePairSmall');
nose_detector.MergeThreshold = 20;
nbox = step(nose_detector, I); % box around the nose
nbox = nbox(1,:); % guess the first box is correct
% extend the box to include the mouth
nbox(1) = nbox(1) - 0.1*nbox(3);
nbox(3) = 1.2*nbox(3);
nbox(4) = 1.5*nbox(4);
ebox = step(eye_detector, I); % box around the eyes
% extend the eye box to include the eyebrows
ebox(2) = ebox(2) - 0.5*ebox(4);
ebox(4) = 1.5*ebox(4);
%find center of nose Haar box
nx = nbox(1) + nbox(3)/2;
ny = nbox(2) + nbox(4)/2;
% plot the original image
figure
subplot(2,3,1);
imshow(I);
hold on;
title('Original Image');
% indicate the nose (with mouth) and eye regions
rectangle('Position',nbox,'EdgeColor', 'r')
rectangle('Position',ebox,'EdgeColor', 'r')
% create a filter for the detected parts of the face (eye, mouth and nose)
maskFilter = uint8(ones(size(I(:,:,1))));
maskFilter(nbox(2):(nbox(2)+nbox(4)), nbox(1):(nbox(1)+nbox(3))) = 0;
maskFilter(ebox(2):(ebox(2)+ebox(4)), ebox(1):(ebox(1)+ebox(3))) = 0;
% convert to grayscale
I_gray = rgb2gray(I);
% filter high frequency noise
I_gray = imfilter(I_gray, fspecial('gaussian', [3,3], 0.5));
% plot the filtered grayscale image
subplot(2,3,2); imshow(I_gray);
title('Gray');
% calculate second order derivatives (laplacian of gaussians)
f = fspecial('log',[5 5], 0.3);
I_filtered = imfilter(I_gray, f);
I_filtered = I_filtered.*maskFilter; % exclude the detected parts of the face
% plot the laplacian of gaussians
subplot(2,3,3); imshow(I_filtered);
title('LoG');
% apply thresshold to LoG
I_bin = I_filtered < 40;
seDiskNoise = strel('disk',1);
seDiskClose = strel('disk',10);
I_bin1 = imerode(imdilate(I_bin,seDiskNoise), seDiskNoise); % remove noise from the face
I_bin2 = imerode(I_bin1,seDiskClose); % close the boundaries of the face
I_bin3 = imdilate(I_bin2,seDiskClose); % reverse the erode (not used for processing)
subplot(2,3,4); imshow(I_bin1); title('LoG > 50');
subplot(2,3,5); imshow(I_bin2); title('eroded');
subplot(2,3,6); imshow(I_bin3); title('dilated');
CC = bwconncomp(I_bin2); % calculate the regions in the binary image
% search the region containing the nose
ni = sub2ind(size(I_gray), round(ny), round(nx));
for i=1:length(CC.PixelIdxList)
if any(CC.PixelIdxList{i}==ni)
iPhase = i;
end
end
% create a mask for the full face
maskFace = zeros(size(I_gray));
maskFace(CC.PixelIdxList{iPhase}) = 1;
% undo the erosion
maskFace = imdilate(maskFace, seDiskClose);
% visualise the face region
subplot(2,3,1);
visboundaries(maskFace,'Color','b');
% remove all the extrusions and inner regions of the face region
seDisk2 = strel('disk',20);
maskFace = imerode(imdilate(maskFace, seDisk2), seDisk2);
% draw the final face region in red
subplot(2,3,1);
visboundaries(maskFace,'Color','r');
title('Final is in red');