Draw a rectangle in the preview window in MATLAB - matlab

How do I draw rectangles over the detected faces in the preview window in MATLAB? I have done a program in MATLAB for face detection and this program when it is running will take one frame and detect the face in that frame and draw circles over that face. However, I need to draw rectangles in the preview window so that I can achieve a continuous face detection. Can anybody give an answer for this?

Use the rectangle command. Assuming that the figure window is already open, you can call rectangle like so:
rectangle('Position', [x y w h]);
x and y denote the column and row co-ordinate of the top left corner of your rectangle. w,h denote the width and height of the rectangle. By default, this will draw a black rectangle. If you want to change the line colour, you can do:
rectangle('Position', [x y w h], 'EdgeColor', 'c');
c would be a string of the colour you want (i.e. 'red', 'blue', 'yellow', etc.)
Hope this helps!

Related

Ignore certain area(roi) in an image while processing in Matlab

I'm a fresher to Matlab. I'm working on
vision.CascadeObjectDetector on Mat-lab and is used
twice to find-out two different objects(separately
trained), say E and K from a video. bbox and bbox2
are respective ROIs. part of code in while loop is given below:
videoFrame=step(videoFileReader);
bbox=step(letterDetector_E,videoFrame);
bbox2=step(letterDetector_K,videoFrame);
C = vertcat(bbox,bbox2);
videoOut=insertObjectAnnotation(videoFrame, 'rectangle', C, 'E&K');
step(videoPlayer, videoOut);
I want to ignore the area denoted by bbox while finding out bbox2. That is, no two object should be find out from same part of image(obviously there are similiarities in both type of objects). So I wish to mask or ignore bbox area of videoFrame while
bbox2 is assigned with step(letterDetector_K, videoFrame)
is executing. Format of bbox is [xUpperLeft, yUpperLeft, width,
height].
How can I do that.
That's pretty easy to do. Once you detect the first shape, use the bounding box detected for the first object E, then insert a filled rectangle in that spot using insertShape. Make sure you set the Opacity to 1.0 so that it doesn't mix any pixels from the background into this rectangle, and choose a colour of the filled rectangle that is completely different from the object you're trying to detect. Perhaps choose black. Also, I would recommend you turn off anti-aliasing when drawing the rectangle, because it actually takes more time to draw a shape with this turned on. Anti-aliasing essentially smoothes edges for any shapes. Because you don't want to include information with this region, there's really no need for anti-aliasing and so set this to false. This is done with the SmoothEdges option.
Once you're finished filling the shape in, use this modified frame and detect the next object K. As such, you only need one more line of code, so do this:
videoFrame=step(videoFileReader);
bbox=step(letterDetector_E,videoFrame);
%// NEW - Insert filled rectangle
videoFrame = insertShape(videoFrame, 'FilledRectangle', bbox, ...
'Opacity', 1.0, 'Color', 'black', ...
'SmoothEdges', false);
%// Now detect next shape on modified frame
bbox2=step(letterDetector_K,videoFrame);
C = vertcat(bbox,bbox2);
videoOut=insertObjectAnnotation(videoFrame, 'rectangle', C, 'E&K');
step(videoPlayer, videoOut);
How insertShape works is that it takes in an image (videoFrame in your case), then you specify the FilledRectangle flag and the bounding box location, which precisely coincides with a 4 element array in the way you described, which is the x and y of top-left corner, followed by width and height of the rectangle. We will place a filled in rectangle at this location. We then specify further options for the rectangle before drawing it, such as setting the opacity to 1.0, the colour to black and anti-aliasing turned off. We output the modified frame with this rectangle inserted, where I will mutate videoFrame so that there is minimal editing required for your code. You would then use videoFrame to detect the next shape.

How to identify boundaries of a binary image to crop in matlab?

How to identify boundaries of a binary image to crop in matlab?
ie. the input binary image has no noises. only has one black object in white background.
You can use the edge command in MATLAB.
E = edge(I);
I would be an input grayscale or binary image. This will return a binary image with only the edges.
This can provide further assistance:
http://www.mathworks.com/help/images/ref/edge.html
If your image is just black-and-white and has a single object, you can likely make use of the Flood fill algorithm, for which Matlab has built-in support!
Try the imfill function (ref).
This should give you the extents of the object, which would allow you to crop at will.
You can also invert the image, then do regionprops to extract all of the properties for separate objects. You need to invert the image as regionprops assumes that the objects are white while the background is black. A good thing about this approach is that it generalizes for multiple objects and you only need about a few lines of code to do it.
As an example, let's artificially create a circle in the centre of an image that is black on a white background as you have suggested. Let's assume this is also a binary image.
im = true(200, 200);
[X,Y] = meshgrid(1:200, 1:200);
ind = (X-100).^2 + (Y-100).^2 <= 1000;
im(ind) = false;
imshow(im);
This is what your circle will look like:
Now let's go ahead and invert this so that it's a white circle on black background:
imInvert = ~im;
imshow(imInvert);
This is what your inverted circle will look like:
Now, invoke regionprops to find properties of all of the objects in our image. In this case, there should only be one.
s = regionProps(imInvert, 'BoundingBox');
As such, s contains a structure that is 1 element long, and has a single field called BoundingBox. This field is a 4 element array that is structured in the following way:
[x y w h]
x denotes the column/vertical co-ordinate while y denotes the row/horizontal co-ordinate of the top-left corner of the bounding box. w,h are the width and height of the rectangle. Our output of the above code is:
s =
BoundingBox: [68.5000 68.5000 63 63]
This means that the top-left corner of our bounding box is located at (x,y) = (68.5,68.5), and has a width and height of 63 each. Therefore, the span of our bounding box goes from rows (68.5,131.5) and columns (68.5,131.5). To make sure that we have the right bounding box, you can draw a rectangle around our shape by using the rectangle command.
imshow(im);
rectangle('Position', s.BoundingBox);
This is what your image will look like with a rectangle drawn around the object. As you can see, the bounding box given from regionprops is the minimum spanning bounding box required to fully encapsulate the object.
If you wish to crop the object, you can do the following:
imCrop = imcrop(imInvert, s.BoundingBox);
This should give you the cropped image that is defined by the bounding box that we talked about earlier.
Hope this is what you're looking for. Good luck!

Filling some region with colour, and the rest of the image as black

I have drawn some polygon on an image after using imshow and hold on, and filled it with white as follows:
fill(x(k),y(k),[1 1 1])
How can I make the rest of the image black while keeping the polygon white? In other words, how can I make a binary image, where the polygon is white, and the rest of the image is black? Provided that the polygon is a bit complex.
Thanks.
Use roipoly:
BW = roipoly( I, x(k), y(k) );
Where I is your input image (you only need it to get the desired output size of the binary maxk BW). y and x are the corners of your polygon.

How can I create a rectangle with an outlined border?

I want to draw a rectangle to outline an area of an image that I've plotted in one axes of a figure. I have multiple axes in this figure, so I am using the rectangle() function. What I want is to draw a white rectangle a thin black border just inside and just outside the rectangle. The part of the image inside the rectangle should be visible, so all 'facecolor' should be 'none'. I have tried drawing 3 rectangles, two black ones with thin linewidths and one thicker white one, but the problem is that 'Position' is defined in axes units and 'LineWidth' is defined in point units, so that the scaling doesn't work too well, especially when the figure is resized.
FYI, the outline is so that the white rectangle is more visible against a light background. The images plotted vary widely, so a single color won't be universally visible for my data.
Any suggestions on how I can do this?
How about just using different line widths for black and white rectangle?
imshow('cameraman.tif')
rectangle('position',[80 30 100 100],'edgecolor','k','LineWidth',4)
rectangle('position',[80 30 100 100],'edgecolor','w','LineWidth',1)
Hmm, the corners look much better on MATLAB figure than as PNG file.
Better with getframe:
I like #Yuks solution. But there is another possibility that you can consider:
You could also calculate the mean value of the pixels inside the rectangle, and set the box color to the inverse. In this way, you will always have a good contrast.
Here is the code:
function PlotRect(im,x,y,w,h)
m = double(im( round(y): round(y+h) , round(x): round(x+w),:));
if (mean(m(:)) < 255/2)
col = [1 1 1];
else
col = [0 0 0];
end
rectangle('Position',[x y w h],'EdgeColor', col);
end
And the test:
function Inverse()
im = imresize( uint8(0:5:255), [250, 400]) ;
figure;imshow(im); hold on;
PlotRect(im,5,8,50,75);
PlotRect(im,100,30,25,42);
PlotRect(im,200,10,40,40);
PlotRect(im,300,10,40,40);
end
Yuk's solution works quite well for adding a rectangle to a normal MATLAB plot, too. The 'position' values are not interpretet as pixels but are adjusted to the plot values (see code example below):
figure;
plot(0:10,0:10); grid on;
hold on;
rectangle('position',[1 1 8.5 8.5],'LineWidth',2);
hold off;
This code results in the following plot:

How to visualize a 3d scene using surf

I have an image loaded from disk as a texture, and a same-sized matrix d which has the corresponding depths.
How can I use surf to show me the image as a 3d-model? Simply taking
surf(depthMatrix, img);
doesn't give a nice result since
the camera looks not from the x-y plane in z-direction
It looks fairly black
It doesn't look that smooth although my depth matrix is actually smoothed out when I show it using imshow(depthMatrix, []);
You can use texture mapping to display your image on your surface like so:
surf(depthMatrix,img,... %# depthMatrix is z data, img is an image
'FaceColor','texturemap',... %# Use texture mapping
'EdgeColor','none'); %# Turn off edge coloring
And to address your 3 points:
You can adjust your camera angle with the mouse by pressing the button on the figure, which turns on interactive 3-D rotation. You can also turn interactive rotation on using the function ROTATE3D, or you can change the camera view without the mouse using the function VIEW.
Your plot was looking black because edges are drawn as black lines by default, and there were probably a lot of them.
You can adjust the axis scaling and limits to make your surface appear smoother. For example, axis equal will make data units the same for all 3 axes, so your z axis (which ranges from 0 to 25) will be flattened significantly since your other two axes span ranges in the hundreds. Alternatively, in your call to SURF you can specify x and y data to use for the values on those axes, which can ultimately help you to better adjust the relative scaling between those axes and the z axis.