15

I have a grid in a binary image (may be rotated). How can I know approximate formula for that grid using MATLAB?

Example image:


(source: sjtu.edu.cn)

Sometimes these black dots are missing, so I need formula or ‘a way’ to estimate possible center of these black dots.

I have tried by using regionprops, it help me to get center of these exist black dots, but no idea if black dots a missing

clear all
im = imread('print5.jpg');
im = im2bw(im);
[sy,sx] = size(im);
im = imcomplement(im);
im(150:200,100:150) = 0; % let some dots missing!
im = imclearborder(im);
st = regionprops(im, 'Centroid');

imshow(im) hold on;
for j = 1:numel(st)
    px = round(st(j).Centroid(1,1));
    py = round(st(j).Centroid(1,2));
    plot(px,py,'b+')
end
7
  • 1
    Try looking ad the frequency content: fft2 the grid is very regular, you should be able to spot peaks in the frequency domain. Commented May 10, 2013 at 6:32
  • 5
    If you edit all the information from the above comments into your question you should be able to get it re-opened. Commented May 10, 2013 at 7:20
  • 5
    wow, this attracted a lot of downvotes in a short amount of time. I understand why it was closed, but did it really deserve -20 downvotes... Commented May 10, 2013 at 7:54
  • 3
    @Amro If you check out the front-page, you'll see that questions haven't been updated in over an hour, that's probably why they're doing it. Usually questions with -3/-4 downvotes are removed from the 'newest questions' section anyway to stop further downvoting I believe, but because of this glitch, this question is still being shown :/ Commented May 10, 2013 at 8:06
  • 3
    I added OP's code and description from comments. That should slow down ppl who downvote blindly. Those who did, please reconsider.. Commented May 10, 2013 at 8:12

2 Answers 2

41

here's a way using fft in 1D over the x and y projection:

First, I'll blur the image a bit to smooth the high freq noise by convolving with a gaussian:

m=double(imread('print5.jpg'));
m=abs(m-max(m(:))); % optional line if you want to look on the black square as "signal"
H=fspecial('gaussian',7,1);
m2=conv2(m,H,'same');

then I'll take the fft of a projection of each axis:

delta=1;
N=size(m,1);
df=1/(N*delta);        % the frequency resolution (df=1/max_T)
f_vector= df*((1:N)-1-N/2);     % frequency vector 

freq_vec=f_vector;
fft_vecx=fftshift(fft(sum(m2)));
fft_vecy=fftshift(fft(sum(m2')));
plot(freq_vec,abs(fft_vecx),freq_vec,abs(fft_vecy))

enter image description here

So we can see both axis yield a peak at 0.07422 which translate to a period of 1/0.07422 pixels or ~ 13.5 pixels.

A better way to get also the angle info is to go 2D, that is:

ml= log( abs( fftshift (fft2(m2)))+1);
imagesc(ml) 
colormap(bone)

enter image description here

and then apply tools such as simple geometry or regionprops if you want, you can get the angle and size of the squares. The size of the square is 1/ the size of the big rotated square on the background ( bit fuzzy because I blurred the image so try to do that without that), and the angle is atan(y/x). The distance between the squares is 1/ the distance between the strong peaks in the center part to the image center.

so if you threshold ml properly image say

 imagesc(ml>11)

you can access the center peaks for that...

yet another approach will be morphological operation on a binary image, for example I threshold the blurred image and shrink objects to points. It removes pixels so that objects without holes shrink to a point:

BW=m2>100;
BW2 = bwmorph(BW,'shrink',Inf);
figure, imshow(BW2)

enter image description here

Then you practically have a one pixel per lattice site grid! so you can feed it to Amro's solution using Hough transform, or analyze it with fft, or fit a block, etc...

Sign up to request clarification or add additional context in comments.

Comments

28

You could apply Hough transform to detect the grid lines. Once we have those you can infer the grid locations and the rotation angle:

%# load image, and process it
img = imread('print5.jpg');
img = imfilter(img, fspecial('gaussian',7,1));
BW = imcomplement(im2bw(img));
BW = imclearborder(BW);
BW(150:200,100:150) = 0;    %# simulate a missing chunk!

%# detect dots centers
st = regionprops(BW, 'Centroid');
c = vertcat(st.Centroid);

%# hough transform, detect peaks, then get lines segments
[H,T,R] = hough(BW);
P  = houghpeaks(H, 25);
L = houghlines(BW, T, R, P);

%# show image with overlayed connected components, their centers + detected lines
I = imoverlay(img, BW, [0.9 0.1 0.1]);
imshow(I, 'InitialMag',200, 'Border','tight'), hold on
line(c(:,1), c(:,2), 'LineStyle','none', 'Marker','+', 'Color','b')
for k = 1:length(L)
    xy = [L(k).point1; L(k).point2];
    plot(xy(:,1), xy(:,2), 'g-', 'LineWidth',2);
end
hold off

(I'm using imoverlay function from the File Exchange)

The result:

grid_lines_overlayed

Here is the accumulator matrix with the peaks corresponding to the lines detected highlighted:

accumulator_peaks


Now we can recover the angle of rotation by computing the mean slope of detected lines, filtered to those in one of the two directions (horizontals or verticals):

%# filter lines to extract almost vertical ones
%# Note that theta range is (-90:89), angle = theta + 90
LL = L( abs([L.theta]) < 30 );

%# compute the mean slope of those lines
slopes = vertcat(LL.point2) - vertcat(LL.point1);
slopes = atan2(slopes(:,2),slopes(:,1));
r = mean(slopes);

%# transform image by applying the inverse of the rotation
tform = maketform('affine', [cos(r) sin(r) 0; -sin(r) cos(r) 0; 0 0 1]);
img_align = imtransform(img, fliptform(tform));
imshow(img_align)

Here is the image rotated back so that the grid is aligned with the xy-axes:

aligned_img

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.