субота, 22 травня 2021 р.

Реалізація алгоритму Хафа для прямих ліній в OpenCV

Mathedemo
В OpenCV алгоритм є дві функції які реалізують алгоритм Хафа cv2.HoughLines(Standard Hough Line Transform) i cv.HoughLinesP(Probabilistic Line Transform) з синтаксисом
lines = cv2.HoughLines(img, rho, theta, threshold, None, srn, stn)
де
  • img: Вхідне зображення, може бути як бінарним так і напівтоновим
  • lines: Вектор в якому зберігаються параметри $(r, \theta)$ виявлених прямих ліній. Кожна лінія представлена наборами $(x_1, y_1, x_2, y_2)$, де $(x_1, y_1)$ та $(x_2, y_2)$ - кінцеві точки кожного виявленого відрізка лінії.
  • rho : Роздільна здатність параметру $r$ у пікселях, рекомендується виставити 1 піксель.
  • theta: Роздільна здатність параметру акумулятора $\theta$ у радіанах. Рекомендується перевести у градуси і виставити np.pi/180
  • threshold: Мінімальна кількість перетинів необхідна для того щоб виявити лінію.
  • srn, stn: Параметри, які за замовчуванням дорівнюють нулю.
Проілюструємо використання на штучному зображенні
img = np.zeros((100,100)).astype(np.uint8)
#малюємо дві лінії
cv2.line(img, (10, 10), (60, 70), 255, 3)
cv2.line(img, (90, 10), (90, 70), 255, 3)
# виділяємо краї
img = cv2.Canny(img,50,150)
# знаходимо параметри прямих ліній
lines = cv2.HoughLines(img,1,np.pi/180,50)
copy = cv2.cvtColor(img.copy(),1)
for k in range(lines.shape[0]):
    for rho,theta in lines[k]:
		        #для кожної пари параметрів  rho, theta
						#знаходимо дві точки на прямій лінії 
            a = np.cos(theta)
            b = np.sin(theta)
            x0 = a*rho
            y0 = b*rho
						P=2*max(img.shape)
            x1 = int(x0 + P*(-b))
            y1 = int(y0 + P*(a))
            x2 = int(x0 - P*(-b))
            y2 = int(y0 - P*(a))
            cv2.line(copy,(x1,y1),(x2,y2),(0,255,0),1)
Знаходження прямих ліній функцією cv2.HoughLines
Функція cv2.HoughLines, з параметрами як у прикладі, знайшла сім пар $(r, \theta)$ які визначають лінії, серед яких три лінії (ліворуч) які визначилися помилково. Їх можна було усунути, збільшивши кількість перетинів, але тоді ми би втратили вертикальні лінії.

При додатковій обробці можна добитися покращення результату -- самостійно вилучити зайві лінії, перетворити їх на відрізки і припасувати до розмірів об'єктів.

При великих розмірах зображення, використовують оптимізований ймовірнісний алгоритм Хафа, який розглядає не всі точки зображення, що є затратним, а лише випадкову множину, достатньо велику щоб визначити прямі лінії. Функція cv.HoughLinesP має ті самі параметри, що і функція cv2.HoughLines до яких додаються два нові параметри:

  • minLineLength: Мінімальна кількість точок, які можуть утворювати пряму. Лінії з меншою кількістю точок не виводяться
  • maxLineGap: Максимальний розрив між двома точками лінії щоб сприймати цю лінію як одну а не дві і більше
Як видно з наступного прикладу, при правильному виборі параметрів, ця функція краще виділяє лінії:
img1 = cv2.Canny(img,50,150)
minLineLength = 30
maxLineGap = 20
lines = cv2.HoughLinesP(img1,1,np.pi/180,40,minLineLength,maxLineGap)
copy = cv2.cvtColor(img.copy(),1)
for line in lines:
    x1, y1, x2, y2 = line[0]
    cv2.line(copy, (x1, y1), (x2, y2), (0, 0, 255), 3)
Знаходження прямих ліній функцією cv2.HoughLinesP

Якщо нам додатково відомий колір ліній, які нас цікавить, наприклад у задачі про виділення дорожньої розмітки, то перед бінаризацією спочатку можна виділити області зображення саме з цим кольором.

Немає коментарів:

Дописати коментар