user2368870
user2368870

Reputation: 471

Grid detection in matlab

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

Upvotes: 15

Views: 7983

Answers (2)

Amro
Amro

Reputation: 124563

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

Upvotes: 28

bla
bla

Reputation: 26069

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...

Upvotes: 41

Related Questions