i have a real time skin detection algorithm where it gives me a bounding box around the skin region with rectangle('Position',bb,'EdgeColor','r','LineWidth',2) from an original image. I wish to use the code to first detect the skin region from the original image before i use Viola Jones to detect the face region from the cropped skin region. I wish to know after i crop the skin region then use the face detection algorithm to detect the face, how can i map the bounding box of the face to the original image.
function cameraon_Callback(hObject, eventdata, handles)
% hObject handle to cameraon (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global video;
global videoFrame;
axes(handles.axes1);
video = videoinput('winvideo',1,'YUY2_320x240');
set(video,'ReturnedColorSpace','rgb');
handles.video=video;
triggerconfig(video,'manual');
video.FramesPerTrigger = 1;
guidata(hObject,handles);
faceDetector=vision.CascadeObjectDetector('FrontalFaceCART');
faceDetector.MinSize=[20 20];
faceDetector.MergeThreshold = 20;
videoFrame=getsnapshot(video);
bbox=step(faceDetector,videoFrame);
if numel(bbox) == 0
errordlg('Face not detected. Please try again.');
set(handles.cameraon,'String','Start Camera')
stop(video);
delete(video);
clear;
else
axes(handles.axes1);
start(video);
end
while(true)
frame=getsnapshot(video);
%Detect faces.
data = frame;% this is to read a image from data base. just put any image name u want to give make sure its placed in bin
diff_im = imsubtract(data(:,:,1), rgb2gray(data)); % deleting gray scale pixels from image
diff_im = medfilt2(diff_im, [3 3]); %applying filter one
diff_im = imadjust(diff_im); % adjust image function to fill small holes (check all the function's functionality to have idea of whats going on)
level = graythresh(diff_im);% extract level value
bw = im2bw(diff_im,level);
BW5 = imfill(bw,'holes');
bw6 = bwlabel(BW5, 8);
stats = regionprops(bw6,['basic']);%basic mohem nist
measurements = regionprops(bw6, 'boundingbox');
BB1=struct2cell(measurements);
BB2=cell2mat(BB1);
a = BB2(1);
b = BB2(2);
c = BB2(3);
d = BB2(4);
[N,M]=size(stats);
if (bw==0)% check if there is no skin color then exit
break;
else
tmp = stats(1);
for i = 2 : N % checking for biggest hole to mark it as face
if stats(i).Area > tmp.Area
tmp = stats(i);
end
end
bb = tmp.BoundingBox; % applying identification square to mark skin color region
bc = tmp.Centroid;
videoFrame=getsnapshot(video);
This is the place where i cannot put the bounding box back to the original image.
skinImage = imcrop(videoFrame,bb(1,:));
bbox = step(faceDetector,skinImage);
bbox(1,1:2) = bbox(1,1:2) + bb(1,1:2);
videoOut = insertObjectAnnotation(videoFrame,'rectangle',bbox,'Face');
cla;
imshow(videoOut,[]);
drawnow;
pause(0.0001);
end
end
guidata(hObject,handles);
I want to put the rectangle i got from the face detector onto the full size image at the original location in the image where the cropped image come from.
You simply add the coordinates of the top-left corner of the cropped region to the top-left corners of the detected bounding boxes.
Also, in the latest version of MATLAB vision.CascadeObjectDetector supports passing in the region of interest where you want to detect objects, so that you do not need to crop. Then it will adjust the coordinates for you. Check the documentation for the step() method of vision.CascadeObjectDetector.
Related
New to Matlab here. I'm trying to implement some code to detect a face in an image and crop it. I have the script running, but the bounding box that it places around the detected face is a bit small. Is there any way to change the dimensions of the bounding box to capture more of the faces?
clc;
% cd into the a folder with pictures
cd 'C:\Users\abc\Desktop\folder'
files = dir('*.jpg');
for file = files'
img = imread(file.name);
figure(1),imshow(img);
FaceDetect = vision.CascadeObjectDetector;
FaceDetect.MergeThreshold = 7;
BB = step(FaceDetect,img);
figure(2),imshow(img);
for i = 1:size(BB,1)
rectangle('Position',BB(i,:),'LineWidth',2,'LineStyle','- ','EdgeColor','r');
end
for i = 1:size(BB,1)
rectangle('Position',BB(i,:),'LineWidth',2,'LineStyle','- ','EdgeColor','r');
J = imcrop(img,BB(i,:));
figure(3);
imshow(J);
a = 'edited\'
b = file.name
output = strcat(a,b);
imwrite(J,output);
end
%Code End
end
Currently, the script finds a face like so:
And outputs an image such as this:
This is good, I just want to extend the boundaries of the cropping zone to capture more of the face (e.g., hair and chin).
From the MATLAB rectangle function documentation.
rectangle('Position',pos) creates a rectangle in 2-D coordinates.
Specify pos as a four-element vector of the form [x y w h] in data
units. The x and y elements determine the location and the w and h
elements determine the size. The function plots into the current axes
without clearing existing content from the axes.
If you are just looking to increase the bounding box by some scale factor about the center of the rectangle, you could scale the w and h components in BB and adjust the rectangle origin x and y by subtracting half the scale difference. The following code should work if you place it right after the BB = step(FaceDetect,img); line in your code. I don't have MATLAB available to me at the moment but I'm pretty sure this will work.
% Scale the rectangle to 1.2 times its original size
scale = 1.2;
% Adjust the lower left corner of the rectangles
BB(:,1:2) = BB(:,1:2) - BB(:,3:4)*0.5*(scale - 1)
% Adjust the width and height of the rectangles
BB(:,3:4) = BB(:,3:4)*scale;
You can use imresize function in Matlab as described in this link and bboxresize to resize the bounding box
Below is the simple code to resize your image into 3 times the original one
%% clean workspace
clc;
clear;
cd 'C:\Users\abc\Desktop\folder';
files = dir('*.jpg');
for file = files'
img = imread(file.name) ;
figure(1),imshow(img);
FaceDetect = vision.CascadeObjectDetector;
FaceDetect.MergeThreshold =7;
BB = step(FaceDetect,img);
BB2 = BB;
%% Scale the rectangle to 3 times its original size
scale = 3;
%% Resize image
ImgResized = imresize(img,scale);
%% Resize bound box using the function named bboxresize in Matlab
BBResized = bboxresize(BB,scale);
figure(2),imshow(ImgResized);
%% Draw Bounding Box
for i=1:size(BBResized,1)
rectangle('position',BBResized(i,:),'lineWidth',2,'LineStyle','- ','EdgeColor','y');
end
end
WARNING - Complete n00b here.
I'm working on a project which needs to find holes. I found a method that is fairly accurate (bwconncomp) but I get some extra data that I don't need (a.k.a holes that aren't holes). Now the holes are circular so I was just going to do a check with imfindcircles.
So what I need to do is take the center coordinate and radius info from imfindcircles to filter out the non-circular holes in bwconncomp. How should I tackle that?
%Find Circles
[centersDark, radiiDark] = imfindcircles(im,[10 75],'ObjectPolarity','dark');
%Find holes (I think)
cc = bwconncomp(BW);
%Put box around holes (prints to figure for debugging... kinda)
rp = regionprops(cc,'BoundingBox');
So just to clarify, I need to figure out how to weed out the extra info in cc from the data received in from imfindcircles (those variables being centersDark and radiiDark)
Here's a sample image:
You can also improve your segmentation stage:
close all;
% read input
im = imread('holes.bmp');
grayImg = rgb2gray(im);
% create an image where holes are removed
med = medfilt2(grayImg,[100,100],'symmetric');
figure();
imshow(med);
title('median');
% subtract image with holes from image without holes
% so the whole process is less dependent on ilumination of foreground
diff = double(med) - double(BW);
figure();
imshow(uint8(diff+127));
title('difference');
% apply threshold
bw = diff > 50;
figure();
imshow(bw);
title('threshold');
% remove small objects
SE = strel('disk',10);
opened = imopen(bw,SE);
figure();
imshow(opened);
title('imopen');
% get bounding boxes for each hole
cc = bwconncomp(opened);
rp = regionprops(cc,'BoundingBox');
% draw rectangles
figure();
imshow(im);
hold on;
title('result');
for i = 1:length(rp)
rectangle('Position',rp(i).BoundingBox,'EdgeColor','red')
end
Result:
I have a code that detects a face in an image and places a bounding box around the image like below.
But I want to go further and colour the area outside the bounding box black so that only the face can be seen and the background becomes black.
Original code..
FDetect = vision.CascadeObjectDetector;
I = imread('PresidentClinton.jpg');
%Returns Bounding Box values based on number of objects
BB = step(FDetect,I);
figure,
imshow(I); hold on
for i = 1:size(BB,1)
rectangle('Position',BB(i,:),'LineWidth',5,'LineStyle','-','EdgeColor','r');
end
title('Face Detection');
hold off;
Here is a simple method in which you first create a target image of the same size/class as your original image and fill it with black. Then you get the rectangle coordinates and assign the data from the original image to the target image:
clear
close all
A = imread('peppers.png');
B = zeros(size(A),class(A)); % //Pre-define target image of identical size and class than original.
%// You could also use this line:
%//B = zeros(size(A),'like',A);
hRect = rectangle('Position',[100 100 200 160],'LineWidth',3); %// Define rectangle
RectPos = get(hRect, 'Position'); %// Get the coordinates of the rectangle.
x = RectPos(1):RectPos(1)+RectPos(3); %// Define x- and y-span
y = RectPos(2):RectPos(2)+RectPos(4);
B(x,y,:) = A(x,y,:); %// Assign the selected part of the image to B
figure
subplot(1,2,1)
imshow(A)
subplot(1,2,2)
imshow(B)
Giving something like this:
There are other ways of course but I think this one is straightforward and easy to implement in a loop.
I am trying to make a binary region of interest mask over an image stack (GUI). Here is what I have thus far:
% Initalize lesion mask
LesionMask = zeros(size(handles.ImageOne));
% Create an ellipse for roi analysis
Lesion = imellipse(handles.axes1);
% Save roi to 3D binary mask
LesionMask(:,:,handles.CurrentSlice) = Lesion.createMask();
boundary = bwboundaries(LesionMask(:,:,handles.CurrentSlice))
Now I would like to overlay the boundary over my image, in particular, I would like it to stay even when I go through my image stack.
In short, I would like to plot the edge of the ellipse over my image.
Thanks!
This might work for you when added to your code at the end -
hold on
for k = 1:numel(boundary)
plot(boundary{k}(:,2), boundary{k}(:,1), 'r', 'Linewidth', 3) %// Red border
end
Inspired from this blog
If you would like to keep the edge on the image saved for later usage, try this -
[M,N,C] = size(handles.ImageOne)
t1 = cell2mat(boundary);
ind1 = sub2ind([M N],t1(:,1),t1(:,2));
ind2 = bsxfun(#plus,ind1,[0:C-1].*(M*N));
handles.ImageOne(ind2)=0; %// Creates a black border
the region of interest in the image are calculated. Now how to embed the watermark into the roi..i ve put the code for embedding it in the whole image in lsb. How can it modified for roi alone?
clear all;
file_name='pout.tif';
cover_object=imread(file_name);
file_name='cameraman.tif';
message=imread(file_name);
message=double(message);
message=round(message./256);
message=uint8(message);
Mc=size(cover_object,1);
Nc=size(cover_object,2);
Mm=size(message,1);
Nm=size(message,2);
for ii = 1:Mc
for jj = 1:Nc
watermark(ii,jj)=message(mod(ii,Mm)+1,mod(jj,Nm)+1);
end
end
watermarked_image=cover_object;
for ii = 1:Mc
for jj = 1:Nc
watermarked_image(ii,jj)=bitset(watermarked_image(ii,jj),1,watermark(ii,jj));
end
end
imwrite(watermarked_image,'watermarkedimage','bmp');
figure(1)
imshow(watermarked_image,[])
title('Watermarked Image')
If your roi is rectangular, just loop over the appropriate subsection of the image rather than the whole thing.
If not, and you can define the watermarking as some function:
imgout = watermark(img1, img2);
Then you can use roifilt2 to apply that function just in your roi.
In this simple example,mask is a BW matrix where 1 indicates part of our roi (a mask can be created several different ways including using some of the interactive roi functions, see bottom section). img1 and img2 have already been loaded:
f = #(x) watermark(x,img2); % our very basic function
imgout = roifilt2(img1,mask,f);
Complications may arise if your img2 is smaller than img1 (or if you want to resize it to just cover the roi area). In this case, do everything on a subsection of img1/mask and then assemble the final image:
img1_s = img1(a:b,c:d); % these return the same size as img2
mask_s = mask(a:b,c:d);
imgout_s = roifilt2(img1_s,mask1_s,f);
imgout = img1;
imgout(a:b,c:d) = imgout_s;
A mask can be created several ways, some using the interactive roi functions, some not. A lot depends on how you have your roi in the first place - do you have a centre/radius, or do you want to hand-pick the location interactively, etc. Here are a few examples making use of the Image Processing Tool Box:
Interactive ROI function and createMask.
This will work for any of the interactive roi functions (imellipse, imfreehand, etc). You can interactively adjust the mask between the second and third steps. Do not close the image window before calling createMask.
h = imshow(img); %display image
e = imellipse(gca,[50 50 100 100]); % select roi
mask = createMask(e,h); % return mask
List of x/y points and poly2mask
If you have a list of points defining the outer edge of your roi, a quick non-interactive way of producing a mask is to use poly2mask. The third and fourth values define the total size of the mask returned.
mask = poly2mask(x,y,size(img,1),size(img,2));
Using morphological operators
strel defines a structuring element, and imdilate performs a dilation using that structuring element. Given an image which contains a single point, what that does is replace the point with the structuring element - in this case disk which will produce a circle (or as close as you can get using pixels). Other shapes (e.g. diamond) can be used with strel
mask = zeros(size(img));
mask(a,b) = 1; % a,b is the centre point of the circle
se = strel(disk,r,0); %r is the radius of the circle
mask = imdilate(mask,se);