Segmentation in an image with a single object in MATLAB - matlab

Here is the picture:
My goal is placing this bird in another image. I tried something with MATLAB, first rgb2gray then imhist to get the bird intensity, then I made a mask, but I always ended up with a mask which included the tree and the clouds.

Here is some code you can use for this task:
clear;
close all;
im = imread('~/Downloads/siraly_www.kepfeltoltes.hu_.jpg');
im = rgb2gray(im);
%// Manually crop the image
im = double(im(620:1619, 2150:3279));
%// Find edges
hedge = vision.EdgeDetector('Method', 'Sobel');
edges = step(hedge, im);
%// Dilate to close edges around object
edges = imdilate(edges, [0 1 0; 1 1 1; 0 1 0]);
%// Find boundary of object
bound = bwboundaries(edges);
bound = bound{1}; % Largest boundary is around object
%// Display image and object boundary
figure; imshow(im, []);
hold on;
plot(bound(:,2), bound(:,1), '.');
hold off;
%// Select all object pixels by filling the boundary
bwobject = false(size(im));
bwobject(sub2ind(size(im), bound(:,1), bound(:,2))) = true;
bwobject = imfill(bwobject, 'holes');
imobject = zeros(size(im));
imobject(bwobject) = im(bwobject);
figure; imshow(imobject, []);
The method used here is:
Manual cropping of the image.
Edge detection using the EdgeDetector object.
Morphological operations to retrieve the object pixels only using imdilate, bwboundaries and imfill.
Here are the object boundaries computed and plotted in the code:
And here is the object cropped from the image:

Related

How connect the coordinate and fill the area to create a binary mask?

I need to create a binary mask from a series of coordinates. My current code is shown below but the edges of the resulting image are not smooth. I think it is not precise and I need to make sure I am connecting exact coordinate and connect them together.
Here on the left side, I plotted the points (always 42 points) and on the right side is the output of the code. As you can see the edges are not smooth.
Here is the current code and the output: (coordinates are attached)
im is an image of size 112 x 112, filled with zero everywhere except the X, Y coordinates and inside the region filled with the 255.
function BW = mask_data(X,Y, im)
X = round(X);
Y = round(Y);
%round coordinates
X ( X < 1 ) = 1;
Y ( Y < 1 ) = 1;
BW = im > 255;
for p = 1:length(X)
BW(Y(p),X(p)) = 1;
end
BW = BW * 255;
BW = bwconvhull(BW);
BW = im2uint8(BW);
figure;
imshow(BW);
close all;
end
I believe the union convex hull is still your best bet. If you have images that are actually comprised of a single object then your shown algorithm should work just fine, though you are doing some redundant steps in your shown code. If that is not the case, then you may want to consider finding the convex hull of multiple components through adding the objects option to your bwconvhull call. If you strongly believe that the results are "not precise" then you may want to show an example image in which the algorithm actually fails.
As per the results not being smooth, you should logically not expect smooth boundaries for an image of size 112 x 112 with an object boundary similar to what you have shown. However, I would simply smooth the results if smooth images are preferred:
originalImage = imread('Adrress\to\your\image.png');
% To have the same image size as yours
originalImage = imresize(originalImage, [112 112]);
% Create a binary image
binaryImage = im2bw(originalImage);
% Create a binary convex hull image
UnionCH = bwconvhull(binaryImage);
% Smooth the results (note the change of binary class)
% Second arg (0.7) is the std dev of the Gaussian smoothing kernel
SmoothUnionCH = imgaussfilt(single(UnionCH), 0.7);
figure
subplot(131)
imshow(binaryImage)
title('Binary Image')
subplot(132)
imshow(UnionCH)
title('Binary Convex Hull Image')
subplot(133)
imshow(SmoothUnionCH,[])
title('Smooth Convex Hull Image')
You can adjust the size of the smoothing kernel of course. The results for the code above:

How to calculate radius of ring in MATLAB?

I have a stack of cortical bone images, high resolution and binarized. How do I go about calculating the mean inner and outer radii for each image? Here is an example of the kind of images I need to process:
This could be one approach -
%// Read in image and conert to binary
im = im2bw(imread('http://s9.postimg.org/aew1l7tvz/4_COPY_copy.png'));
figure, imshow(im), title('Original Image')
%// Fill holes giving us the "outer blob"
outer_blob = imfill(im,'holes');
outer_blob = biggest_blob(outer_blob); %// remove noise
figure, imshow(outer_blob), title('Outer Blob')
%// Get the inner filled blob by "removing" the original image from outer blob
inner_blob = outer_blob & ~im;
inner_blob = biggest_blob(inner_blob); %// remove noise
figure, imshow(inner_blob), title('Inner Blob')
%// Find the equivalent/mean inner and outer radii
inner_dia = regionprops(inner_blob,'Equivdiameter');
inner_radius = inner_dia.EquivDiameter/2
outer_dia = regionprops(outer_blob,'Equivdiameter');
outer_radius = outer_dia.EquivDiameter/2
Associated function code -
function out = biggest_blob(BW)
%// Find and labels blobs in the binary image BW
[L, num] = bwlabel(BW, 8);
%// Count of pixels in each blob, basically this should give the area of each blob
counts = sum(bsxfun(#eq,L(:),1:num));
%// Get the label(ind) cooresponding to blob with the maximum area
%// which would be the biggest blob
[~,ind] = max(counts);
%// Get only the logical mask of the biggest blob by comparing all labels
%// to the label(ind) of the biggest blob
out = (L==ind);
return;
Code run and debug images -
inner_radius =
211.4740
outer_radius =
267.8926

Colour Segmentation by l*a*b

I'm using the code on the MatLab website, "Color-Based Segmentation Using the Lab* Color Space":
http://www.mathworks.com/help/images/examples/color-based-segmentation-using-the-l-a-b-color-space.html
So I'm trying to select some areas myself instead of using the "load region_coordinates", using roipoly(fabric), but i get stuck. How do I save coordinates of the polygon I just drew? I'm actually following advice from lennon310 at Solution II, bottom of page:
A few questions about color segmentation with L*a*b*
I'm not sure when to save region_coordinates and do size(region_coordinates,1)
I made the following changes (Step 1):
1) Removed "load region_coordinates"
2) Added "region_coordinates = roipoly(fabric);"
Here's the code:
`
%% Step 1
fabric = imread(file);
figure(1); %Create figure window. "If h is not the handle and is not the Number property value of an existing figure, but is an integer, then figure(h) creates a figure object and assigns its Number property the value h."
imshow(fabric)
title('fabric')
%load regioncoordinates; % 6 marices(?) labelled val(:,:,1-6), 5x2 (row x column)
region_coordinates = roipoly(fabric);
nColors = 6;
sample_regions = false([size(fabric,1) size(fabric,2) nColors]); %Initializing an Image Dimension, 3x3 (:,:,:) to zero? Zeros() for arrays only I guess.
%Size one is column, size two is row?
for count = 1:nColors
sample_regions(:,:,count) = roipoly(fabric,region_coordinates(:,1,count),region_coordinates(:,2,count));
end
figure, imshow(sample_regions(:,:,2)),title('sample region for red');
%%Step 2
% Convert your fabric RGB image into an L*a*b* image using rgb2lab .
lab_fabric = rgb2lab(fabric);
%Calculate the mean a* and b* value for each area that you extracted with roipoly. These values serve as your color markers in a*b* space.
a = lab_fabric(:,:,2);
b = lab_fabric(:,:,3);
color_markers = zeros([nColors, 2]);%... I think this is initializing a 6x2 blank(0) array for colour storage. 6 for colours, 2 for a&b colourspace.
for count = 1:nColors
color_markers(count,1) = mean2(a(sample_regions(:,:,count))); %Label for repmat, Marker for
color_markers(count,2) = mean2(b(sample_regions(:,:,count)));
end
%For example, the average color of the red sample region in a*b* space is
fprintf('[%0.3f,%0.3f] \n',color_markers(2,1),color_markers(2,2));
%% Step 3: Classify Each Pixel Using the Nearest Neighbor Rule
%
color_labels = 0:nColors-1;
% Initialize matrices to be used in the nearest neighbor classification.
a = double(a);
b = double(b);
distance = zeros([size(a), nColors]);
%Perform classification, Elucidean Distance.
for count = 1:nColors
distance(:,:,count) = ( (a - color_markers(count,1)).^2 + (b - color_markers(count,2)).^2 ).^0.5;
end
[~, label] = min(distance,[],3);
label = color_labels(label);
clear distance;
%% Step 4: Display Results of Nearest Neighbor Classification
%
% The label matrix contains a color label for each pixel in the fabric image.
% Use the label matrix to separate objects in the original fabric image by color.
rgb_label = repmat(label,[1 1 3]);
segmented_images = zeros([size(fabric), nColors],'uint8');
for count = 1:nColors
color = fabric;
color(rgb_label ~= color_labels(count)) = 0;
segmented_images(:,:,:,count) = color;
end
%figure, imshow(segmented_images(:,:,:,1)), title('Background of Fabric');
%Looks different somehow.
figure, imshow(segmented_images(:,:,:,2)), title('red objects');
figure, imshow(segmented_images(:,:,:,3)), title('green objects');
figure, imshow(segmented_images(:,:,:,4)), title('purple objects');
figure, imshow(segmented_images(:,:,:,5)), title('magenta objects');
figure, imshow(segmented_images(:,:,:,6)), title('yellow objects');
`
You can retrieve the coordinates of the polygon using output arguments in the call to roipoly. You can then get a binary mask of the polygon, as well as vertices coordinates if you want.
Simple example demonstrating:
clear
clc
close all
A = imread('cameraman.tif');
figure;
imshow(A)
%// The vertices of the polygon are stored in xi and yi;
%// PolyMask is a binary image where pixels == 1 are white.
[polyMask, xi, yi] = roipoly(A);
This looks like this:
And if you wish to see the vertices with the binary mask:
%// display polymask
imshow(polyMask)
hold on
%// Highlight vertices in red
scatter(xi,yi,60,'r')
hold off
Which gives the following:
So to summarize:
1) The polygon's vertices are stored in xi and yi.
2) You can plot the binaryMask of the polygon using imshow(polyMask).
3) If you need the coordinates of the white pixels, you can use something like this:
[row_white,col_white] = find(polyMask == 1);
You're then good to go. Hope that helps!

MATLAB - Colour an Area around a bounding box with Black

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.

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