Image Processing Challenge using edge detection

17 views (last 30 days)
Advok8
Advok8 on 25 Dec 2023
Answered: DGM on 26 Dec 2023

I’m trying to apply image processing technique to an image. Specifically, I am trying to apply edge detection to draw rough contour lines around each datapoint cluster in an image using [matlab image processing Tool]. However, my current code is identifying each data point individually rather than the clusters I’m targeting. I’m including an example image to illustrate what I’m trying to achieve. Any guidance would be greatly appreciated, especially since I’m approaching a tight deadline. THANKS

  2 Comments
DGM
DGM on 25 Dec 2023
Edited: DGM on 25 Dec 2023
Attach the actual image instead of a screenshot. Something other than JPG.
If the image is a screenshot of a scatter plot of xy data, attach the data instead of trying to process a picture of a plot..
What sort of boundary is desired? A rectangular box as shown by the screenshot, or a convex hull?
How tightly should the boundary be fit to the cluster? Is it okay to discard some outliers, as the screenshot shows?
Advok8
Advok8 on 25 Dec 2023
Hi @DGM
Thanks for the prompt response. I just have the jpg file. I attached a copy of the original image and also a sketch of what i am hoping to achieve. Please let me know if you have any questions.

Sign in to comment.

Answers (2)

DGM
DGM on 25 Dec 2023
Without knowing the answers to the clarifications, this is one idea.
I recovered a crude image from the damaged screenshot. The thresholding I used is characteristic only of the image I created.
Obviously, if the data source is actually xy data instead of a raster image, creating and processing an image is a waste of time and a huge invitation for problems.
The kmeans setup comes more or less straight from the documentation for kmeans. There's probably room for improvement.
% an image?
inpict = imread('junk.png');
% binarized
mask = ~imbinarize(inpict,'adaptive','foregroundpolarity','dark','Sensitivity',0.4);
% find all true pixel positions
[y x] = find(mask);
% cluster the data into three groups
nclusters = 3;
opts = statset('Display','off');
[idx,C] = kmeans([x y],nclusters,'Distance','cityblock',...
'Replicates',5,'Options',opts);
% split the pointlist into the respective clusters
cpoints = cell(nclusters,1);
chull = cell(nclusters,1);
for k = 1:nclusters
mk = idx==k; % logical map of selected points
cpoints{k} = [x(mk) y(mk)]; % point list in xy coordinates
% find the convex hull of these points
mk = convhull(cpoints{k}(:,1),cpoints{k}(:,2)); % indices of points which are vertices
chull{k} = cpoints{k}(mk,:); % get those xy coordinates
end
% plot the points and hulls over the original mask
imshow(mask,'border','tight'); hold on
colors = {'r.','b.','m.'};
for k = 1:nclusters
plot(cpoints{k}(:,1),cpoints{k}(:,2),colors{k})
plot(chull{k}(:,1),chull{k}(:,2),colors{k}(1))
end
% plot the cluster centroids
plot(C(:,1),C(:,2),'kx',...
'MarkerSize',15,'LineWidth',3)

DGM
DGM on 26 Dec 2023
Well, given that the two images are vastly different, I have no idea where this is going, or what criteria should be used for separating the clusters. I'm just going to say do it manually. You'll have to rescale everything to data coordinates manually anyway. This is why you don't try processing plots. Plots are not data.
% THINGS THAT MUST BE DONE MANUALLY FOR EACH NEW IMAGE:
% -- specify xrange, yrange
% -- crop the image to the extents specified by xrange,yrange
% -- probably have to redo the HSV thresholding if the colormap changes
% -- specify nclusters
% -- manually select each cluster roughly
% an image
inpict = imread('19495.jpg');
% cropped to known axis extents
xrange = [0 350]; % the location of axis extents in data coordinates
yrange = [-40 40];
inpict = imcrop(inpict,[146.51 63.51 842.98 684.98]); % you'll have to do this manually
sz = size(inpict,1:2);
% get mask
[~,S,V] = rgb2hsv(inpict);
mask = S > 0.43 & V > 0.60;
%mask = imerode(mask,ones(3)); % try to make sure dots are isolated
mask = ordfilt2(mask,6,ones(9,1)); % maybe a bit less risk of dot removal
% since it's not clear how many groups there are
% or what actually defines their boundary
% manually select where each group is by drawing a loose polygon around it
nclusters = 2; % specify this
cpoints = cell(nclusters,1);
chull = cell(nclusters,1);
imshow(~mask,'border','loose') % need loose padding in order to be able to select image edges
for k = 1:nclusters
% isolate each group
ROI = drawpolygon(gca);
thisgroupmask = mask & createMask(ROI); % get mask of these blobs
% find centroids of each dot (or dot fragment)
% each dot on the graph represents a single point, not a big circle
% so they all need to be reduced to single points.
% error caused by split dots shouldn't matter if they're on the interior of the hull
S = regionprops(thisgroupmask,'centroid'); % get blob centers
cpoints{k} = vertcat(S.Centroid); % these are in image coordinates, not data coordinates!
% find the convex hull of these points
mk = convhull(cpoints{k}(:,1),cpoints{k}(:,2)); % point indices within the group
chull{k} = cpoints{k}(mk,:); % vertex list in xy coordinates (still in image coordinates)
% convert everything to data coordinates
cpoints{k} = rescalexy(cpoints{k},sz,xrange,yrange);
chull{k} = rescalexy(chull{k},sz,xrange,yrange);
end
% plot the points and hull over the mask
imagesc(mask,'xdata',xrange,'ydata',yrange); hold on
colors = {'r.','b.','m.'};
for k = 1:nclusters
plot(cpoints{k}(:,1),cpoints{k}(:,2),colors{k})
plot(chull{k}(:,1),chull{k}(:,2),colors{k}(1))
end
colormap(gray)
% a simple wrapper function, because rescale() is ugly and cumbersome to use
function xyout = rescalexy(xyin,sz0,xrange,yrange)
xyout(:,1) = rescale(xyin(:,1),xrange(1),xrange(2),'inputmin',1,'inputmax',sz0(2));
xyout(:,2) = rescale(xyin(:,2),yrange(1),yrange(2),'inputmin',1,'inputmax',sz0(1));
end

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!