matlab code for face detection using RGB space color && skin color

5 views (last 30 days)
I have this matlab code for face detection using RGB space color and it is works 100%
clc
I=imread('my.jpg');
figure,imshow(I);
%%skin region in rgb image%%%%%%%%% if(size(I, 3) > 1)
final_image = zeros(size(I,1), size(I,2));
for i = 1:size(I,1)
for j = 1:size(I,2)
R = I(i,j,1);
G = I(i,j,2);
B = I(i,j,3);
if(R > 95 && G > 40 && B > 20)
v = [R,G,B];
if((max(v) - min(v)) > 15)
if(abs(R-G) > 15 && R > G && R > B)
%it is a skin
final_image(i,j) = 1;
end
end
end
end
end
end %%%added
figure, imshow(final_image);
disp('before');
BW=final_image;
%else
% BW=im2bw(I);
% figure, imshow(BW);
%disp('convert');
%end
L = bwlabel(BW,4);
BB = regionprops(L, 'BoundingBox');
BB1 =struct2cell(BB) BB2 = cell2mat(BB1);. [s1 s2]=size(BB2);
mx=0;
for k=3:4:s2-1
p=BB2(1,k)*BB2(1,k+1);
if p>mx && (BB2(1,k)/BB2(1,k+1))<1.8
mx=p;
j=k;
end
end
the questions 1. why for- loop "for k=3:4:s2-1" ??
2. what does this loop ??
3. what dose "if p>mx && (BB2(1,k)/BB2(1,k+1))<1.8" ?
4. what step of loop is 3 ??
  1 Comment
DGM
DGM on 22 Sep 2024
Edited: DGM on 22 Sep 2024
Editor's note: I fixed the code block formatting, but I left all the dead code, missing linebreaks, invalid operators, and bad indentation. It's part of the experience.

Sign in to comment.

Answers (2)

DGM
DGM on 22 Sep 2024
Edited: DGM on 23 Sep 2024
Good gravy.
This is what that section does.
% using bwlabel is unnecessary unless you actually want to
% explicitly use 4-connectivity for blob analysis
% if so, it would probably be better to just use bwconncomp() instead.
L = bwlabel(BW,4);
BB = regionprops(L, 'BoundingBox');
% this just makes everything harder to address
BB1 = struct2cell(BB);
BB2 = cell2mat(BB1);
% find which blob represents the "face"
[s1 s2] = size(BB2);
mx = 0; % the current largest bbox area
for k = 3:4:s2-1 % this garbage is the consequence of collapsing all properties into a vector
p = BB2(1,k)*BB2(1,k+1); % the area of this bounding box
% if this area is larger than the running max area
% and the aspect ratio of the bbox is such that
% the width is less than 1.8 times the height
if p>mx && (BB2(1,k)/BB2(1,k+1))<1.8
mx = p; % update the running max bbox area
j = k; % record the index of the blob with max bbox area
end
end
... of course, j is not an index into S or L, so it doesn't directly tell us which blob is chosen. It's an index into a vectorized pile of properties from regionprops(). We have to reconstruct what the index should have been.
chosenidx = 1 + (j - 3)/4; % this shouldn't have been necessary
That whole mess can be avoided.
inpict = imread('person1.jpg');
% check input depth
if(size(inpict,3) ~= 3)
error('image must be RGB');
end
% if you're going to assume it's uint8, make it uint8
inpict = im2uint8(inpict);
% box mask in RGB
mkrgb = inpict(:,:,1) > 95 ...
& inpict(:,:,2) > 40 ...
& inpict(:,:,3) > 20;
% mask based on chroma
mkc = (max(inpict,[],3) - min(inpict,[],3)) > 15;
% mask based on red dominance
mkrg = (inpict(:,:,1) - inpict(:,:,2)) > 15 ...
& inpict(:,:,1) > inpict(:,:,3);
% combine the masks
mask = mkrgb & mkc & mkrg;
% get rid of specks which are too small
% to be plausible or useful
mask = bwareaopen(mask,100);
% get bounding box metrics
S = regionprops(mask,'BoundingBox','PixelIdxList');
BB = vertcat(S.BoundingBox);
bbarea = BB(:,3).*BB(:,4);
bbaspect = BB(:,3)./BB(:,4);
% sort and winnow
[~,candidates] = sort(bbarea,'descend');
candidates = candidates(bbaspect(candidates) < 1.8);
chosenidx = candidates(1);
% reduce the mask
outmask = false(size(mask));
outmask(S(chosenidx).PixelIdxList) = true;
imshow(outmask)
Other than the call to bwareaopen() (and the fact that it actually works), this is functionally the same as the original example.
Like every other example I've seen, it doesn't "work 100%". Finding skin by a fixed RGB color selection has obvious problems with lighting and skin color variation. Filtering blobs by area or aspect ratio might be prudent, but operating on the bounding box instead of the actual blob is probably going to cause problems. A long thin diagonal line has a larger bbox area than a circle of the same area. This strategy seems like a great way to pick up low-solidity objects which are obviously not faces.(long hair, arms, background objects, etc).
Out of all my face test images, none of them were correctly identified by this method without including large amounts of irrelevant content. I actually had to go find an image that would work with the code.
  1 Comment
DGM
DGM on 23 Sep 2024
Edited: DGM on 23 Sep 2024
For emphasis, this is the region covered by the masking operations in the original example:
Compared to the reference points which were condensed from a large set of photographic samples, the given method will tend to overselect regions which are much more saturated than what one might expect from skin tones.
These are the sample points which were plotted. How many of these samples look like skin?
These are from the reference group. That's a fairly inclusive range for skin tones, but the chroma and hue are much more constrained.

Sign in to comment.


Image Analyst
Image Analyst on 22 Sep 2024
RGB is probably the worst color space you can do skin segmentation in. HSI, HSL, LCH are better? Why? Because the skin gamut is not a rectangular region that can be carved out by specifying thresholds for each axis to get the bounding box of it without including a bunch of other non-skin colors in the box. Just run the attached demo, skin_color.m, where I plotted a bunch of skin colors that we collected with our spectrophotometer.
As you can see from looking down the L axis, all skin colors are about the same hue -- they all lie roughly along a plane coming off the L axis at the same angle. Makes sense. Everybody has red blood in their skin so all colors are various shades of red. There are no green- or blue-skinned people (at least not in real life - movies are another world).
Now let's look at it in 3-D. You can see that the gamut of skin colors has a boomerang shape.
Why is it a boomerang shape? Because there are no gray-skinned people (no points along the L axis with zero saturation value. It curves back towards the L axis for very pale skin because very pale white skin has little saturation (vivid color). Same thing for the very dark skin colors. When skin is black, you can't, at the same time, have a vivid color to it. But the in-between lightnesses can have a noticeable skin tone/color.
Thus to truly capture only skin colored pixels perfectly you'd have to have a segmentation routine that carves out that boomerang shape.
The other demo is an attempt I made at segmentation using two different color spaces. Try running that for several visualizations.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!