Automatic Dial Reader
This is an explanation of how I created an automatic dial
reader with Matlab and a webcam.
First I took a picture of the dial indicator.

Then I converted it to a single color. (This is necessary
for the contour extraction).

After that, I extracted the contours. There are a fair
number of contour extraction methods, but I used the Matlab
default: Sobel. It seemed to have the best performance for
my needs. I wanted it to extract only the most important
information, i.e. the longest lines.

After that, I thickened the image in order to increase the
weight of the lines, and thus increase the significance of
the two long lines that form the edge of the need

Finally, I performed a Hough transform on the image,
filtering all but the longest two lines. These two
remaining lines were (usually) the left- and right-hand
side of the needle. Where the lines intersect is where the
needle points.

This is the Matlab code. Notice, I used the Hough algorithm
from Matlab. This is only available on Matlab 7 SP2 and
later. If you do not have this, you can use this
Hough transformation code
(although it's not quite
as nice) or download a free image analysis
toolbox.
function
m=dial_reader(Image,lightThresh)
%hough_analysis performs a hough transformation on each
image in a movie
%file. The two longest lines are then stored in (x1,y1) and
(x2,y2)
%coordinate fashion in cal_lines.
global circle rectCrop BandWect
thickener = strel('square',4);
cropImage=imcrop(Image,rectCrop);
% BandW=uint8(im2bw(Image,lightThresh-0.05));
BandW=uint8(im2bw(cropImage,lightThresh-0.05));
[BandWe,thresh]=edge(BandW,'sobel');
BandWec=BandWe.*imcrop(circle,rectCrop);
% BandWec=BandWe.*circle;
BandWect=imdilate(BandWec,thickener);
% image(BandW);
% drawnow
imagesc(BandWect);
colormap(jet)
drawnow
[TransH,theta,rho]=hough(BandWect);
peaksH=houghpeaks(TransH,2,'Threshold',0.3);
linesH=houghlines(BandWect, theta, rho,
peaksH,'MinLength',150,'Fillgap',20);
if length(linesH) < 2 %If we've only found one line for
some reason or another.
% m=0
else
[u1,v1]=linesH.point1;
[u2,v2]=linesH.point2;
cal_lines(1:4, 1)=[[u1(1) u2(1)] [u1(2) u2(2)]];
cal_lines(1:4, 2)=[[v1(1) v2(1)] [v1(2) v2(2)]];
v=cal_lines(1:4,1);
w=cal_lines(1:4,2);
a1 = v(4) - v(3);
b1 = v(1) - v(2);
c1 = v(1)*v(4) - v(2)*v(3);
a2 = w(4) - w(3);
b2 = w(1) - w(2);
c2 = w(1)*w(4) - w(2)*w(3);
if (-a1*b2+b1*a2)==0
m=1/0;
%Does nothing. This triggers an error and a catch in the
calling
%loop.
else
x1 = (-b2*c1+c2*b1)/(-a1*b2+b1*a2);
y1 = (-a1*c2+c1*a2)/(-a1*b2+b1*a2);
m=[x1 y1];
% line(cal_lines(1:2,1),cal_lines(3:4,1),'Color',[0 0 1])
%Blue line
% line(cal_lines(1:2,2),cal_lines(3:4,2),'Color',[1 0 0])
%Red line
hold on;
for k = 1:length(linesH)
xy = [linesH(k).point1; linesH(k).point2];
plot(xy(:,1),xy(:,2),'LineWidth',2,'Color','magenta');
% Plot beginnings and ends of lines
plot(xy(1,1),xy(1,2),'x','LineWidth',2,'Color','yellow');
plot(xy(2,1),xy(2,2),'x','LineWidth',2,'Color','red');
end
plot(x1,y1,'g-x');
hold off;
end
drawnow
end
save calibration_transforms.mat cal_lines rates