Hough Line Transform

Question on HoughLineTransform got me started on this.

The HoughLineTransform turns straight line segments in an input matrix into into points in an output matrix. The bright spots in the output matrix represent an angle and distance from center of a line. The output matrix represents the line containing the segment (the end point information is mostly lost).

In the JSL below, the input matrix is 100x100, a field of zeros with ones where the lines are. The output matrix dimension is determined by the nAngle and nRadius parameters; the columns represent the angle of the line and the rows are distance from center. The gen function is called for each change of the handles in the left-hand graph. Gen re-manufactures the mat matrix (100x100) and calls the transform. Gen then rebuilds a bitmap with the transform's output and updates the right-hand picture. Most of the code is just window dressing; the call to the transform is near the middle.

`mx = [10 10 90 90 20 80]; // starter pointsmy = [10 90 10 90 10 90];mat = J( 100, 100, 0 ); // input to hough line transformNew Window( "Hough Line Transform", H List Box( radio = Radio Box( {"1", "2", "3"}, gen() ), // sometimes you want to see just one line Graph Box( // left side is just a GUI to position 3 lines Frame Size( 400, 400 ), Y Scale( -10, 110 ), X Scale( -10, 110 ), xaxis( Add Ref Line( 50, "Dashed", blue, "", 1 ), showmajorticks( 0 ), showminorticks( 0 ), showlabels( 0 ) ), xname( "drag the square handles" ), yaxis( Add Ref Line( 50, "Dashed", blue, "", 1 ), showmajorticks( 0 ), showminorticks( 0 ), showlabels( 0 ) ), yname( "" ),  // when the 6 handles are moved, they capture their location AND generate results Handle( mx, my, mx = clamp( x ); my = clamp( y ); gen(); ); Handle( mx, my, mx = clamp( x ); my = clamp( y ); gen(); ); Line( mx[1 :: 2], my[1 :: 2] ); // draw the lines in the GUI text({(mx+mx)/2,(my+my)/2},char(mod(360+180*atan(my-my,mx-mx)/pi(),180),4));// label angle If( radio << get > 1, Handle( mx, my, mx = clamp( x ); my = clamp( y ); gen(); ); Handle( mx, my, mx = clamp( x ); my = clamp( y ); gen(); ); Line( mx[3 :: 4], my[3 :: 4] ); text({(mx+mx)/2,(my+my)/2},char(mod(360+180*atan(my-my,mx-mx)/pi(),180),4));// label angle ); If( radio << get > 2, Handle( mx, my, mx = clamp( x ); my = clamp( y ); gen(); ); Handle( mx, my, mx = clamp( x ); my = clamp( y ); gen(); ); Line( mx[5 :: 6], my[5 :: 6] ); text({(mx+mx)/2,(my+my)/2},char(mod(360+180*atan(my-my,mx-mx)/pi(),180),4));// label angle ); ),  // reserve a place to display results H List Box( V List Box( imgholder = Border Box( Left( 5 ), Right( 5 ), top( 5 ), bottom( 5 ), Text Box( "drag handles" ) ), H Center Box( anglebox = Text Box( "angle" ) ) ), V Center Box( Text Box( "Distance from black line to blue center", <<rotatetext( "left" ) ) ) ) ), hcenterbox(textbox("The blue cross hair and the nearest point on the line (defined by the black line segment) form a distance. When the blue cross hair is on the line defined by the black segment, the red cross hair is centered vertically (zero distance).The black segment's slope forms the angle. The displayed angle is for the point identified by the red cross hair, which is on the brightest point. ",<<setwrap(700))));// keep the handles in range so the drawline function is happyclamp = Function( {t}, Max( 1, Min( 99, t ) ));//// the three lines in the gui generate three lines in mat// then the transform runs on mat and the result updates//gen = Function( {}, {xy, r, c}, mat[0, 0] = 0; // reset mat drawline( mx[1 :: 2], my[1 :: 2] ); // add lines to mat If( radio << get > 1, drawline( mx[3 :: 4], my[3 :: 4] ) ); If( radio << get > 2, drawline( mx[5 :: 6], my[5 :: 6] ) ); // run hough... result = Hough Line Transform( mat, nangle( 200 ), nradius( 200 ) );// just to make result matrix square // normalize... result = result / Max( result ); result = result^.5; // boost brightness ResultRed = result; If( 1,//radio << get == 1, xy = Loc Max( result ); // maximum bright point in transform r = Floor( (xy - 1) / N Cols( result ) ) + 1; c = xy - (r - 1) * N Cols( result ); anglebox << settext( "Black line angle "||Char( 180 * c / N Cols( result ), 4 ) || "°" ); ResultRed[r, 0] = .5; ResultRed[0, c] = .5; ); // update the results img = New Image( "rgb", {resultRed, result, result} ); // gray scale bitmap from result img << scale( 2 ); // bigger (imgholder << child) << delete; // swap out old imgholder << append( img ); // for new);// taken from scripting index example, a fast drawline in a matrixdrawline = Function( {mx, my}, {dx = mx - mx, dy = my - my, adx = Abs( dx ), ady = Abs( dy ), m, b}, If( adx > ady, xx = Round( mx ) :: Round( mx ); m = dy / dx; b = my - m * mx; yy = Round( xx * m + b ); , yy = Round( my ) :: Round( my ); m = dx / dy; b = mx - m * my; xx = Round( yy * m + b ); ); singleindex = (N Row( mat ) - yy) * N Col( mat ) + xx; Try( mat[singleindex] = 1, 0 ); /* catch indexing errors and ignore the problems */);gen(); // do the first round` The JSL creates a GUI to help understand the Hough Line Transform

update 25Jun2018: repair comment...gen updates the right-hand picture

Article Labels
Article Tags
1 Comment Craige_Hales
Staff (Retired)

@dqr2 posted an addin that explores the Hough Transform in a different way; it has an animation button that illustrates where the sine waves come from. It does its work without using the builtin JSL function.