Bài viết này chia sẻ cách tìm đường thẳng trong ảnh bằng hàm HoughLines. Công dụng là tìm đường thẳng trong ảnh mặc dù có thể bị đứt đoạn.
Trong hình học thì đường thẳng có phương trình:
y = m.x + c
hoặc là
ρ = x.cosθ + y.sinθ (ρ đọc là ro, còn đọc θ là theta nhé)
Với ρ là khoảng cách từ đường thẳng tới gốc tọa độ, còn θ là góc giữa trục hoành và đoạn thẳng ngắn nhất nối tới gốc tọa độ (đơn vị là radian).
Hình minh họa trong hệ tọa độ Đề Cát
Hình minh họa sử dụng trong OpenCV
Lưu ý: Hệ tọa độ trên máy tính có gốc tọa độ ở góc trên bên trái
Có 2 cách để xác định 1 đường thẳng, người ta chọn cách thứ 2 vì chỉ cần 2 tham số (ρ, θ) tiện cho tính toán hơn. Vì θ được tính bằng radian nên có giá trị trong khoảng [0;π] (hay là [0;3.14]). Khi θ bằng 0 hoặc bằng 3.14 thì đường thẳng dựng đứng, còn θ bằng 1.57 (π/2) là nằm ngang.
MÔ TẢ CÁCH HOẠT ĐỘNG CỦA THUẬT TOÁN
Vì mỗi đường thẳng được xác dịnh bởi 2 giá trị (ρ, θ) nên thuật toán tạo 1 mảng 2 chiều. Dòng ứng với ρ và cột ứng với θ, kích thước của mảng phụ thuộc vào bạn chọn, và tất nhiên là mảng càng lớn thì càng chính xác và tính toán càng lâu, còn mảng nhỏ thì nhanh hơn nhưng không chính xác bằng.
Khi sử dụng người dùng sẽ truyền giá trị ρ và θ họ mong muốn. Thuật toán sẽ vẽ ρ x θ đường thẳng trên ảnh, với mỗi đường thẳng thuật toán đếm số pixel nằm trên đường thẳng đó, cứ mỗi pixel tìm thấy thì cộng thêm giá trị vào ô ứng với (ρ, θ).
Trong ảnh trên: bên trái là các điểm trong ảnh, bên phải là mảng 2 chiều
Sau quá trình tính toán thì mỗi ô sẽ có giá trị là số pixel nằm trên đường thẳng đó.
SỬ DỤNG HÀM HOUGHLINES TRONG OPENCV
Hàm houghlines() sử dụng ảnh nhị phân để xử lý, bạn cần phân ngưỡng trước khi gọi hàm.
1 |
void HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0 ) |
- image – ảnh input nhị phân (ảnh có thể bị thay đổi khi tính toán)
- lines – Output là vector chứa các đường thẳng. Mỗi đường thẳng chứa 2 giá trị (ρ, θ)
- rho – Khoảng cách của các đường thẳng tính bằng pixels
- theta – Khoảng cách góc của các đường thẳng tính bằng radians
- threshold – Số lần được tìm thấy phải vượt qua ngưỡng mới lấy
- srn – Dùng cho multi-scale
- stn – Cũng dùng cho multi-scale
Ảnh gốc
Biến đổi ảnh bằng hàm Canny
Sau đó tìm đường thẳng và vẽ
Thông thường người ta sẽ truyền rho = 1px, theta = 3.14/180 (rad).
Hàm PROBABILISTIC HOUGH
Hàm HoughLines() phải tính toán quá nhiều để tìm đường thẳng, còn Probabilistic Hough ít tính toán hơn. Nó không kiểm tra tất cả các pixel mà chỉ lấy 1 số cụm pixel vừa đủ để tìm ra đường thẳng.
Nhược điểm thứ 2 là HoughLines() không xác định được điểm đầu và điểm cuối của đoạn thẳng. Do đó chúng ta dùng HoughLinesP() để khắc phục nhược điểm
Thuật toán này có thêm 2 tham số nữa:
- minLineLength – Độ dài tối thiểu của đường thẳng
- maxLineGap – Nếu 2 đường thẳng có khoảng đứt gãy ở giữa ngắn hơn maxLineGap thì được xem là 1 đường thẳng
Source code
Các bạn clone source về (nhớ checkout sub modules OpenCV). Sau đó chạy LineFinder.sln vì trong source code có nhiều example khác