[openCV] Hough Transform
openCV

[openCV] Hough Transform

오늘은 Hough Transform에 대해서 공부를 진행해보자

 

이미지나 영상에서 직선을 검출하고자 할 때 주로 3가지 방법을 고안한다.

 

1. curve fitting

 

많은 점들을 가지고 최적의 라인을 찾는 것으로 다수의 점을

이용하여 직선을 찾는다.

 

2. RANSAC

 

Random Sample Consensus의 약자로

두 점을 가지고 랜덤하게 추출한 후, 최적의 직선을 구하거나

혹은 특이점을 제거하는 알고리즘이다.

 

3. Hough Transform

 

직선을 검출하는데 주로 쓰이는 알고리즘으로

빠른 직선 처리와 간단한 알고리즘이다.

 

 

0. Hough Transform

 

x, y 좌표계에서 (2,2)가 있다고 가정을 해보자

 

(2, 2)를 지나는 직선의 방정식을 y = ax + b라고 해보면

2 = 2a + b라고 할 수 있다.

 

b = -2a + 2가 도출된다.

 

b = -2a + 2의 그래프를 그려보자

 

굳2

좌표계가 a, b로 바뀌었으며, (2, 2)를 지나는 직선의 방정식이다.

 

굳3

(2, 1) / (2, 2) / (3, 2) / (4, 3) / (5, 2)

 

위 좌표들을 특징점이라고 가정해보자

 

굳4

b = ax + y에 특징점들을 대입해보면 a, b로 나타낼 수 있다.

 

출처 : https://diyver.tistory.com/100

위의 그래프에서 3번 이상 교차하는 지점을 빨간 원을 표시하였다.

 

빨간 원의 a, b값을 보게 되면

(a, b) - > (0, 2) / (1, -1)이 된다.

 

이걸 다시 y = ax + b에 대입을 해보면

 

y = 2

y = x - 1

이라는 그래프가 나온다.

 

굳5

그러면 원래 이미지에 특징점들을 연결한 직선이 되는

모습을 확인 할 수 있다.

 

Hough Transform를 이용한

직선 검출은 위와 같은 원리로 진행되는 것이다.

 

 

 

 

1. Hough Line Transform

 

Hough Transform중에서도 Hough Line Transform에 대해서

먼저 공부를 해보자


What Is Hough Line Transform?

 

Hough Line Transfrom은 이미지에서 직선을 찾기 위해서 사용한다.


openCV에서는 Hough Transform을 위해서 아래와 같은 함수를 제공한다.

 

lines = cv2.HoughLines(img, rho, theta, threshold, lines, srn=0, stn=0, min_theta, max_theta)

 

img = 입력 이미지는 8비트 바이너리 이미지

 

rho = 거리 측정 스케일, 0 ~ 1

 

theta = 각도, 라디안 단위 (np.pi / 0 ~ 180)

 

threshold = 직선으로 판단할 최소한의 동일 개수

(작은 값 : 정확도 감소, 검출 개수 증가 / 큰 값 : 정확도 증가, 검출 개수 감소)

 

lines = 검출 결과, N x 1 x 2 배열 (r, Θ)

 

srn, stn = 멀티 스케일 허프 변환에 사용, 선 검출에서는 사용 안 함

 

min_theta, max_theta = 검출을 위해 사용할 최대, 최소 각도

 

 

import cv2
import numpy as np
import sys
import math

img = cv2.imread("./test.jpg", cv2.IMREAD_GRAYSCALE)

img_edge = cv2.Canny(img, 50, 150)
#Canny Edge 검출

img_result = cv2.cvtColor(img_edge, cv2.COLOR_GRAY2BGR)
img_result_P = np.copy(img_result)

lines = cv2.HoughLines(img_edge, 1, np.pi / 180, 150)
#Hough Line 검출, 직선으로 판단할 최소한의 점은 150개로 지정

if lines is not None:
    for i in range(0, len(lines)):
        rho = lines[i][0][0] #거리 지정
        theta = lines[i][0][1] #각도 지정
        a = math.cos(theta) #x축에 대한 삼각비
        b = math.sin(theta) #y축에 대한 삼각비
        x0 = a * rho #x축 기준 좌표
        y0 = b * rho #y축 기준 좌표

        pt1 = (int(x0 + 1000 * (-b)), int(y0 + 1000 * (a))) #시작점
        pt2 = (int(x0 - 1000 * (-b)), int(y0 - 1000 * (a))) #끝점

        cv2.line(img_result, pt1, pt2, (0, 0, 255), 3)

while True:
    cv2.imshow("Source", img)
    cv2.imshow("Standard Hough Linee Transform", img_result)

    key = cv2.waitKet(0)
    if key == 27:
        break
    
cv2.destroyAllWindows()

 

 

위 코드는 HoughLines를 이용하여 직선을 검출한 예제이다.

 

하지만 HoughLines는 모든 점에 대해 계산하기 때문에 결과를

출력하는데 오래 걸릴 뿐만 아니라 원하는 결과가 나오지 않을 수도 있다.

 

 

[ Result ]

오른쪽 : Original Image(GrayScale) / 왼쪽 : Hough Line Transformation

확실히 많은 직선들이 검출된 것을 볼 수 있다.

 

 

 

2. Probabilistic Hough Line Transformation

 

위에서 말했듯이 HoughLines는 모든 점에 대해 계산하기 때문에

연산량이 많아 속도가 느리다.

 

이를 개선한 방법이 Probalbilistic(확률적) Hough Lines Transform이다.

 

Probalbilistic Hough Lines Transform은 모든 점을 고려하지 않고

무작위로 선정한 픽셀에 대해 Hough Transform을 수행하고

점차 그 수를 증가시키는 방법이다.

 

lines = HoughLinesP(img, rho, theta, threshold, lines, minLineLength, maxLineGap)

 

img = 입력 이미지는 8비트 바이너리 이미지여야 함

 

rho = 거리 측정 스케일, 0 ~ 1

 

theta = 각도, 라디안 단위 (np.pi / 0 ~ 180)

 

threshold = 직선으로 판단할 최소한의 동일 개수

(작은 값 : 정확도 감소, 검출 개수 증가 / 큰 값 : 정확도 증가, 검출 개수 감소)

 

lines = 검출된 직선의 시작점과 끝 점 정보를 리턴한다.

 

minLineLength = 최소 선의 길이이다. 이 값보다 큰 직선만 검출된다.

 

maxLineGap = 찾은 직선이 이 값 이상 떨어져 있어야 별개의 직선으로 간주한다.

 

import cv2
import numpy as np
import imutils
import math

img = cv2.imread("./test.jpg", cv2.IMREAD_GRAYSCALE)

img_edge = cv2.Canny(img, 50, 150)

img_result = cv2.cvtColor(img_edge, cv2.COLOR_GRAY2BGR)

linesP = cv2.HoughLinesP(img_edge, 1, np.pi / 180, 50, None, 50, 5)

if linesP is not None:
    for i in range(0, len(linesP)):
        l = linesP[i][0]
        cv2.line(img_result, (l[0], l[1]), (l[2], l[3]), (0,0,255), 3, cv2.LINE_AA)

cv2.imshow("Source", img)
cv2.imshow("Probabilistic Line Transform",  img_result)

cv2.waitKey(0)
cv2.destroyAllWindows()

위 예제는 Probabilistic Hough Line Transform이 적용된 예제이다.

 

[ Result ]

 

오른쪽: Original Image (GrayScale) / 왼쪽: Probabilistic Hough Line Transform

 

확실히 그냥 HougnLines를 이용하는 것보다는 HoughLinesP를

이용하는 것이 우리가 원하는 이상적인

결과와 가깝다고 보여진다.

 

 

3. Hough Circle Transform

 

Hough Transform을 이용해서 직선 뿐만 아니라

원 역시 검출할 수 있다

 

circle = cv2.HoughCircles(img, method, dp, minDist, circles, param1, param2, minRadius, maxRadius)

 

img = 입력 이미지는 GrayScale 이미지여야 한다.

 

method = 원 검출 방식 지정 (현재 cv2.HOUGH_GRADIENT만 가능하다)

 

dp = 이미지 해상도에 대한 accumulate 해상도의 비율의 역수이다.

(만약 dp = 1라면 입력 이미지와 같은 해상도를 가지고, 값이 커질 수록 부정확해진다.)

 

minDist = 원들 중심 간의 최소 거리 ( minDist = 0 -> Error : 동심원 검출 불가능)

 

Circles = 발견한 원의 벡터이다. 각 벡터는 3개 (x, y, radius) 또는 4개(x, y, radius, votes)의 원소를 가진다.

 

param1 = Canny Edge에 전달할 Threshold의 Maximum Value

 

param2 = 경사도 누적 경계 값 (값이 작을수록 잘못된 원 검출)

 

minRadius, maxRadius = 원의 최소 반지름, 최대 반지름

 

Hough Line Transform에서는 Canny Edge등을 사용하여

Edge를 검출한 이미지를 이용하여야 했지만

 

Hough Circle Transform에서는 HoughCircles() 함수 내부에

Edge Detection 알고리즘이 포함되어 있기 때문에

GrayScale Image로만 넘겨주면 된다.

 

import cv2
import imutils
import numpy as np
import math

#GrayScale로 입력 이미지를 불러온다.
img_gray = cv2.imread("./Circle.jpg", cv2.IMREAD_GRAYSCALE)
img_gray = cv2.medianBlur(img_gray, 5)

#결과 이미지에 컬러 도형을 사용하기 위해 컬러로 변환시킨다.
img_color = cv2.cvtColor(img_gray, cv2.COLOR_GRAY2BGR)

#원을 검출한다.
circles = cv2.HoughCircles(img_gray, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=35, minRadius=0, maxRadius=0)
circles = np.uint16(np.around(circles))

#검출된 원 위에 빨간색 / 초록색 원을 그려준다.
for c in circles[0,:]:
    center = (c[0], c[1])
    radius = c[2]

    #바깥 원
    cv2.circle(img_color, center, radius, (0, 255, 0), 2)
    #중심 점
    cv2.circle(img_color, center, 2, (0, 0, 255), 3)

cv2.imshow("detected circles", img_color)
cv2.waitKey(0)
cv2.destroyAllWindows()

 위 예제는 원을 검출하는 예제입니다.

 

Edge Detection은 하지 않고 그냥 블러 처리만 해서 원을 검출했습니다.

 

[Result]

Hough Circle Transform

 

 

오늘도 끄-읕👨‍🎓

'openCV' 카테고리의 다른 글

[openCV] Morphology  (0) 2021.03.12
[openCV] Convolution & Mask (2)  (0) 2021.03.06
[openCV] Convolution & Mask (1)  (0) 2021.03.06
[openCV] Image Geometric Transformation (2)  (0) 2021.02.21
[openCV] Image Geometric Transformation (1)  (0) 2021.02.20