How to get accurate clusters using k-means clustering in matlab - matlab

I am doing a project on plant disease detection. I need to extract diseased parts from images of leafs but I'm not able to separate out diseased regions accurately using k-means. Specifically, the rest of the leaf is visible on the image with the diseased parts segmented. Here is the original image and image after extracting diseased parts:original image image after separating diseased parts
Here is the code I have written
b=imread('12.jpeg');
G=fspecial('gaussian',[200 250],1);
Ig=imfilter(b,G,'same');
figure,imshow(Ig);
conversionform = makecform('srgb2lab');
lab_img = applycform(Ig,conversionform);
figure,imshow(lab_img);
ab = double(lab_img(:,:,2:3));
nrows = size(ab,1);
ncols = size(ab,2);
ab = reshape(ab,nrows*ncols,2);
nColors = 2;
[cluster_idx, cluster_center] = kmeans(ab,nColors,'distance','sqEuclidean', ...,
'Replicates',3);
pixel_labels = reshape(cluster_idx,nrows,ncols);
figure, imshow(pixel_labels,[]), title('image labeled by cluster index');
segmented_images = cell(1,3);
rgb_label = repmat(pixel_labels,[1 1 3]);
for k = 1:nColors
color = lab_img;
color(rgb_label ~= k) = 0;
segmented_images{k} = color;
end
figure, imshow(segmented_images{1}), title('objects in cluster 1');
figure, imshow(segmented_images{2}), title('objects in cluster 2');
e=segmented_images{1};
figure,imshow(e);
conversionform = makecform('lab2srgb');
new_image=applycform(e,conversionform);
figure,imshow(new_image);
I want to extract only the diseased regions using K means clustering. I would be grateful if someone could help me with this. I am using matlab 2009a.

Here is a corrected code that will do what you expect:
function segmented_img = leaf_segmentation( original_img, nclusters )
original_img = im2double(original_img);
smoothed_img = imgaussfilt(original_img,1);
conversionform = makecform('srgb2lab');
lab_img = applycform(smoothed_img,conversionform);
ab_img = lab_img(:,:,2:3);
[nrows,ncols,~] = size(ab_img);
ab_img = reshape(ab_img,nrows*ncols,2);
cluster_idx = kmeans(ab_img,nclusters,'distance','sqEuclidean','Replicates',3);
cluster_img = reshape(cluster_idx,nrows,ncols);
%figure, imagesc(cluster_img), title('Clustering results');
segmented_img = cell(1,nclusters);
for k = 1:nclusters
segmented_img{k} = bsxfun( #times, original_img, cluster_img == k );
end
end
You can call it and visualise the results like so:
segmented = leaf_segmentation( original, 3 );
figure;
subplot(1,3,1), imshow(segmented{1}), title('Cluster 1');
subplot(1,3,2), imshow(segmented{2}), title('Cluster 2');
subplot(1,3,3), imshow(segmented{3}), title('Cluster 3');
Note that the order of the clusters may vary. You can order them a posteriori knowing that the leaf should be mostly green/yellow, and that the background should be mostly black.

Related

how to find the corners of rotated object in matlab?

I want to find the corners of objects.
I tried the following code:
Vstats = regionprops(BW2,'Centroid','MajorAxisLength','MinorAxisLength',...
'Orientation');
u = [Vstats.Centroid];
VcX = u(1:2:end);
VcY = u(2:2:end);
[VcY id] = sort(VcY); % sorting regions by vertical position
VcX = VcX(id);
Vstats = Vstats(id); % permute according sort
Bv = Bv(id);
Vori = [Vstats.Orientation];
VRmaj = [Vstats.MajorAxisLength]/2;
VRmin = [Vstats.MinorAxisLength]/2;
% find corners of vertebrae
figure,imshow(BW2)
hold on
% C = corner(VER);
% plot(C(:,1), C(:,2), 'or');
C = cell(size(Bv));
Anterior = zeros(2*length(C),2);
Posterior = zeros(2*length(C),2);
for i = 1:length(C) % for each region
cx = VcX(i); % centroid coordinates
cy = VcY(i);
bx = Bv{i}(:,2); % edge points coordinates
by = Bv{i}(:,1);
ux = bx-cx; % move to the origin
uy = by-cy;
[t, r] = cart2pol(ux,uy); % translate in polar coodinates
t = t - deg2rad(Vori(i)); % unrotate
for k = 1:4 % find corners (look each quadrant)
fi = t( (t>=(k-3)*pi/2) & (t<=(k-2)*pi/2) );
ri = r( (t>=(k-3)*pi/2) & (t<=(k-2)*pi/2) );
[rp, ip] = max(ri); % find farthest point
tc(k) = fi(ip); % save coordinates
rc(k) = rp;
end
[xc,yc] = pol2cart(tc+1*deg2rad(Vori(i)) ,rc); % de-rotate, translate in cartesian
C{i}(:,1) = xc + cx; % return to previous place
C{i}(:,2) = yc + cy;
plot(C{i}([1,4],1),C{i}([1,4],2),'or',C{i}([2,3],1),C{i}([2,3],2),'og')
% save coordinates :
Anterior([2*i-1,2*i],:) = [C{i}([1,4],1), C{i}([1,4],2)];
Posterior([2*i-1,2*i],:) = [C{i}([2,3],1), C{i}([2,3],2)];
end
My input image is :
I got the following output image
The bottommost object in the image is not detected properly. How can I correct the code? It fails to work for a rotated image.
You can get all the points from the image, and use kmeans clustering and partition the points into 8 groups. Once partition is done, you have the points in and and you can pick what ever the points you want.
rgbImage = imread('your image') ;
%% crop out the unwanted white background from the image
grayImage = min(rgbImage, [], 3);
binaryImage = grayImage < 200;
binaryImage = bwareafilt(binaryImage, 1);
[rows, columns] = find(binaryImage);
row1 = min(rows);
row2 = max(rows);
col1 = min(columns);
col2 = max(columns);
% Crop
croppedImage = rgbImage(row1:row2, col1:col2, :);
I = rgb2gray(croppedImage) ;
%% Get the white regions
[y,x,val] = find(I) ;
%5 use kmeans clustering
[idx,C] = kmeans([x,y],8) ;
%%
figure
imshow(I) ;
hold on
for i = 1:8
xi = x(idx==i) ; yi = y(idx==i) ;
id1=convhull(xi,yi) ;
coor = [xi(id1) yi(id1)] ;
[id,c] = kmeans(coor,4) ;
plot(coor(:,1),coor(:,2),'r','linewidth',3) ;
plot(c(:,1),c(:,2),'*b')
end
Now we are able to capture the regions..the boundary/convex hull points are in hand. You can do what ever math you want with the points.
Did you solve the problem? I Looked into it and it seems that the rotation given by 'regionprops' seems to be off. To fix that I've prepared a quick solution: I've dilated the image to close the gaps, found 4 most distant peaks of each spine, and then validated if a peak is on the left, or on the right of the centerline (that I have obtained by extrapolating form sorted centroids). This method seems to work for this particular problem.
BW2 = rgb2gray(Image);
BW2 = imbinarize(BW2);
%dilate and erode will help to remove extra features of the vertebra
se = strel('disk',4,4);
BW2_dilate = imdilate(BW2,se);
BW2_erode = imerode(BW2_dilate,se);
sb = bwboundaries(BW2_erode);
figure
imshow(BW2)
hold on
centerLine = [];
corners = [];
for bone = 1:length(sb)
x0 = sb{bone}(:,2) - mean(sb{bone}(:,2));
y0 = sb{bone}(:,1) - mean(sb{bone}(:,1));
%save the position of the centroid
centerLine = [centerLine; [mean(sb{bone}(:,1)) mean(sb{bone}(:,2))]];
[th0,rho0] = cart2pol(x0,y0);
%make sure that the indexing starts at the dip, not at the corner
lowest_val = find(rho0==min(rho0));
rho1 = [rho0(lowest_val:end); rho0(1:lowest_val-1)];
th00 = [th0(lowest_val:end); th0(1:lowest_val-1)];
y1 = [y0(lowest_val:end); y0(1:lowest_val-1)];
x1 = [x0(lowest_val:end); x0(1:lowest_val-1)];
%detect corners, using smooth data to remove noise
[pks,locs] = findpeaks(smooth(rho1));
[pksS,idS] = sort(pks,'descend');
%4 most pronounced peaks are where the corners are
edgesFndCx = x1(locs(idS(1:4)));
edgesFndCy = y1(locs(idS(1:4)));
edgesFndCx = edgesFndCx + mean(sb{bone}(:,2));
edgesFndCy = edgesFndCy + mean(sb{bone}(:,1));
corners{bone} = [edgesFndCy edgesFndCx];
end
[~,idCL] = sort(centerLine(:,1),'descend');
centerLine = centerLine(idCL,:);
%extrapolate the spine centerline
yDatExt= 1:size(BW2_erode,1);
extrpLine = interp1(centerLine(:,1),centerLine(:,2),yDatExt,'spline','extrap');
plot(centerLine(:,2),centerLine(:,1),'r')
plot(extrpLine,yDatExt,'r')
%find edges to the left, and to the right of the centerline
for bone = 1:length(corners)
x0 = corners{bone}(:,2);
y0 = corners{bone}(:,1);
for crn = 1:4
xCompare = extrpLine(y0(crn));
if x0(crn) < xCompare
plot(x0(crn),y0(crn),'go','LineWidth',2)
else
plot(x0(crn),y0(crn),'ro','LineWidth',2)
end
end
end
Solution

How to apply kmeans clustering on gray scale image in matlab

skin cancer image
I want to apply K means clustering on grayscale image, code is as follow
im = imread('SSM1_2_orig.jpg');
im = rgb2gray(im);
[idx centroids]=kmeans(double(im(:)),3,'distance','sqEuclidean','Replicates',3);
%imseg = zeros(size(im,1),size(im,2));
%{for i=1:max(idx)
%imseg(idx==i)=i;
%end}
segmented_images = cell(1,3);
for k = 1:3
color = im;
color(im ~= k) = 0;
segmented_images{k} = color;
end
figure(),imshow(segmented_images{1});
figure(),imshow(segmented_images{2});
figure(),imshow(segmented_images{3});
but it gives me the black output only
Here is the working code. Notes:
You are never using the result of the clustering,you are comparing the original pixel values with k, instead of the clustered pixel values idx.
Also, remember to use imshow(____, []) if your images are not [0-1] or [0-255].
im = imread('https://i.stack.imgur.com/ZYp7r.jpg');
im = rgb2gray(im);
[idx, centroids]=kmeans(double(im(:)),3,'distance','sqEuclidean','Replicates',3);
segmented_images = cell(1,3);
for k = 1:3
color = zeros(size(im));
color(idx==k) = im(idx==k);
segmented_images{k} = color;
end
figure(),imshow(segmented_images{1},[]);
figure(),imshow(segmented_images{2},[]);
figure(),imshow(segmented_images{3},[]);

Extraction of Plankton using Segmentation with Matlab

I am trying to extract plankton from a scanned image.
I segmented the plankton using the technique I found here, http://www.mathworks.com/help/images/examples/detecting-a-cell-using-image-segmentation.html
The outline is not bad, however, now I am not sure how to extract the images so each individual plankton can be saved individually. I tried to use labels but there is a lot of noise and it labels every single spec. I am wondering if there is a better way to do this.
Here is my code:
I = imread('plankton_2.jpg');
figure, imshow(I), title('original image');
[~, threshold] = edge(I, 'sobel');
fudgeFactor = .5;
BWs = edge(I,'sobel', threshold * fudgeFactor);
figure, imshow(BWs), title('binary gradient mask');
se90 = strel('line', 3, 90);
se0 = strel('line', 3, 0);
BWsdil = imdilate(BWs, [se90 se0]);
figure, imshow(BWsdil), title('dilated gradient mask');
BWdfill = imfill(BWsdil, 'holes');
figure, imshow(BWdfill);
title('binary image with filled holes');
BWnobord = imclearborder(BWdfill,1);
figure, imshow(BWnobord), title('cleared border image');
seD = strel('diamond',1);
BWfinal = imerode(BWnobord,seD);
BWfinal = imerode(BWfinal,seD);
figure, imshow(BWfinal), title('segmented image');
BWoutline = bwperim(BWfinal);
Segout = I;
Segout(BWoutline) = 0;
figure, imshow(Segout), title('outlined original image');
label = bwlabel(BWfinal);
max(max(label))
for j = 1:max(max(label))
[row, col] = find(label == j);
len = max(row) - min(row)+2;
breadth = max(col)-min(col) +2;
target = uint8(zeros([len breadth]));
sy = min(col)-1;
sx = min(row)-1;
for i = 1:size(row,1)
x = row(i,1)-sx;
y = col(i,1) - sy;
target(x,y)=I(row(i,1),col(i,1));
end
mytitle =strcat('Object Number:',num2str(j));
figure, imshow(target);mytitle;
end
for j = 1:max(max(label))
[row, col] = find(label == j);
len = max(row) - min(row)+2;
breadth = max(col)-min(col) +2;
target = uint8(zeros([len breadth]));
sy = min(col)-1;
sx = min(row)-1;
for i = 1:size(row,1)
x = row(i,1)-sx;
y = col(i,1) - sy;
target(x,y)=I(row(i,1),col(i,1));
end
mytitle =strcat('Object Number:',num2str(j));
figure, imshow(target);mytitle;
end
You should use the regionprops function to filter the detected objects by size and/or shape characteristics.

Image Segmentation WIth Self Organizing Map in Matlab

i'm making image segmentation with self organizing map. the image segement by 3 cluster. Sample image is :
and i have type the matlab code like this bellow :
clear;
clc;
i=imread('DataSet/3.jpg');
I = imresize(i,0.5);
cform = makecform('srgb2lab');
lab_I = applycform(I,cform);
ab = double(lab_I(:,:,2:3));
nrows = size(ab,1);
ncols = size(ab,2);
ab = reshape(ab,nrows*ncols,2);
a = ab(:,1);
b = ab(:,2);
normA = (a-min(a(:))) ./ (max(a(:))-min(a(:)));
normB = (b-min(b(:))) ./ (max(b(:))-min(b(:)));
ab = [normA normB];
newnRows = size(ab,1);
newnCols = size(ab,2);
cluster = 3;
% Max number of iteration
N = 90;
% initial learning rate
eta = 0.3;
% exponential decay rate of the learning rate
etadecay = 0.2;
%random weight
w = rand(2,cluster);
%initial D
D = zeros(1,cluster);
% initial cluster index
clusterindex = zeros(newnRows,1);
% start
for t = 1:N
for data = 1 : newnRows
for c = 1 : cluster
D(c) = sqrt(((w(1,c)-ab(data,1))^2) + ((w(2,c)-ab(data,2))^2));
end
%find best macthing unit
[~, bmuindex] = min(D);
clusterindex(data)=bmuindex;
%update weight
oldW = w(:,bmuindex);
new = oldW + eta * (reshape(ab(data,:),2,1)-oldW);
w(:,bmuindex) = new;
end
% update learning rate
eta= etadecay * eta;
end
%Label Every Pixel in the Image Using the Results from KMEANS
pixel_labels = reshape(clusterindex,nrows,ncols);
%Create Images that Segment the I Image by Color.
segmented_images = cell(1,3);
rgb_label = repmat(pixel_labels,[1 1 3]);
for k = 1:cluster
color = I;
color(rgb_label ~= k) = 0;
segmented_images{k} = color;
end
figure,imshow(segmented_images{1}), title('objects in cluster 1');
figure,imshow(segmented_images{2}), title('objects in cluster 2');
figure,imshow(segmented_images{3}), title('objects in cluster 3');
and after runing the matlab code, there is no image segmentation result. Matlab show 3 figure, Figure 1 show the full image, figure 2 blank, figure 3 blank .
please anyone help me to revise my matlab code, is any wrong code or something?
new = oldW + eta * (reshape(ab(data,:),2,1)-oldW);
This line looks suspicious to me, why you are subtracting old weights here, i dont think this makes any sense there, just remove oldW from there and check your results again.
Thank You

How to use the new functions of PDE toolbox in image processing (Matlab R2015a)

I want to use the line new command of PDE toolbox as Matlab R2015 to restore a noisy image with gaussian noise.
The PDE is:
∇.(( ∇u)/(√(1+|∇u|2))) +(f2)/(u2) = 1 in Ω (∂u)/(∂n)=0 in ∂Ω
Where f is the noisy image and u the restored image.
I tried the following code:
clear
close all
clc
img = 'AA.jpg';
mInputImage = double(imread(img));
mInputImage = rgb2gray(mInputImage);
[numRows, numCols] = size(mInputImage);
Var = 0.04;
Mean = 0;
mInputImageNoisy = imnoise((mInputImage(:,:,1)),'gaussian',Mean, Var);
% reshape the input and noisy images to vectors
mInputImageVector = reshape(mInputImage,numRows*numCols,1);
mInputImageNoisyVector = reshape(mInputImageNoisy,numRows*numCols,1);
Residu1 = norm(mInputImageVector-mInputImageNoisyVector)/norm(mInputImageVector)
RegularisationCoefficient = 0.7*ones((numRows-1)*(numCols-1),1);
mOutputImageVector = mInputImageNoisyVector;
%a = (mInputImageNoisyVector.^2) ./ mOutputImageVector.^3;
f = 1;
rtol = 1e-1;
c = '1./sqrt(1+ux.^2+uy.^2)';
% Create a PDE Model with a single dependent variable
numberOfPDE = 1;
pdem = createpde(numberOfPDE);
g = #squareg;
geometryFromEdges(pdem,g);
% Plot the geometry and display the edge labels for use in the boundary
% condition definition.
figure;
pdegplot(pdem, 'edgeLabels', 'on');
%axis([0 numRows 0 numCols]);
axis([-2 2 -2 2]);
title 'Geometry With Edge Labels Displayed'
b2 = applyBoundaryCondition(pdem,'Edge',[1 2 3 4], 'u', 0);
[p,e,t] = poimesh(g,numRows, numCols);
numCols
pdemesh(p,e,t);
axis equal
for iter = 1: numRows*numRows,
mOutputImageVector(iter) = pdenonlin(pdem,c,...
(mInputImageNoisyVector(iter).^2) ./ mOutputImageVector(iter).^3,...
f,'tol',rtol);
SaveImageVector(iter) = mOutputImageVector;
end
mOutputImage = reshape(SaveImageVector,numRows,numRows);
mOutputImage = uint8(mOutputImage);
figure()
imshow(mOutputImage)