How Can I recognize/detect the Needle/hand in the below images?

10 views (last 30 days)
Hi I am very new to image processing and struggling to detect the Needle in the below images. Anybody who can help me to segment the Needle. Keep in mind that it moves as in sped meter. We can use multiple stream to find out the needle but I don't know how to do it?
many many thanks in advance for your time

Accepted Answer

Cedric
Cedric on 29 Jul 2015
Edited: Cedric on 1 Aug 2015
ImageAnalyst will certainly provide a fancy solution (like a bwGetBlobAngle from his FEX ;-)), but (waiting for him to hit the forum) here is one way to do it "by hand" (I did that during a short pause, so all should be optimized).
=== VERSION 07/31, 2 =======================================================
Reading another post by ImageAnalyst, I realize that I should learn more about NORMXCORR2, but here is a version based on a 2D convolution for matching the "200" in the indicator. I chose it because it should never be hidden by the needle. From the center of the match, we get the center of rotation of the needle by adding a fixed offset. I generated a shifted 3rd image to test the approach. I attached the shifted image, the code and a template file (for the match) to this answer, below.
clear ; close all ; clc ;
display = true ; % True for debug, false for processing
% large number of files.
% - Parameters associated with the needle
originAngle = 4 ; % Used to compensate for the image tilt.
needleLength = 400 ;
% - Parameters associated with the curve around the needle center.
curveRadius = 200 ;
kernelSize = 30 ; % Kernel size for 1D conv along curve.
% - Parameters associated with the window that must frame the "200"
% on the indicator.
w200Center = [1000, 1860] ; % Approx. center of window "200".
w200OffsetNC = [290, 180] ; % Approx. offset to needle center.
w200width = 800 ;
w200Height = 600 ;
w200MatFile = 'w200_threshold08_template.mat' ;
% - Load/build '200' template for 2D convolution. Prepare for convolution
% purpose: remap 0 to -1 and 1 to 1.
loaded = load( w200MatFile ) ;
w200Template = -1 + 2 * rot90( double( loaded.thresh08_200 ), 2 ) ;
% - Get listing of jpeg files.
D_jpg = dir( '*.jpg' ) ;
nFiles = numel( D_jpg ) ;
% - Prealloc(s), initialize.
needleAngles = zeros( nFiles, 1 ) ;
w200RowBnd = round( w200Center(1) + 0.5*[-w200Height, w200Height] ) ;
w200ColBnd = round( w200Center(2) + 0.5*[-w200width, w200width] ) ;
for fId = 1 : nFiles
% Initialize angle with NaN (=failed).
needleAngles(fId) = NaN ;
% - Read and "flatten" image.
I_flat = sum( imread( D_jpg(fId).name ), 3 ) ;
tic ;
% - Extract window "200", threshold @ 80% for comparison with template.
w200 = I_flat(w200RowBnd(1):w200RowBnd(2), w200ColBnd(1):w200ColBnd(2)) ;
w200 = w200 > 0.8 * max( w200(:) ) ;
% - Match template in window.
match = conv2( double( w200 ), w200Template, 'same' ) ;
[r, c] = find( match == max( match(:) ) ) ;
if numel( r ) > 1
fprintf( '%-20s: failed to match "200" template.\n', D_jpg(fId).name ) ;
if ~display
continue ; % Loop back, leaving NaN angle value.
end
end
matchCenter(1) = r(1) ;
matchCenter(2) = c(1) ;
% - Compute needle center.
needleCenter = [w200RowBnd(1) + matchCenter(1) + w200OffsetNC(1), ...
w200ColBnd(1) + matchCenter(2) + w200OffsetNC(2)] ;
% - Build curve around indicator center, match needle origin and
% rotation direction.
curveRowIds = round( needleCenter(1) - curveRadius * cos( 0:0.02:2*pi )) ;
curveColIds = round( needleCenter(2) + curveRadius * sin( 0:0.02:2*pi )) ;
% - Extract "signal" or sample along curve, perform 1D convolution.
% Manage circularity by tripling sample and working on middle part
% (crappy, must be overworked).
curveSample = I_flat( sub2ind( size(I_flat), curveRowIds, curveColIds )) ;
sampleConv = conv( repmat( curveSample, 1, 3 ), ...
ones( 1, kernelSize )/kernelSize, 'same' ) ;
nSamples = numel( curveSample ) ;
sampleConv = sampleConv(nSamples + (1:nSamples)) ;
needleAngles(fId) = -originAngle + ...
360/nSamples * find( sampleConv == max(sampleConv), 1 ) ;
fprintf( '%-20s: processing time = %.2fs.\n', D_jpg(fId).name, toc ) ;
if display
figure() ;
set( gcf, 'Units', 'normalized', 'Position', [0.1,0.1,0.8,0.8] ) ;
% - Plot image, window "200", curve, center, needle.
subplot( 2, 2, 1 ) ; hold on ;
imshow( I_flat/max(I_flat(:)) ) ;
plot( needleCenter(2), needleCenter(1), 'xb', curveColIds, curveRowIds, 'r' ) ;
plot( [reshape( [w200ColBnd; w200ColBnd], 1, [] ), w200ColBnd(1)], ...
[w200RowBnd, fliplr(w200RowBnd), w200RowBnd(1)], 'g' ) ;
needleTip = [needleCenter(1) - cosd( needleAngles(fId)+originAngle ) * needleLength, ...
needleCenter(2) + sind( needleAngles(fId)+originAngle ) * needleLength] ;
plot( [needleCenter(2), needleTip(2)], [needleCenter(1), needleTip(1)], ...
'b', 'LineWidth', 3 ) ;
% - Plot window "200" content and match center.
subplot( 2, 2, 2 ) ; hold on ;
imshow( w200 ) ;
plot( matchCenter(2), matchCenter(1), 'rx', 'LineWidth', 3, 'MarkerSize', 10 ) ;
% - Plot "signal" along curve, convolution, angle.
subplot( 2, 2, 3 ) ; hold on ; grid on ;
title( D_jpg(fId).name ) ;
angleSample = 0:360/(nSamples-1):360 ;
plot( angleSample, curveSample, 'b', angleSample, sampleConv, 'r' ) ;
line( [needleAngles(fId) needleAngles(fId)], ylim, 'Color', [0, 1, 0] ) ;
% - Text: angle, ..
subplot( 2, 2, 4 ) ; hold on ;
set(gca, 'Visible', 'off' ) ;
text( 0.1, 0.5 , sprintf( 'Angle = %.1f°', needleAngles(fId)), 'FontSize', 20 ) ;
end
end
With that we get:
And the 3rd, shifted image:
Note: I moved my first two answers (irrelevant now) at the end of my first comment below, for reference.
  20 Comments
Cedric
Cedric on 3 Aug 2015
Edited: Cedric on 3 Aug 2015
My pleasure! If you go for the green band approach, one way to get the center without performing a fit, is to define 3 windows that capture respectively the leftmost, the middle, and the topmost regions of the green band. Then you compute the center of mass of true pixels (the detection of the green band is likely to produce an array of logicals) in the three regions, and you get 3 points that characterize the arc of circle. The computation of the center of this circle based on these 3 points is direct (no fit of a model or anything).
wasiqbarazai
wasiqbarazai on 3 Aug 2015
yes, but I am satisfied with your previous approach as it is more generic to all types of Dials. Also, in different light/reflections dynamics, the green colour detection/filter may be false. for example, in yellow light, the green clour may change....similarly, for very bright and so on.... Also, i need to apply simoultanously for different colours and kind of dials. So happy with previous approach. I will let you know if needed your help at any point. Thanks again

Sign in to comment.

More Answers (0)

Community Treasure Hunt

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

Start Hunting!