📜 ⬆️ ⬇️

Implementation of the Hough Transform algorithm (Hough Transform) (+ work visualization)

Not so long ago I wrote my first article , thanks to which I became a full-fledged habrazhitel. But nevertheless, the method proposed by me calibrates with a significant error of 5-7%; it is foolish to lose a chance at such a place for a successful result. Therefore, it was decided to implement the method published by Vasyutka in this topic, to which ZlodeiBaal sent me , for which he thanks. To implement the idea, I use the .NET cross-platform wrapper over OpenCV - EMGU.

The first thing I suggest is to see how it works:



The visualization process itself lasted about 6 to 8 hours, since a small step was taken for θ , and everything was done for one time.
')
It is assumed that the reader is familiar with the algorithm. If not, then you can do it here. “Digital Image Processing” R. Gonzalez. R. Woods. 3rd Edition, 2012 pages 848 - 854 or “Digital Image Processing” R. Gonzalez. R. Woods. 2005 Chapter 10. The books have written comprehensive information for writing the program.

Post processing


First of all, you need to visualize the direct, you can do this using three operations:

CvInvoke.GaussianBlur(gray, gray, new Size(3, 3), 0, 1, BorderType.Default); CvInvoke.Sobel(gray, gray, DepthType.Default, 0, 1, 3); CvInvoke.Canny(gray, gray, 70, 130); 

Smoothing CvInvoke.GaussianBlur removes unnecessary details, the Sobel operator CvInvoke.Sobel with a multiplication factor of Kx = 0 and Ky = 1 visualizes only horizontal lines, and the operator Kenny CvInvoke.Canny finally highlights the boundaries and binarizes the image.

Determining the boundaries for ρ and θ


 public double SomeMethode(Image<Gray, byte> gray) { int D = (int)(Math.Sqrt(gray.Width * gray.Width + gray.Height * gray.Height)); Image<Gray, int> houghSpace = new Image<Gray, int>(181, ((int)(1.414213562 * D) * 2) + 1); } 

houghSpace is the accumulator of values, the range of which is in θ [-90 °, 90 °], and in ρ is [-sqrt (2) * D, sqrt (2) * D] - where D is the distance between two angles located diagonally.

Cache the value of angles


It's simple, we cache the value of sinθ and cosθ. Where rad is the step of filling the table, in the video it was taken 20 times smaller than (Math.PI / 180).

 private double[,] CreateTable() { double[,] table = new double[2, 181]; // 0 - cos, 1 - sin; double rad = (Math.PI / 180); double theta = rad * -90; for (int i = 0; i < 181; i++) { table[0, i] = Math.Cos(theta); table[1, i] = Math.Sin(theta); theta += rad; } return table; } 

HotPoint Findings


When finding the maximum value of the battery, the i-th value is recorded to find the angle.

 public double SomeMethode(Image<Gray, byte> gray) { int D = (int)(Math.Sqrt(gray.Width * gray.Width + gray.Height * gray.Height)); Image<Gray, int> houghSpace = new Image<Gray, int>(181, ((int)(1.414213562 * D) * 2) + 1); int xpoint = 0; double maxT = 0; double[,] table = CreateTable(); for (int xi = 0; xi < gray.Width; xi++) for (int yi = 0; yi < gray.Height; yi++) { if (gray[yi, xi].Intensity == 0) continue; for (int i = 0; i < 181; i++) { int rho = (int)((xi * table[0, i] + yi * table[1, i])) + (houghSpace.Height / 2); Gray g = new Gray(houghSpace[rho, i].Intensity + 1); if (g.Intensity > maxT) { maxT = g.Intensity; xpoint = i; } houghSpace [rho, i] = g; } } } 


Rotation angle calculation


  double thetaHotPoint = ((Math.PI / 180) * -90d) + (Math.PI / 180) * xpoint; return (90 - Math.Abs(thetaHotPoint) * (180 / Math.PI)) * (thetaHotPoint< 0 ? -1 : 1); 

Thus, we have obtained the angle by which it is necessary to transform the image so that the longest segment has a horizontal position.

Source: https://habr.com/ru/post/263493/


All Articles