How to classify objects with different number of holes? - matlab

My object is classifying cells in the given image. Classification is based on the shape and number of the nucleus(holes). Some of the cells have a circular type while others not. Some of has one hole (nucleus), while others have more.
After some clearing and preprocessing, I have classified circular and overlapped cells so far. But there is a cell with two holes(nucleus) which should belong to another class. But I couldn't do it. If I can count the number of holes, I think I can classify also that cell.
im =imread('blood.jpg'); % Reading target image
figure(1),imshow(im), title('Original Image');
imGray = rgb2gray(im); % Converting image RGB to gray-level (2-Dimensional).
gray_thresh = graythresh(imGray);
bw = im2bw(imGray, gray_thresh); figure(2), imshow(bw), title('Binary Image'); % Converting image to binary.
bw = imcomplement(bw); % Taking image's complement.
figure(3), imshow(bw), title('Complement of Image');
%bw=imfill(bw,'holes');
bw = imclearborder(bw);
figure(4), imshow(bw), title('Objects touching image borders removed');
bw = bwareaopen(bw,500); % Remove objects smaller than 500px.
figure(5),imshow(bw); title('Small objects removed');
label = bwlabel(bw);
[B,L] = bwboundaries(bw,'noholes');
stats = regionprops(L,'Area','Centroid');
threshold = 0.70;
figure(6), imshow(bw)
hold on
for k = 1:length(B)
% obtain (X,Y) boundary coordinates corresponding to label 'k'
boundary = B{k};
% compute a simple estimate of the object's perimeter
delta_sq = diff(boundary).^2;
perimeter = sum(sqrt(sum(delta_sq,2)));
% obtain the area calculation corresponding to label 'k'
area = stats(k).Area;
% compute the roundness metric
metric = 4*pi*area/perimeter^2;
if metric > threshold
plot(boundary(:,2),boundary(:,1),'r','LineWidth',2)
%Circular
else
plot(boundary(:,2),boundary(:,1),'g','LineWidth',2)
%Overlapped
end
end
Cell with two nucleus(holes)

Related

Create boundary around the object

I have the input image. I want to create the boundary around the object and marked the boundary pixels as gray i.e. 128 intensity value. I need this type of output image. I traced the boundary of the object:
level = graythresh(im);
BW = im2bw(im,level);
figure; imshow(BW);
[B,L] = bwboundaries(BW,'noholes');
imshow(im);
hold on
for k = 1:length(B)
boundary = B{k};
plot(boundary(:,2), boundary(:,1), 'Color', [0.5 0.5 0.5], 'LineWidth', 5)
end
But it will only plot the boundary over the image. I want to create this boundary around the object of input image. How can I do this? I hope my question is clear.
While I don't know why you wan this, a word of advice: you may not want to do it. You are losing information of the image by doing so. It is possible that for you application knowing the indices of the boundaries is enough, and you do already know them.
However, this is what you would need to do in case of really wanting to do it:
clear;
clc;
im=imread('https://i.stack.imgur.com/r7uQz.jpg');
im=im(31:677,90:1118);
level = graythresh(im);
BW = im2bw(im,level);
[B,L] = bwboundaries(BW,'noholes');
for k = 1:length(B)
boundary = B{k};
%%%%%%%%% Fill the boundary locations with he desired value.
for ii=1:size(boundary,1)
im(boundary(ii,1), boundary(ii,2))=128;
end
end
If you want "fat" lines as in your image, add this after:
im128=im==128;
bigboundary=imdilate(im128,ones(5));
im(bigboundary)=128;
You can binarize the image and detect the contours using OpenCV.
Here is the Python implementation:
img = cv2.imread(r'D:\Image\temp1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret,bw = cv2.threshold(gray,100,255,cv2.THRESH_BINARY)
_,contours,hierarchy = cv2.findContours(bw, cv2.RETR_CCOMP, 1)
for cnt in contours:
c = np.random.randint(0,256,3)
c = (int(c[0]), int(c[1]), int(c[2]))
cv2.drawContours(img,[cnt],0,c,2)
Output image:

Area calculation in MATLAB

I am working on a paper and I need to find out the area of the region having color black from the image that I have attached.
Original image
I have done some processing by using threshold and complimenting the image.Processed image
Now I'm having a problem finding the area of the black colored region. Can someone please help? I'm new to MATLAB.
Here is my code :
img1=imread('C:/Users/Allan/Desktop/unnamed1.jpg');
imshow(img1)
img1=rgb2gray(img1);
imshow(img1)
img2=im2bw(img1,graythresh(img1));
imshow(img2)
img2=~img2;
imshow(img2)
B = bwboundaries(img2);
imshow(img2)
hold on
for k = 1:length(B)
boundary = B{k};
plot(boundary(:,2), boundary(:,1), 'g', 'LineWidth', 0.2)
end
use regionprops or bwarea:
% take the NOT image
bw = ~img2;
% find individual regions
cc = bwconncomp(bw);
% find area for each black region
props = regionprops(cc,{'Area','Centroid'});
regionArea = [props(:).Area];
% find area of total black region
totalArea = bwarea(bw);
% plotting
for ii = find(regionArea > 100)
c = props(ii).Centroid;
text(c(1),c(2),num2str(regionArea(ii)),'Color','b',...
'HorizontalAlignment','center','VerticalAlignment','middle',...
'FontWeight','bold');
end

How to get mean and standard deviation of each channel (RGB) in an image

I am trying to output mean and standard deviation for each channel in the object located in the image. At the moment, my code produce mean and standard RGB as one figure, but instead, I would like to output mean and standard for R, G, B individualy.
Sample data: https://drive.google.com/file/d/0B_M7fjkKw1r3ZnM3N0I1aGkzbjA/edit?usp=sharing
This is my code:
function findspuds( image )
%findspuds function locates object boundaries and displays details in Command
%Windows
%read image
orginalImage = imread(image);
%convert to grayscale
grayImage = rgb2gray(orginalImage);
%convert to black/white with low threshold
blackWhiteImage = im2bw(grayImage,6/255);
%reverse binary values
reversedBlackWhiteImage = imcomplement(blackWhiteImage);
%compute distance transform to the nearest 0 pixel in the binary image
calReversedBlackWhiteImage = bwdist(reversedBlackWhiteImage);
%reverse back binary values
reversed2BlackWhiteImage = imcomplement(calReversedBlackWhiteImage);
%suppress pixel depth minimum
shallowImage = imhmin(reversed2BlackWhiteImage,10);
%compute a label matrix of watershed regions
waterImage = watershed(shallowImage);
%use watershed matrix to separate the touching objects in the binary image
blackWhiteImage(waterImage == 0) = 0;
%remove elements with fewer then 500 pixels
clnImage = bwareaopen(blackWhiteImage,500);
%remove holes in objects
filledImage = imfill(clnImage,'holes');
%get object boundaries
objectBoundries = bwboundaries(filledImage);
%label each object to get its measurements
labeledImage = bwlabel(filledImage);
%get all the object properties
objectMeasurements = regionprops(labeledImage, grayImage, 'all');
%align object labels in the centre of the object
labelShiftX = -7;
%display object boundaries on original image
imshow(orginalImage)
hold on
%print table header line in the command window
fprintf(1,'Object # Centroid Size Major/minor axis Circularity Mean/standard deviation\n');
%for each labelled object...
for thisObject = 1:length(objectBoundries)
%get and print its boundries
boundary = objectBoundries{thisObject};
plot(boundary(:,2), boundary(:,1), 'b', 'LineWidth', 2)
%get centroid
objectCentroid = objectMeasurements(thisObject).Centroid;
%get area
objectSize = objectMeasurements(thisObject).Area;
%get major axis length
objectMajorAxisLength = objectMeasurements(thisObject).MajorAxisLength;
%get minor axis length
objectMinorAxisLength = objectMeasurements(thisObject).MinorAxisLength;
%get circularity
objectCircularity = objectMeasurements(thisObject).Perimeter;
%get list of pixels in current object
objectPixels = objectMeasurements(thisObject).PixelIdxList;
%get mean intensity of grayImage
objectMean = mean(grayImage(objectPixels));
%get standard intensity of grayImage
objectStandard = std2(grayImage(objectPixels));
%print object properties
fprintf(1,'#%2d %8.1f %8.1f %10.1f %10.1f %8.1f %12.1f %15.1f %8.1f\n', thisObject, objectCentroid, objectSize, objectMajorAxisLength, objectMinorAxisLength, objectCircularity, objectMean, objectStandard);
%print object labels
text(objectCentroid(1) + labelShiftX, objectCentroid(2), num2str(thisObject), 'FontSize', 14, 'FontWeight', 'Bold', 'Color','w');
end
end
mask = false(size(grayImage));
mask(objectPixels) = true;
%on R channel
tmp = orginalImage(:,:,1);
objectMeanR = mean(tmp(mask));
objectStandard = std2(tmp(mask));
Similarly you can implement mean and std2 on G and B channels.

how to detect optic disc in retinal images using matlab

enter code here
% Finding mean for 49*49 sub images
meanmat=ones(209,209);
k=1;count=1;
[m n]=size(BW);
for i=25:1:m-24
for j=25:1:n-24
rowst=i-24;rowend=i+24;
colst=j-24;
colend=j+24;
summat=0;
for row=rowst:1:rowend
for col=colst:1:colend
summat=summat+BW(row,col);
end
end
meanval=(summat)/(49*49);
meanmat(k,count)=meanval;
if(count>208)
count=1;k=k+1;
else
count=count+1;
end
end
end
% mean and median filter
I = im2double(BW);
kernel = ones(80,80) / (80*80); % 49*49 mean kernel
J = conv2(I, kernel, 'same'); % Convolve keeping size of I
stdDevImage = stdfilt(BW);
varianceIMage = stdDevImage .^2;
figure,subplot(2,2,1);
imshow(BW);title('Original');
subplot(2,2,2);
imshow(meanmat);title(sprintf('MeanImage'));
subplot(2,2,3);
imshow(varianceIMage);title(sprintf('variance using stdfilt'));
subplot(2,2,4);
imshow(J);title(sprintf('Average Variance using conv2'));
I have calculated mean,variance and average variance for the image using the above code.But the optic disc was not detected properly.Can anyone help me with the matlab code for finding the optic disc?
%% Initial Image Processing.
% get image and mode from workspace
Im = evalin('base','Im');
singlemode = evalin('base','singlemode');
% apply filter on green component
f1 = fspecial('average',31); % create averaging filter
IMA = imadjust(Im(:,:,2)); % adjust green component intensity first
Imf = filter2(f1,IMA); % apply filter
Imf = mat2gray(Imf); % convert back from (0,1) to (0,255)
axes(handles.axes2); % show grayscale filtered image
imshow(Imf);
%% Edge Detection.
thrsh = str2num(get(handles.edit1,'String')); % default = 0.98
Ibw=im2bw(Imf,thrsh); % binary mask / black & white threshold
I_edge = edge(Ibw); % edge detection
% axes(handles.axes3);
% imshow(I_edge); % show image
%% Circular Hough transform to detect optical disc (OD).
% Rmin = str2num(get(handles.edit3,'String')); % minimum radius from user input
% Rmax = str2num(get(handles.edit4,'String')); % maximum radius from user input
Rmin = 80;
Rmax = 120;
radii = Rmin:5:Rmax; % radii to check
h = circle_hough(I_edge,radii,'same','normalise');
peaks = circle_houghpeaks(h,radii,'nhoodxy',2*(Rmax/2)+1,'nhoodr',5,'npeaks',1); % find the peaks in the transform, meaning find the best fit of a circle. and we only want 1 circle.
% Lines 196 -207 - if we're in single mode, we're plotting the circle in the top left image
if singlemode
axes(handles.axes1);
imshow(Im);
hold on
for peak = peaks
[x y] = circlepoints(peak(3)); % This function returns the x,y coordinates of the found circle, peak(3) is the radius of the found circle.
plot(x+peak(1),y+peak(2),'b-'); % we plot the x,y coordinates shifted by the center of the circle, which are peak(1) and peak(2)
end
plot(peak(1),peak(2),'r+'); % We plot the center of the circle with a red cross.
hold off
end
axes(handles.axes2); % Lines 208 - 214, we repeat the plot of the circle into axes2, the top right figure
hold on
for peak = peaks
[x y] = circlepoints(peak(3));
plot(x+peak(1),y+peak(2),'b-');
end
hold off
%% Region of Interest (ROI) Processing.
% we have localized the OD, define the ROI around this position for further
% processing.
axes(handles.axes2); % Activate axes2.
e = imellipse(gca,[peak(1)-2*peak(3) peak(2)-2*peak(3) 4*peak(3) 4*peak(3)]); %get an elliptical sub image centered around the peak(1) and peak(2) values (the centers of the previously found OD) and 2 times the radius that was found previously.
BW = createMask(e); % Create a mask from this region of interest = ROI.
Imf_masked = Imf.*BW; % Apply mask to the image, this will make everything outside of the ROI become black.
% axes(handles.axes4);
% imshow(Imf_masked);
thrsh = str2num(get(handles.edit5,'String')); % get threshold for ROI hough transform from the GUI, default = 0.65
Ibw=im2bw(Imf_masked,thrsh); % binary mask / black & white threshold (threshold the masked image).
I_edge = edge(Ibw); % edge detection
% axes(handles.axes3);
% imshow(I_edge); % show image
% hough transform to find circle in the ROI
h = circle_hough(I_edge,radii,'same','normalise');
peaks = circle_houghpeaks(h,radii,'nhoodxy',2*(Rmax/2)+1,'nhoodr',5,'npeaks',1);
if singlemode
axes(handles.axes1);
hold on
for peak = peaks
[x y] = circlepoints(peak(3));
plot(x+peak(1),y+peak(2),'g-');
end
plot(peak(1),peak(2),'g+');
hold off
end

Drawing the major and minor axis of an elliptical object in MATLAB

This program currently inputs an image of a coin, thresholds it, binarizes it, and finds the major and minor axis lengths of the segmented elliptical using the regionprops function. How do I output a subplot where I draw the axes used to calculate the 'MajorAxisLength' and 'MinorAxisLength' over the original image?
I have appended my code for your perusal.
% Read in the image.
folder = 'C:\Documents and Settings\user\My Documents\MATLAB\Work';
baseFileName = 'coin2.jpg';
fullFileName = fullfile(folder, baseFileName);
fullFileName = fullfile(folder, baseFileName);
if ~exist(fullFileName, 'file')
fullFileName = baseFileName; % No path this time.
if ~exist(fullFileName, 'file')
%Alert user.
errorMessage = sprintf('Error: %s does not exist.', fullFileName);
uiwait(warndlg(errorMessage));
return;
end
end
rgbImage = imread(fullFileName);
% Get the dimensions of the image. numberOfColorBands should be = 3.
[rows columns numberOfColorBands] = size(rgbImage);
% Display the original color image.
subplot(2, 3, 1);
imshow(rgbImage, []);
title('Original color Image', 'FontSize', fontSize);
% Enlarge figure to full screen.
set(gcf, 'Position', get(0,'Screensize'));
% Extract the individual red color channel.
redChannel = rgbImage(:, :, 1);
% Display the red channel image.
subplot(2, 3, 2);
imshow(redChannel, []);
title('Red Channel Image', 'FontSize', fontSize);
% Binarize it
binaryImage = redChannel < 100;
% Display the image.
subplot(2, 3, 3);
imshow(binaryImage, []);
title('Thresholded Image', 'FontSize', fontSize);
binaryImage = imfill(binaryImage, 'holes');
labeledImage = bwlabel(binaryImage);
area_measurements = regionprops(labeledImage,'Area');
allAreas = [area_measurements.Area];
biggestBlobIndex = find(allAreas == max(allAreas));
keeperBlobsImage = ismember(labeledImage, biggestBlobIndex);
measurements = regionprops(keeperBlobsImage,'MajorAxisLength','MinorAxisLength')
% Display the original color image with outline.
subplot(2, 3, 4);
imshow(rgbImage);
hold on;
title('Original Color Image with Outline', 'FontSize',fontSize);
boundaries = bwboundaries(keeperBlobsImage);
blobBoundary = boundaries{1};
plot(blobBoundary(:,2), blobBoundary(:,1), 'g-', 'LineWidth', 1);
hold off;
I had the same task as you for some project I did 2 years ago. I've modified the code I used then for you below. It involved calculating the covariance matrix for the datapoints and finding their eigenvalues/eigenvectors. Note here that because of circular symmetry, the minor and major axis will be somewhat "random". Also note that I have made the image binary in a very naïve way to keep the code simple.
% Load data and make bw
clear all;close all; clc;
set(0,'Defaultfigurewindowstyle','docked')
I = imread('american_eagle_gold_coin.jpg');
Ibw = im2bw(I,0.95);
Ibw = not(Ibw);
figure(1);clf
imagesc(Ibw);colormap(gray)
%% Calculate axis and draw
[M N] = size(Ibw);
[X Y] = meshgrid(1:N,1:M);
%Mass and mass center
m = sum(sum(Ibw));
x0 = sum(sum(Ibw.*X))/m;
y0 = sum(sum(Ibw.*Y))/m;
%Covariance matrix elements
Mxx = sum(sum((X-x0).^2.*Ibw))/m;
Myy = sum(sum((Y-y0).^2.*Ibw))/m;
Mxy = sum(sum((Y-y0).*(X-x0).*Ibw))/m;
MM = [Mxx Mxy; Mxy Myy];
[U S V] = svd(MM);
W = V(:,1)/sign(V(1,1)); %Extremal directions (normalized to have first coordinate positive)
H = V(:,2);
W = 2*sqrt(S(1,1))*W; %Scaling of extremal directions to give ellipsis half axis
H = 2*sqrt(S(2,2))*H;
figure(1)
hold on
plot(x0,y0,'r*');
quiver(x0,y0,W(1),H(1),'r')
quiver(x0,y0,W(2),H(2),'r')
hold off
Look at the documentation for the Orientation attribute that regionprops() can return to you.
This gives the angle between the positive x-axis and the major axis of the ellipse. You should be able to derive the equation for the major axis line in terms of that angle, and then just make a grid of x-axis points, and compute the major axis line's value for all the points in your grid, then just plot it like you would plot any other curve in MATLAB.
To do the same for the minor axis, just note that it will be 90 degrees further counter-clockwise from the major axis, then repeat the step above.
Usually one does it with computing eigenvectors, as explained in the Wikipedia article Image moment under 'examples'. That would be the correct way.
But I wonder, if you know the centroid and the boundingbox from MATLAB, then the endpoint of the major axis must be in the upper left or upper right corner. So checking (apart from noise) these two corners, if there are pixel, would give you the major axis. The minor axis then is just orthogonal to it with respect to the centroid.
Sorry for not having MATLAB code ready.
The reasoning is not that wrong, but not so good either, using the orientation as written above is better ;)