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