MATLAB - Colour an Area around a bounding box with Black - matlab

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.

Related

Matlab - Plot areas of interest onto an image

I'm working on an application and I'm at a stage where I'm comparing two images to see if they have any resemblance, with one another. I have managed to do this, an example you can find here.
From the image, it will display white spaces for pixels that are near the same for both images given. What I want to do next is get the coordinates of the white spaces and plot them onto the original image to highlight the strongest features about the coin. However, I'm unsure how to do this as I'm rather new to Matlab.
firstImage = sprintf('M:/Project/MatLab/Coin Image Processing/Image Processing/test-1.jpg');
secondImage = sprintf('M:/Project/MatLab/Coin Image Processing/Image Processing/test-99.jpg');
a = rgb2gray(imread(firstImage));
b = rgb2gray(imread(secondImage));
axes(handles.axes4);
imshow(a==b);
title('Scanning For Strongest Features', 'fontweight', 'bold')
From using disp(a==b), I can see which points of both pictures are the same. So my guess is that I need to do something where I get the coordinates of all the zeroes and then plot them onto the original image in a way that highlights it, similar to using a yellow highlighter, but I just don't know how.
If I got your question, I think you should use find to collect all the coordinates for which a==b:
[X, Y] = find(a == b); % Find coordinates for which the two images are equal
imshow(a), axis image; % Show first image
hold on
plot(Y, X, 'y.'); % Overlay those coordinates
hold off
You can use a transparent overlay to plot the region of interest.
figure
imshow(originalImage); % plot the original image
hold on
% generate a red overlay
overlay(:, :, 1) = ones(size(a)); % red channel
overlay(:, :, 2) = zeros(size(a)); % green channel
overlay(:, :, 3) = zeros(size(a)); % blue channel
h = imshow(overlay); % plot the overlay
set(h, 'AlphaData', (a == b) * 0.5); % set the transparency to 50% if a == b and 0% otherwise

Changing Bounding Box Dimensions

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

Write number over an image

Using Matlab, I want to write a number in a specific position inside an image shown by imshow. At the moment, I have:
myimage = imread('Route of my image');
myimage = im2double(myimage);
imshow(myimage)
MyBox = uicontrol('style','text');
set(MyBox,'String',mynumber);
set(MyBox,'Position',[25,25,15,15]);
My problem is that positions given in 'set' are relatives to all window that manage the figure window so it also includes the gray borders. How can I write them relative to only the figure (without the gray borders)?
You could use text instead?
imshow(image);
text(x,y,'your text')
You can follow the steps described here to remove the grey border from the figure so as to obtain right coordinates when placing the text. Basically fetch the dimensions of both the figure and axes containing the image and make the figure fit exactly the axes.
Beware that when specifying the position of a uicontrol object the 0 position is at the BOTTOM left, whereas the pixel coordinates inside an image start from the TOP left. Therefore you will need to get the dimensions of the image and subtract the actual y-coordinate from the number of rows forming the image, i.e. the 1st dimension.
Here is an example:
clear
clc
close all
myimage = imread('coins.png');
myimage = im2double(myimage);
imshow(myimage);
[r,c,~] = size(myimage);
%// Copied/pasted from http://www.mathworks.com/matlabcentral/answers/100366-how-can-i-remove-the-grey-borders-from-the-imshow-plot-in-matlab-7-4-r2007a
set(gca,'units','pixels'); %// set the axes units to pixels
x = get(gca,'position'); %// get the position of the axes
set(gcf,'units','pixels'); %// set the figure units to pixels
y = get(gcf,'position'); %// get the figure position
set(gcf,'position',[y(1) y(2) x(3) x(4)]);% set the position of the figure to the length and width of the axes
set(gca,'units','normalized','position',[0 0 1 1]) % set the axes units to pixels
%// Example
hold on
mynumber = 20;
%// Set up position/size of the box
Box_x = 25;
Box_y = 25;
Box_size = [15 15];
%// Beware! For y-position you want to start at the top left, i.e. r -
%// Box_y
BoxPos = [Box_x r-Box_y Box_size(1) Box_size(2)];
MyBox = uicontrol('style','text','Position',BoxPos);
set(MyBox,'String',mynumber);
and output:
yay!
The answers above add text on the figure window. If you want to modify your image itself and change the pixels so that you get the text where ever you display the image you can use insertText function available in Computer Vision toolbox.
myimage = imread('Route of my image');
myimage = im2double(myimage);
myimage = insertText(myimage, [25 25], 'your text');
imshow(myimage)

Plot imellipse over image in MATLAB

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

matlab: how to plot multidimensional array

Let's say I have 9 MxN black and white images that are in some way related to one another (i.e. time lapse of some event). What is a way that I can display all of these images on one surface plot?
Assume the MxN matrices only contain 0's and 1's. Assume the images simply contain white lines on a black background (i.e. pixel value == 1 if that pixel is part of a line, 0 otherwise). Assume images are ordered in such a way as to suggest movement progression of line(s) in subsequent images. I want to be able to see a "side-view" (or volumetric representation) of these images which will show the surface that a particular line "carves out" in its movement across the images.
Coding is done in MATLAB. I have looked at plot (but it only does 2D plots) and surf, which does 3D plots but doesn't work for my MxNx9 matrix of images. I have also tried to experiment with contourslice, but not sure what parameters to pass it.
Thanks!
Mariya
Are these images black and white with simple features on a "blank" field, or greyscale, with more dense information?
I can see a couple of approaches.
You can use movie() to display a sequence of images as an animation.
For a static view of sparse, simple data, you could plot each image as a separate layer in a single figure, giving each layer a different color for the foreground, and using AlphaData to make the background transparent so all the steps in the sequenc show through. The gradient of colors corresponds to position in the image sequence. Here's an example.
function plotImageSequence
% Made-up test data
nLayers = 9;
x = zeros(100,100,nLayers);
for i = 1:nLayers
x(20+(3*i),:,i) = 1;
end
% Plot each image as a "layer", indicated by color
figure;
hold on;
for i = 1:nLayers
layerData = x(:,:,i);
alphaMask = layerData == 1;
layerData(logical(layerData)) = i; % So each layer gets its own color
image('CData',layerData,...
'AlphaData',alphaMask,...
'CDataMapping','scaled');
end
hold off
Directly showing the path of movement a "line" carves out is hard with raster data, because Matlab won't know which "moved" pixels in two subsequent images are associated with each other. Don't suppose you have underlying vector data for the geometric features in the images? Plot3() might allow you to show their movement, with time as the z axis. Or you could use the regular plot() and some manual fiddling to plot the paths of all the control points or vertexes in the geometric features.
EDIT: Here's a variation that uses patch() to draw each pixel as a little polygon floating in space at the Z level of its index in the image sequence. I think this will look more like the "surface" style plots you are asking for. You could fiddle with the FaceAlpha property to make dense plots more legible.
function plotImageSequencePatch
% Made-up test data
nLayers = 6;
sz = [50 50];
img = zeros(sz(1),sz(2),nLayers);
for i = 1:nLayers
img(20+(3*i),:,i) = 1;
end
% Plot each image as a "layer", indicated by color
% With each "pixel" as a separate patch
figure;
set(gca, 'XLim', [0 sz(1)]);
set(gca, 'YLim', [0 sz(2)]);
hold on;
for i = 1:nLayers
layerData = img(:,:,i);
[x,y] = find(layerData); % X,Y of all pixels
% Reshape in to patch outline
x = x';
y = y';
patch_x = [x; x+1; x+1; x];
patch_y = [y; y; y+1; y+1];
patch_z = repmat(i, size(patch_x));
patch(patch_x, patch_y, patch_z, i);
end
hold off