How to Crop Multiple Objects in an Image [MATLAB] - matlab

I'm freshman to MATLAB & Developing "Rice Quality Identification" Application using MATLAB & NEURAL NETWORK .For my Guidance I'm preferring this Research Paper
This Application Comprises with 5 Phases
Image Acquisition
Image Pre-processing
Image Segmentation and Identifying Region of Interest
Feature Extraction
Training and Testing
I'm now in 3rd Phase , Already developed initial steps for this application
Step 1: Browse Image from Computer and Show it
% Get the orginal image & show , Figure 1
[fileName, pathName] = uigetfile('*.jpg;*.tif;*.png;*.gif','Select the Picture file');
I = fullfile(pathName, fileName);
I = imread(I);
imshow(I)
Step 2: Background subtraction
% selected rice image Background subtraction , Figure 2
% Use Morphological Opening to Estimate the Background
background = imopen(I,strel('disk',7));
I2 = I - background;
figure, imshow(I2);
Step 3:
% get the Black and white Image , Figure 3
% output image BW replaces all pixels in the input image with luminance greater than 0.17 level
BW = im2bw(I2,0.17);
figure, imshow(BW)
Step 4:
% Remove small objects fewer than 30 pixels from binary image
pure = bwareaopen(BW,30);
figure, imshow(pure)
Step 5: Labeling
% Label Black and white & Image bounding box around each object
L=bwlabel(pure,8);
bb=regionprops(L,'BoundingBox');
I'm Sticking at Step 6 since 2 days. Step 6 is crop multiple objects from original image using Labeled Binary Image
which is exactly output should get like below image ,
if I can get this I can easily calculate Morphological Features and Color features for each object in that original image , to use for phase 4 .
Morphological Features
1.Area for each Object
2.scale of X, Y axis for each object in above picture
3.using X, Y axis I can Calculate Aspect Ratio
Color features
1. Red Mean
2. Green Mean
3. Blue Mean
Can you please explain the way to crop multiple objects from original image using Labeled Binary Image which is Step 6.

If I am interpreting Step #6 right, I believe what it's saying is that they want you to segment out the final objects after Step #5 using the binary map that you have produced. Given your comments, you also want to extract the bounding boxes delineated in Step #5 as well. If that's the case, then all you have to do is use the RegionProps structure defined in bb that will help us do this for you. As a bit of review for you, the BoundingBox field of a RegionProps structure for each object extracted from the image returns an array of 4 numbers like so:
[x y w h]
x denotes the column / horizontal co-ordinate, y denotes the row / vertical co-ordinate, and w,h denote the width and height of the bounding box.
All you need to do is create a binary map, and cycle through each bounding box to delineate where we need to cut out of the image. When you're done, use this binary map to extract out your pixels. In other words:
%//Initialize map to zero
bMap = false(size(pure));
%//Go through each bounding box
for i = 1 : numel(bb)
%//Get the i'th bounding box
bbox = bb(i).BoundingBox;
%//Set this entire rectangle to true
%//Make sure we cast off any decimal
%//co-ordinates as the pixel locations
%//are integer
bbox = floor(bbox);
bMap(bbox(2):bbox(4), bbox(1):bbox(3)) = true;
end
%//Now extract our regions
out = zeros(size(I));
out = cast(out, class(I)); %//Ensures compatible types
%//Extract cropped out regions for each channel
for i = 1 : size(out,3)
chanOut = out(:,:,i);
chanIm = I(:,:,i);
chanOut(bMap) = chanIm(bMap);
out(:,:,i) = chanOut;
end
This creates an output image stored in out, and copies only those pixels that are true from each channel over, based on each bounding box given in Step #5.
I believe this is what Step #6 is talking about. Let me know if I have interpreted this properly.

Related

Superimposing Multiple Images + Adding Colormap

I'm an undergrad student working in a cell biology lab with a basic background in matlab. I'm working on a project of tracking cell trajectory (time lapse) on a petri dish. Below are two example images that i used the watershed feature to separate from the background. The original pictures had neon green cells, now this is all in black and white/
Let's say i have 20 pictures like this, how might I superimpose one on top of another so they all of equal transparency?
Then, how can i add a colormap that represents time? (The bottom most picture is one end of the colormap and the most recent picture is the opposite end) <- this is extremely challenging as it often things the background is black and not NaN
The Basic Idea
Probably the easiest way to do this, is to take the binary image for each layer, and multiply the image by the time at which it was acquired (or it's index in time). Then you can concatenate all images along the third dimension (using cat). You can compute the maximum value along the third dimension using max. This will make the newer time points appear to be "on top" of the older time points. You can then display the resulting flattened matrix using imagesc and it will automatically map to the colormap for the current figure. Typically we would refer to this as a maximum intensity projection.
Creating Some Data
First since you've only provided two images, I'm going to create some shifted versions of the first image you've provided for the demonstration.
% Create some pseudo-data in a cell array that represents the image over time
im = imread('http://i.imgur.com/xTurvfO.jpg');
im = im(:,:,1);
ims = cell(1, 5);
% Create some shifted versions of im1
shifts = round(linspace(0,1000,5));
for k = 1:numel(shifts)
ims{k} = circshift(im > 100, shifts([k k]));
end
Implementing the Method
Now for the application of the method I discussed
% For each image, multiply the binary mask by the time
for k = 1:numel(ims)
ims{k} = ims{k} * k;
end
% Concatenate all images along the third dimension
IMS = cat(3, ims{:});
% Flatten by taking the maximum value along the third dimension
MIP = max(IMS, [], 3);
% Display the resulting flattened image using imagesc
imagesc(MIP);
% Create a custom colormap with black at the end to create our black background
colormap(cat(1, [0 0 0], parula))
The Result
I have used imfuse to create composite images, which is similar to combining multiple channels on a fluorescent microscope. The Mathworks documentation is http://www.mathworks.com/help/images/ref/imfuse.html.
The tricky part is choosing the vector for color channels. For example, [2,1,2] means choosing B(lue) for image 1, R(ed) and G(reen) for image 2. [2,1,2] is the scheme recommended for colorblind people and gives figure on the left of this image. Using [1,0,2] for red/blue gives the the figure on the right.
fig1 = imread([basepath filesep 'fig.jpg']); %white --> black
fig2 = imread([basepath filesep 'fig2.jpg']);
fig_overlay = imfuse(fig1, fig2,'falsecolor','Scaling','joint', 'ColorChannels', [1,0,2]);
imshow(fig_overlay)

How to crop and scale an image in relation to another?

I have two images: a manual segmentation (red line) and automated segmentation (blue line).
What I want to do is
Overlap them so that the points in the first correspond to the points in the second.
Crop the image (automated segmentation) for the points to have the same dimensions and same scale, so that I can validate the segmentation by comparing the two contours.
While I tried a similar solution from MATHWORKS, registering-an-image-using-normalized-cross-correlation, using the code below, but I got an error.
What am I doing wrong? Why is xbegin and offset negative?
% Algorithm for image validation
% Open the two images which will be compared
name2=input('Image name ( automated segmentation) ','s');
img_automated=imread(name2,'png');
figure (1), imshow(img_automated), title('Image automated')
name=input('Image name ( manual segmentation) ','s');
img_manual=imread(name,'png');
img_manual_gray=rgb2gray(img_manual);
figure (2), imshow (img_manual),title('Image manual')
img_automated_gray=rgb2gray(img_automated);
%img_double=im2double(img_automated_gray);
figure (3), imshow (img_automated_gray), title (' Image converted to double ');
imcontrast
%uiwait(img_automated_gray)
img_automated_eq=adapthisteq(img_automated_gray);
figure (5), imshow (img_automated_eq), title (' Image after histogram equalization ');
img_automated_gray=rgb2gray(img_automated);
figure (6), imshowpair(img_manual,img_automated_eq)
title('Images overlap')
%Step 2: Choose Subregions of Each Image
%It is important to choose regions that are similar.The image sub_automated
%will be the template, and must be smaller than the image sub_manual.
% interactively
[sub_manual,rect_manual] = imcrop(img_manual); % choose the pepper below the onion
[sub_automated,rect_automated] = imcrop(img_automated_gray); % choose the whole onion
% display sub images
figure(8), imshow(sub_automated)
figure(9), imshow(sub_automated)
%Step 3: Do Normalized Cross-Correlation and Find Coordinates of Peak
%Calculate the normalized cross-correlation and display it as a surface plot.
% The peak of the cross-correlation matrix occurs where the sub_images are
% best correlated. normxcorr2 only works on grayscale images, so we pass it
% the red plane of each sub image.
c = normxcorr2(sub_automated(:,:,1),sub_manual(:,:,1));
figure (10), surf(c), shading flat
%Step 4: Find the Total Offset Between the Images
%The total offset or translation between images depends on the location
%of the peak in the cross-correlation matrix, and on the size and position
%of the sub images.
% offset found by correlation
[max_c, imax] = max(abs(c(:)));
[ypeak, xpeak] = ind2sub(size(c),imax(1));
corr_offset = [(xpeak-size(sub_automated,2))
(ypeak-size(sub_automated,1))];
% relative offset of position of subimages
rect_offset = [(rect_manual(1)-rect_automated(1))
(rect_manual(2)-rect_automated(2))];
% total offset
offset = corr_offset + rect_offset;
xoffset = offset(1);
yoffset = offset(2);
%Step 5: See if the Onion Image was Extracted from the Peppers Image
%Figure out where onion falls inside of peppers.
xbegin = round(xoffset+1);
xend = round(xoffset+ size(img_automated_gray,2));
ybegin = round(yoffset+1);
yend = round(yoffset+size(img_automated_gray,1));
% extract region from peppers and compare to onion
extracted_automated =img_manual(ybegin:yend,xbegin:xend,:);
if isequal(img_automated_gray,extracted_automated)
disp('extracted_automated.png was extracted from img_automated.png')
end
%Step 6: Pad the Onion Image to the Size of the Peppers Image
%Pad the automated image to overlay on manual, using the offset determined above.
recovered_automated = uint8(zeros(size(img_manual)));
recovered_onion(ybegin:yend,xbegin:xend,:) = img_automated_gray;
figure(11), imshow(recovered_automated)
figure (12), imshowpair(img_manual(:,:,1),recovered_automated,'blend')
This answer may not be complete, but with the amount of information you've already included, I have this to share:
It would be interesting to know what kind of distortion the two images you are trying to register exhibit. I see that you've used 'similarity' as the transformation type. There are other transformation types that may be more suitable to your images, and getting this wrong will not give you a good result in spite of you selecting enough, and accurately located control points.
The MATLAB documentation lists out other ways to register two images, and depending on the type of features in your images, one of the other options: namely Intensity based (using imregister) or feature based (using a set of functions from the Computer Vision System Toolbox) may be more accurate.
To crop the images to be of the same size, you could display them using imshowpair as you already are, and then use imcrop to the size you intend. imshowpair displays all the pixels of the registered pair, so that your final result is always a sub-component of what is displayed.

Matlab - How to manually trace a boundary of an object

I am trying to find and extract the boundary of a binary image in matlab, without using something like bwboundaries.
Is there a more manual way to do this, using loops maybe and changing the colour of the boundary pixels.
Any help would be appreciated.
Since it is binary so you can use two loop pairs.
-first ensure that image is binary.(just in case it is greyscale threshold it)
-use the first loop pair for height and one for width and trace any change i.e if a pixel is black and the next pixel is white draw that point onto a new mat.(i.e mark that point as 255 or of any colour you desire)
-Do the same for width and height and store it into another mat.
-Then add both the mats and average out the result.
This is the manual way and it may not be efficient.But it helps you modify the process to get you the exact edges.
(Source:I had used this technique for detecting perspective transformed rectangles containing bar code in java since canny edge used to give out too many edges due to bar code lines)
I don't understand what you mean by manual way. Is it mean pixel by pixel or anything else? Anyway try this example and fully explain your question that what you really want.
d1 = double(imread('cameraman.TIF'))./255; %# Load the image, scale from 0 to 1
subplot(2,2,1); imshow(d1); title('d1'); %# Plot the original image
d = edge(d1,'canny',.6); %# Perform Canny edge detection
subplot(2,2,2); imshow(d); title('d'); %# Plot the edges
ds = bwareaopen(d,40); %# Remove small edge objects
subplot(2,2,3); imshow(ds); title('ds'); %# Plot the remaining edges
iout = d1;
BW = ds;
iout(:,:,1) = iout; %# Initialize red color plane
iout(:,:,2) = iout(:,:,1); %# Initialize green color plane
iout(:,:,3) = iout(:,:,1); %# Initialize blue color plane
iout(:,:,2) = min(iout(:,:,2) + BW, 1.0); %# Add edges to green color plane
iout(:,:,3) = min(iout(:,:,3) + BW, 1.0); %# Add edges to blue color plane
subplot(2,2,4); imshow(iout); title('iout'); %# Plot the resulting image
you can also track boundary by using Blob method but it depend on your requirements.

Detection of homogeneous area in term of connectivity in image

I am looking for some measurements to do to distinct between these two binary images (texte and noise).
Hough transform of the frequency domain don't tell me much (either in skeleton or in the original shape), as can be seen below !
in the spatial domain, I have try to measure, if a given pixel participate to line or curve, or participate to a random shape, and then measures the percentage of all pixels participating and not participating to normal shape (lines and curves) to distinguish between these images, but I didn't succeed, in implementation.
what do you think ?
I use matlab for test.
Thanks in advance
Looking at the skeleton images, one could notice how the noise image has lots of branches in it, as compared to the text image and this looks like one of the features that could be exploited. The experiment as code shown below soughts to verify the same, using the OP's images -
Experiment Code
%%// Experiment to research what features what might help us
%%// differentiate betwen noise and text images
%%// Read in the given images
img1 = imread('noise.png');
img2 = imread('text.png');
%%// Since the given images had the features as black and rest as white,
%%// we must invert them
img1 = ~im2bw(img1);
img2 = ~im2bw(img2);
%%// Remove the smaller blobs from both of the images which basically
%%// denote the actual noise in them
img1 = rmnoise(img1,60);
img2 = rmnoise(img2,60);
%// Get the skeleton images
img1 = bwmorph(img1,'skel',Inf);
img2 = bwmorph(img2,'skel',Inf);
%%// Find blobs branhpoints for each blob in both images
[L1, num1] = bwlabel(img1);
[L2, num2] = bwlabel(img2);
for k = 1:num1
img1_bpts_count(k) = nnz(bwmorph(L1==k,'branchpoints'));
end
for k = 1:num2
img2_bpts_count(k) = nnz(bwmorph(L2==k,'branchpoints'));
end
%%// Get the standard deviation of branch points count
img1_branchpts_std = std(img1_bpts_count)
img2_branchpts_std = std(img2_bpts_count)
Note: Above code uses a function - rmnoise shown below that is built based on the problem discussed at this link :
function NewImg = rmnoise(Img,threshold)
[L,num] = bwlabel( Img );
counts = sum(bsxfun(#eq,L(:),1:num));
B1 = bsxfun(#eq,L,permute(find(counts>threshold),[1 3 2]));
NewImg = sum(B1,3)>0;
return;
Output
img1_branchpts_std =
73.6230
img2_branchpts_std =
12.8417
One can see the big difference between the standard deviations of the two input images, suggesting this feature could be used.
Runs on some other samples
To make our theory a bit more concrete, let's use a pure text image and gradually add noise and see if the standard deviation of branch-points, naming it as check_value suggest anything on them.
(I) Pure text image
check_value = 1.7461
(II) Some added noise image
check_value = 30.1453
(III) Some more added noise image
check_value = 54.6446
Conclusion: As can be seen, this parameter provides quite a good indicator to decide on the nature of images.
Finalized Code
A script could be written to test for whether another input image would be a text or noise one, like this -
%%// Parameters
%%// 1. Decide this based on the typical image size and count of pixels
%%// in the biggest noise blob
rmnoise_threshold = 60;
%%// 2. Decide this based on the typical image size and how convoluted the
%%// noisy images are
branchpts_count_threshold = 50;
%%// Actual processing
%%// We are assuming input images as binary images with features as true
%%// and false in rest of the region
img1 = im2bw(imread(FILE));
img1 = rmnoise(img1,rmnoise_threshold);
img1 = bwmorph(img1,'skel',Inf);
[L1, num1] = bwlabel(img1);
for k = 1:num1
img1_bpts_count(k) = nnz(bwmorph(L1==k,'branchpoints'));
end
if std(img1_bpts_count) > branchpts_count_threshold
disp('This is a noise image');
else
disp('This is a text image');
end
And now what you suggest if we try to use the original shape instead of the skeleton, (to avoid the loss of information).
I try to measure for a given pixel, the elongation of the strokes (instead of straight branches) that past throughout that pixel, by counting the number of transitions from white to black in a clockwise.
I am thinking to use a circle with a radius, and for the origin the pixel in consideration, and store the pixels locating at the edge of the circle in an ordered list (clockwise) and then compute the number of transitions (black to white) from this list.
by increasing the radius of the circle we could trace the shape of elongated stokes and know his orientation.
this is a schema illustrating this.
the pixels that have a number of transitions equal to 0 or bigger than 2 (red ones) have to be classified as noise, and those that have 2 or 1 transition classified as normal.
What do you think of this approach !

MATLAB Image Processing - Find Edge and Area of Image

As a preface: this is my first question - I've tried my best to make it as clear as possible, but I apologise if it doesn't meet the required standards.
As part of a summer project, I am taking time-lapse images of an internal melt figure growing inside a crystal of ice. For each of these images I would like to measure the perimeter of, and area enclosed by the figure formed. Linked below is an example of one of my images:
The method that I'm trying to use is the following:
Load image, crop, and convert to grayscale
Process to reduce noise
Find edge/perimeter
Attempt to join edges
Fill perimeter with white
Measure Area and Perimeter using regionprops
This is the code that I am using:
clear; close all;
% load image and convert to grayscale
tyrgb = imread('TyndallTest.jpg');
ty = rgb2gray(tyrgb);
figure; imshow(ty)
% apply a weiner filter to remove noise.
% N is a measure of the window size for detecting coherent features
N=20;
tywf = wiener2(ty,[N,N]);
tywf = tywf(N:end-N,N:end-N);
% rescale the image adaptively to enhance contrast without enhancing noise
tywfb = adapthisteq(tywf);
% apply a canny edge detection
tyedb = edge(tywfb,'canny');
%join edges
diskEnt1 = strel('disk',8); % radius of 4
tyjoin1 = imclose(tyedb,diskEnt1);
figure; imshow(tyjoin1)
It is at this stage that I am struggling. The edges do not quite join, no matter how much I play around with the morphological structuring element. Perhaps there is a better way to complete the edges? Linked is an example of the figure this code outputs:
The reason that I am trying to join the edges is so that I can fill the perimeter with white pixels and then use regionprops to output the area. I have tried using the imfill command, but cannot seem to fill the outline as there are a large number of dark regions to be filled within the perimeter.
Is there a better way to get the area of one of these melt figures that is more appropriate in this case?
As background research: I can make this method work for a simple image consisting of a black circle on a white background using the below code. However I don't know how edit it to handle more complex images with edges that are less well defined.
clear all
close all
clc
%% Read in RGB image from directory
RGB1 = imread('1.jpg') ;
%% Convert RPG image to grayscale image
I1 = rgb2gray(RGB1) ;
%% Transform Image
%CROP
IC1 = imcrop(I1,[74 43 278 285]);
%BINARY IMAGE
BW1 = im2bw(IC1); %Convert to binary image so the boundary can be traced
%FIND PERIMETER
BWP1 = bwperim(BW1);
%Traces perimeters of objects & colours them white (1).
%Sets all other pixels to black (0)
%Doing the same job as an edge detection algorithm?
%FILL PERIMETER WITH WHITE IN ORDER TO MEASURE AREA AND PERIMETER
BWF1 = imfill(BWP1); %This opens figure and allows you to select the areas to fill with white.
%MEASURE PERIMETER
D1 = regionprops(BWF1, 'area', 'perimeter');
%Returns an array containing the properties area and perimeter.
%D1(1) returns the perimeter of the box and an area value identical to that
%perimeter? The box must be bounded by a perimeter.
%D1(2) returns the perimeter and area of the section filled in BWF1
%% Display Area and Perimeter data
D1(2)
I think you might have room to improve the effect of edge detection in addition to the morphological transformations, for instance the following resulted in what appeared to me a relatively satisfactory perimeter.
tyedb = edge(tywfb,'sobel',0.012);
%join edges
diskEnt1 = strel('disk',7); % radius of 4
tyjoin1 = imclose(tyedb,diskEnt1);
In addition I used bwfill interactively to fill in most of the interior. It should be possible to fill the interior programatically but I did not pursue this.
% interactively fill internal regions
[ny nx] = size(tyjoin1);
figure; imshow(tyjoin1)
tyjoin2=tyjoin1;
titl = sprintf('click on a region to fill\nclick outside window to stop...')
while 1
pts=ginput(1)
tyjoin2 = bwfill(tyjoin2,pts(1,1),pts(1,2),8);
imshow(tyjoin2)
title(titl)
if (pts(1,1)<1 | pts(1,1)>nx | pts(1,2)<1 | pts(1,2)>ny), break, end
end
This was the result I obtained
The "fractal" properties of the perimeter may be of importance to you however. Perhaps you want to retain the folds in your shape.
You might want to consider Active Contours. This will give you a continous boundary of the object rather than patchy edges.
Below are links to
A book:
http://www.amazon.co.uk/Active-Contours-Application-Techniques-Statistics/dp/1447115570/ref=sr_1_fkmr2_1?ie=UTF8&qid=1377248739&sr=8-1-fkmr2&keywords=Active+shape+models+Andrew+Blake%2C+Michael+Isard
A demo:
http://users.ecs.soton.ac.uk/msn/book/new_demo/Snakes/
and some Matlab code on the File Exchange:
http://www.mathworks.co.uk/matlabcentral/fileexchange/28149-snake-active-contour
and a link to a description on how to implement it: http://www.cb.uu.se/~cris/blog/index.php/archives/217
Using the implementation on the File Exchange, you can get something like this:
%% Load the image
% You could use the segmented image obtained previously
% and then apply the snake on that (although I use the original image).
% This will probably make the snake work better and the edges
% in your image is not that well defined.
% Make sure the original and the segmented image
% have the same size. They don't at the moment
I = imread('33kew0g.jpg');
% Convert the image to double data type
I = im2double(I);
% Show the image and select some points with the mouse (at least 4)
% figure, imshow(I); [y,x] = getpts;
% I have pre-selected the coordinates already
x = [ 525.8445 473.3837 413.4284 318.9989 212.5783 140.6320 62.6902 32.7125 55.1957 98.6633 164.6141 217.0749 317.5000 428.4172 494.3680 527.3434 561.8177 545.3300];
y = [ 435.9251 510.8691 570.8244 561.8311 570.8244 554.3367 476.3949 390.9586 311.5179 190.1085 113.6655 91.1823 98.6767 106.1711 142.1443 218.5872 296.5291 375.9698];
% Make an array with the selected coordinates
P=[x(:) y(:)];
%% Start Snake Process
% You probably have to fiddle with the parameters
% a bit more that I have
Options=struct;
Options.Verbose=true;
Options.Iterations=1000;
Options.Delta = 0.02;
Options.Alpha = 0.5;
Options.Beta = 0.2;
figure(1);
[O,J]=Snake2D(I,P,Options);
If the end result is an area/diameter estimate, then why not try to find maximal and minimal shapes that fit in the outline and then use the shapes' area to estimate the total area. For instance, compute a minimal circle around the edge set then a maximal circle inside the edges. Then you could use these to estimate diameter and area of the actual shape.
The advantage is that your bounding shapes can be fit in a way that minimizes error (unbounded edges) while optimizing size either up or down for the inner and outer shape, respectively.