Python/파이썬 OpenCV 공부

[파이썬 OpenCV] 영상에서 원 검출하기 - 허프 변환 원 검출 - cv2.HoughCircles

AI 꿈나무 2020. 10. 9. 20:44
반응형

황선규 박사님의 <OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝>를 공부한 내용을 정리해 보았습니다.

 

예제 코드 출처 :  황선규 박사님 github홈페이지

 

『OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝』

예제 소스 코드는 아래 링크를 참고하세요

sunkyoo.github.io


허프 변환 원 검출

 허프 변환을 응용하여 원을 검출할 수 있습니다.

 직선 검출과 같이 원의 방정식을 파라미터 좌표평면에 표현하면 3차원 축적 평면이 되므로 연산속도가 너무 오래 걸립니다.

 

 속도를 더 빠르기 위해 제안된 방법이 Hough gradient method 입니다.

 

Hough gradient method

 원에서 검출된 에지의 원주 점의 정보를 이용합니다.

 원 에지 픽셀에서 그래디언트를 계산합니다.

 그래디언트 크기 방향으로 직선을 그리면서 값을 누적시킵니다..

 그래디언트 크기는 원의 중심을 향하므로 직선은 원의 중심에서 모이게 됩니다.

 이처럼 원의 중심을 찾습니다.

 

 원의 중심을 찾은 후 반지름을 찾습니다.

 원의 중심에서 반지름을 점점 키워가면서 원주와 만나는지를 확인합니다.

 

 단점은 여러 개의 동심원을 검출 못합니다.

 가장 작은 원 하나만 검출됩니다.

 

허프 변환 원 검출 함수 - cv2.HoughCircles

cv2.HoughCircles(image, method, dp, minDist, circles=None, param1=None, param2=None, minRadius=None, maxRadius=None) -> circles

• image: 입력 영상. (에지 영상이 아닌 일반 영상)
• method: OpenCV 4.2 이하에서는 cv2.HOUGH_GRADIENT만 지정 가능
• dp: 입력 영상과 축적 배열의 크기 비율. 1이면 동일 크기. 2이면 축적 배열의 가로, 세로 크기가 입력 영상의 반.
• minDist: 검출된 원 중심점들의 최소 거리
• circles: (cx, cy, r) 정보를 담은 numpy.ndarray. shape=(1, N, 3), dtype=np.float32
• param1: Canny 에지 검출기의 높은 임계값
• param2: 축적 배열에서 원 검출을 위한 임계값
• minRadius, maxRadius: 검출할 원의 최소, 최대 반지름

 허프 변환 원 검출 함수는 직선 검출 함수와 다르게 입력 영상에 에지 영상이 아닌 일반 영상을 입력해줍니다.

 에지의 방향 성분을 이용해야 하는데 에지 영상은 방향 정보가 제공되지 않습니다.

 따라서 함수 내부에서 캐니 에지를 진행하여 방향 성분을 추출합니다.

 

 method는 cv2.Hough_GRADIENT_ALT가 기존 방법보다 더 정확한 원을 검출할 수 있습니다. 또한 기존 방법은 파라미터의 영향을 많이 받았지만 cv2.Hough_GRADIENT_ALT는 적은 영향을 받습니다.

cv2.Hough_GRADIENT_ALT의 경우에 입력 인자가 달라지므로 주의해야 합니다.

 

 

 dp는 보통 1을 설정하며 경우에 따라 2로 설정하여 입력 영상보다 1/2 크기의 축적 영상을 생성합니다.

 1/2 크기의 영상을 생성하면 연산 속도가 빨라지지만 아주 정교한 원은 찾아내지 못합니다.

 

 mniDIst는 검출된 원 중심점들의 최소거리를 설정하여 원이 너무 붙어 있는 것은 안찾습니다.

 

 circles는 원의 정보가 담겨있습니다. 중심점 좌표, 반지름과 원의 갯수 (1, N, 3) 3차원 데이터 입니다.

 허프 직선 검출 결과값과 차원이 다르므로 주의해야 합니다.

 

 parmas1는 캐니 엣지에서 높은 임계값입니다. 낮은 임계값은 1/2로 자동 설정됩니다.

 

 params2 는 원 검출을 위한 임계값입니다.

 

 minRadius, maxRadius는 검출할 원의 최소 최대 반지름입니다. 설정을 해준다면 빠른 연산이 가능합니다.

 

허프 변환 원 검출 예제

 허프 서클 함수를 적용하기 전에 입력 영상에 블러링을 통해 노이즈를 제거해주는 것이 효과가 좋습니다.

 가우시안 블러링을 적용하지 않으면 원 검출이 지저분하게 됩니다.

 원이 아닌데도 원으로 판단하는 경우를 줄이기 위해 적절한 블러링을 해줘야 합니다.

 

 예제는 파라미터를 조절할 수 있는 트랙바를 추가하여 파라미터에 따른 원 검출을 비교해보겠습니다.

 

src = cv2.imread('dial.jpg')

if src is None:
    print('Image open failed!')
    sys.exit()
    
gray = cv2.cvtCplor(src, cv2.COLOR_BGR2GRAY)

# 블러를 통해 노이즈 제거
blr = cv2.GaussianBlur(gray, (0, 0), 1.0)

# 트랙바 함수 정의
def on_trackbar(pos):
    # 트랙바 초기값 정보 받아오기
    rmin = cv2.getTrackbarPos('minRadius', 'img')
    rmax = cv2.getTrackbarPos('maxRadius', 'img')
    th = cv2.getTrackbarPos('threshold', 'img')
    
    # 받아온 정보를 cv2.HoughCircles에 입력
    circles = cv2.HoughCircles(blr, cv2.HOUGH_GRADIENT, 1, 50
                               parmam1=120, param2=th, minRadius=rmin, maxRadius=rmax)
    
    dst = src.copy() # 복사한 입력영상 위에 원 그리기
    if circles is not None:
        for i in range(circles.shape[1]) # 검출된 원 갯수만큼 반복
            cx, cy, radius = circles[0][i] # i번째 원에 데이터 저장
            cv2.circle(dst, (cx, cy), radius, (0, 0, 255), 2, cv2.LINE_AA) # 저장된 데이터를 이용해 원 그리기
    
    cv2.imshow('img', dst)
    
# 트랙바 생성
cv2.imshow('img', src)

# 트랙바 범위
cv2.createTrackbar('minRadius', 'img', 0, 100, on_trackbar)
cv2.createTrackbar('maxRadius', 'img', 0, 150, on_trackbar)
cv2.createTrackbar('threshold', 'img', 0, 100, on_trackbar)

# 트랙바 초깃값
cv2.setTrackbarPos('minRadius', 'img', 10) # 초기값 10
cv2.setTrackbarPos('maxRadius', 'img', 80)
cv2.setTrackbarPos('threshold', 'img', 40)

cv2.waitKey()

cv2.destroyAllWindows()

 

 

 이처럼 트랙바를 이용해 파라미터 값을 변화하면서 원하는 원을 검출할 수 있습니다.

 

반응형