Trying to determine locations of markers in image

I'm trying to obtain the pixel coordinates of the dot pattern image data that is stored in the attached file; I'm using this image to spatially calibrate my camera image. Is there a way to automate the detection of these dots? Thanks in advance for any guidance.

5 Kommentare

What 'markers' are you referring to?
% type('CalImage_Grayscale.txt')
A = readmatrix('CalImage_Grayscale.txt');
figure
surfc(A, EdgeColor='none')
colormap(turbo)
view(65,45)
title('Surface Plot')
colorbar
figure
contourf(A)
colormap(turbo)
grid
title('''contourf'' Plot')
figure
imshow(A)
title('''imshow Plot')
figure
surf(A, EdgeColor='none')
colormap(turbo)
view(0,90)
axis('tight')
title('Surface Plot (Top View)')
colorbar
.
fid = fopen('CalImage_Grayscale.txt','r');
data = textscan(fid,'');
fclose(fid);
data = cell2mat(data);
imagesc(data)
MBP
MBP am 18 Jul. 2025
Bearbeitet: MBP am 18 Jul. 2025
The image shows a plate with dots. The dots are a known distance apart, which allows me to convert the image from pixels to units of distance. The 'markers' I'm referring to are the dots on the plate (as seen when using the imshow or imagesc commands). If I can get the pixel location of these dots, I can use this information to convert my images to spatial coordinates. I hope this clarifies things. Thanks!
Is the projection unequal? That is, is the distance between dots on (say) the lower left corner different from the distance between dots (say) near the upper right corner? If the distances are always the same, then you only need to locate a small number of dots in order to calculate the distance between pixels. If the distances are not always the same but the change is linear, then you only need to calculate based on a small number of locations. If, however, the projection is non-linear then the task becomes more difficult.
MBP
MBP am 18 Jul. 2025

The projections are equal... So, you're right, if I can get a small subset of dots that will be sufficient. I just need an automated way to do that rather than a manual method using, say ginput, to select the dot locations.

Melden Sie sich an, um zu kommentieren.

 Akzeptierte Antwort

hello
maybe this ? not perfect but you may refine it and get as much dots as we / you can
% Read the grayscale image
img = readmatrix('CalImage_Grayscale.txt');
figure
imshow(img);
% Use adaptthresh to determine threshold to use in binarization operation.
T = adaptthresh(img, 0.3);
% Threshold the image to create a binary mask
binaryMask = imbinarize(img,T);
figure
imshow(binaryMask);
% Remove noise , small (and large) objects
cleanMask = bwareafilt(binaryMask, [5, 20]); % Keep objects with area between xx and yy pixels
figure
imshow(cleanMask);
% Label connected components (dots)
[labeledImage, numDots] = bwlabel(cleanMask);
% Display results
figure
imshow(img); hold on;
stats = regionprops(labeledImage, 'Centroid');
for k = 1:numDots
centroid = stats(k).Centroid;
plot(centroid(1), centroid(2), 'r*', 'MarkerSize', 10); % Mark dots
end
title(['Detected Dots: ', num2str(numDots)]);
hold off;

4 Kommentare

a bit for my own fun, I tried a "no image processing Tbx" solution
here I extract some isoclines , find out which ones are almost circular and within a certain range of radius (r2 = squared radius) and get the centroid
is not perfect either , so up to you to figure out it that help you (not really sure)
A = readmatrix('CalImage_Grayscale.txt');
figure
imshow(A)
title('''imshow Plot')
hold on
% extract outer isocline
level = (0.2:0.1:0.6);
[C,h] = contour(A,level);
[m,n] = size(C);
for ii = 1:numel(level)
ind = find(C(1,:)==level(ii)); % index of beginning of each isocline data in C
ind = [ind n+1]; % add end (+1)
for k = 1:numel(ind)-1
xc = C(1,ind(k)+1:ind(k+1)-1);
yc = C(2,ind(k)+1:ind(k+1)-1);
% centroid
Xce = mean(xc);
Yce = mean(yc);
% check if circle
r2 = (xc-Xce).^2+(yc-Yce).^2;
% check if peak (and not local minimum)
val = interp2(A,Xce,Yce);
if val>level(1) && (max(r2)-min(r2))/mean(r2)<1.2 && (mean(r2)> 0.4) && (mean(r2) < 10)
plot(xc,yc,'m');
plot(Xce,Yce,'+r','markersize',15);
end
end
end
hold off
with some high pass filtering now :
A = readmatrix('CalImage_Grayscale.txt');
Af = fft2(A); % compute FFT of the grey image
A1=fftshift(Af); % frequency scaling
% Gaussian Filter Response Calculation
[m, n]=size(A); % image size
sigma=10; % filter size parameter
X=0:n-1;
Y=0:m-1;
[X, Y]=meshgrid(X,Y);
Cx=0.5*n;
Cy=0.5*m;
Lo=exp(-((X-Cx).^2+(Y-Cy).^2)./(2*sigma).^2);
Hi=1-Lo; % High pass filter=1-low pass filter
% Filtered image=ifft(filter response*fft(original image))
K=A1.*Hi;
K1=ifftshift(K);
B=abs(ifft2(K1));
%----visualizing the results----------------------------------------------
figure
imshow(A);
title('original image','fontsize',14)
figure
B = B - min(B(:));
B = B./max(B(:));
imshow(B)
title('High pass filtered image','fontsize',14)
hold on
%---multi level isoclines and centroids computation
level = (0.1:0.1:0.4);
[C,h] = contour(B,level);
[m,n] = size(C);
for ii = 1:numel(level)
ind = find(C(1,:)==level(ii)); % index of beginning of each isocline data in C
ind = [ind n+1]; % add end (+1)
for k = 1:numel(ind)-1
xc = C(1,ind(k)+1:ind(k+1)-1);
yc = C(2,ind(k)+1:ind(k+1)-1);
% centroid
Xce = mean(xc);
Yce = mean(yc);
% check if circle
r2 = (xc-Xce).^2+(yc-Yce).^2;
% check if peak (and not local minimum)
val = interp2(A,Xce,Yce);
if val>level(1) && (max(r2)-min(r2))/mean(r2)<1.2 && (mean(r2)> 0.4) && (mean(r2) < 10)
mr2(k) = mean(r2);
% plot(xc,yc,'m');
plot(Xce,Yce,'+r','markersize',15);
end
end
end
hold off
MBP
MBP am 18 Jul. 2025
I really like the isocline-based detection, and I combined it with some pre-processing from ImageJ to get what I was looking for...thank you Mathieu for your help, and setting me on the right path!
The reason I used ImageJ was that I was able to get rid of the horizontal lines that are showing up in my image using the gray morphology option followed by the using the image calculator to subtract out the original and processed images (somewhat similar to what you did using the bwareafilt command). The resulting "cleaned-up" image I processed using the isocline-based technique and that gave me great results.
Thanks again!
as always, my pleasure !

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (1)

Image Analyst
Image Analyst am 21 Jul. 2025

0 Stimmen

I recommend you use the code in the other answer to get the "cleanMask" binary image above. Then use regionprops to get the centroids, or weighted centroids, of the dots. The contour and looping stuff is overly complicated and not needed, when regionprops gives you the centroids directly (but it requires the Image Processing Toolbox).
Then for the next step needed for calibration you can use kmeans to get the mean rows and columns of each linear series of dot. If the image is tilted, you might then use that to get the angle of tile and then use imrotate to square it up with the image edges. Then you can sum the binary image vertically and horizontally with sum() to get a 1-D horizontal or vertical profile. Then you can use regionprops to get the row and column numbers of each line of dots. Knowing that you can complete your calibration in terms of millimeters (or whatever) per pixel.

Produkte

Version

R2024b

Gefragt:

MBP
am 17 Jul. 2025

Beantwortet:

am 21 Jul. 2025

Community Treasure Hunt

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

Start Hunting!

Translated by