Creating a Grid for cooridnates

Hello, I have an image where i have foudn the location of the spot centroid. I have the liist of all the coordimates.
What I want to do is create a set of vertical lines that is an average of the spots x positon, so in this case 4 vertical lines of which I have shown 1 below). and then do it for the horizontal lines.
In reality my images change in size and I can have upto 50x50 spots.
these are the actual coordiantes (x,y)
3.9988 76.5058
5.4914 203.4980
7.3364 330.4643
130.3843 77.1741
132.5535 204.2574
134.5383 331.2441
257.6364 77.8253
259.6390 205.0028
261.5130 331.9971
385.1154 78.8457
386.9360 205.8598
388.7871 332.6533
(Or Broken in to single column vectors)
x =
3.9988
5.4914
7.3364
130.3843
132.5535
134.5383
257.6364
259.6390
261.5130
385.1154
386.9360
388.7871
y =
76.5058
203.4980
330.4643
77.1741
204.2574
331.2441
77.8253
205.0028
331.9971
78.8457
205.8598
332.6533

 Accepted Answer

Matt J
Matt J on 15 Oct 2023
Edited: Matt J on 15 Oct 2023
and I also do pick up a few spurious spots that are'nt part of the grid
If outliers are present, I would use the approach below, which requries the download of this FEX contribution,
I don't really know the distribution of your outliers, so that may affect choices of certain parameters, as noted below in the code.
load Image_outliers
C=vertcat(regionprops(Image,'Centroid').Centroid);
x=C(:,1);
y=C(:,2);
D=pdist2([x,y],[x,y],'city','Smallest',2);
D(1,:)=[];
d=median(D(:));
Xedges=binEdges(x,d);
Yedges=binEdges(y,d);
[~,~,~,Gx,Gy]=histcounts2(x,y,Xedges,Yedges);
xl=splitapply(@median,x,Gx);
yl=splitapply(@median,y,Gy);
imshow(Image,[]);
xline(xl,'y--'); yline(yl,'y--')
function edges=binEdges(z,d)
Z=-d/2:round(max(z)+d/2);
T=sum(abs(Z-z(:))<=d/5,1);
thresh=0.5*max(T); %depends on outlier rate
[start,stop]=groupLims(groupTrue(T<=thresh),1);
edges=(Z(start)+Z(stop))/2;
end

3 Comments

Thanks again Matt J. Im going to accept this, but could I ask something first (feel free to tell me to raise a new topic!)
You suggested using this:
D=pdist2([x,y],[x,y],'city','Smallest',2);
D(1,:)=[];
d=median(D(:));
which I have never come across before - but seems to be exactly what I need!
So if I wanted to have a seperate median for x and y distances, is this possible?
In the example below, Im trying to see if there is always a pattern to how D is calculated i.e. is it always top left and next point below?
x1 =
41.5535
43.5383
168.6390
170.5130
y1 =
51.2574
178.2441
52.0028
178.9971
D =
0 0 0 0
127.8308 127.7277 127.8308 127.7277
So if I wanted to have a seperate median for x and y distances, is this possible?
If you know a fairly tight upper bound on the distance of the points from their grid lines (e.g., 10 pixels) then you can do as below,
dx=dmedian(x);
dy=dmedian(y);
function d=dmedian(u)
D=abs(u(:)-u(:)');
D(D<10)=inf;
d=median(min(D));
end
In the example below, Im trying to see if there is always a pattern to how D is calculated i.e. is it always top left and next point below?
No, the second row of D is just the distance from each (x,y) to its nearest neighbor, whichever that happens to be.
Thanks Matt, it all works beautifully!
Spurious spots removed!
Can even get the angle

Sign in to comment.

More Answers (1)

Matt J
Matt J on 13 Oct 2023
Edited: Matt J on 13 Oct 2023
x =[3.9988
5.4914
7.3364
130.3843
132.5535
134.5383
257.6364
259.6390
261.5130
385.1154
386.9360
388.7871];
y =[76.5058
203.4980
330.4643
77.1741
204.2574
331.2441
77.8253
205.0028
331.9971
78.8457
205.8598
332.6533];
scatter(x,y)
[~,~,~,Gx,Gy]=histcounts2(x,y,[4,3]);
xl=splitapply(@mean,x,Gx);
yl=splitapply(@mean,y,Gy);
xline(xl,'r--'); yline(yl,'r--')

7 Comments

Hi matt, thanks, but does this assume you know the [4,3]. In reality I wont
Matt J
Matt J on 13 Oct 2023
Edited: Matt J on 13 Oct 2023
It assumes that, but there are a number of different options for specifying the binning which you will see in the doc for histcounts2. The one that applies will depend on what info you have. For example, maybe you know that the (x,y) are always separated by at least 50.
Here's a morphological way you can find the number of rows and columns of points from the original binarized image:
load Image
coarsify=@(I) imdilate(cummax(I,2),ones(5,1));
R=coarsify(Image);
C=coarsify(Image')';
rows=bwconncomp(R).NumObjects
rows = 3
columns=bwconncomp(C).NumObjects
columns = 4
immontage({Image,R,C},'Bor',[15,15],'Size',[1,3],'Back','r');
Hi matt, wow that is beautiful and absolutely fantastic! I have some questions if thats O.K
1: Your coarsify function, what exactly does that do (in simplistic terms) , just "elongate" in 1D?
2: So I've copied your code as below:
%%% Draw Grid if user wants -----
%Calc number of discrete Rows and Cols
coarsify=@(IM) imdilate(cummax(IM,2),ones(5,1)); %Matt J
R=coarsify(I); % My Image is I
C=coarsify(I')';
rows=bwconncomp(R).NumObjects
columns=bwconncomp(C).NumObjects
immontage({I,R,C},'Bor',[2,2],'Size',[1,3],'Back','r');
[~,~,~,Gx,Gy]=histcounts2(x1,y1,[columns,rows]);
xl=splitapply(@mean,x1,Gx);
yl=splitapply(@mean,y1,Gy);
xline(ax,xl,'y--'); yline(ax,yl,'y--')
But its not counting the number of rows and columns correctly - I can't see my mistake
rows =
1
columns =
1
And this is my montage and final image with lines
Also, I do know the separation but in reality there is some jitter (as my imaging system has distortion) and I also do pick up a few spurious spots that are'nt part of the grid
Thanks
Jason
I think I've realised why the count is wrong - bwconncomp(R) requires a binary image and not 12 bit tiff!
Problem solved, then? If so, please Accept-click the answer.
I think you could also use kmeans() to count the number of rows and column.

Sign in to comment.

Products

Release

R2022b

Asked:

on 13 Oct 2023

Commented:

on 16 Oct 2023

Community Treasure Hunt

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

Start Hunting!