OpenCV 의 허프 변환에 대해 공부한 것을 정리하여 이번 포스팅을 작성하였습니다.
허프 변환은 이미지에서 모양을 찾는 유명한 방법입니다.
그중에서 OpenCV에서 사용하는 선, 확률적, 원 변환에 대해 정리해보았습니다.
자세한 이론은 허프 변환 을 보고 공부했습니다.
허프 선 변환
이미지의 수많은 픽셀 중 직선의 관계를 가진 것만 처리하는 것이 선 변환입니다.
OpenCV에서 제공하는 함수는 cv2.HoughLines를 제공합니다.
- lines = cv2.HoughLines(img, rho, theta, threshold, lines, srn=0, stn=0, min_theta, max_theta)
- img : 입력 이미지
- rho: 거리 측정 해상도, 0~1
- theta: 각도, 라디안 단위 (np.pi/0~180)
- threshold: 직선으로 판단할 최소한의 동일 개수 (작은 값: 정확도 감소, 검출 개수 증가 / 큰 값: 정확도 증가, 검출 개수 감소)
- lines: 검출 결과
- srn, stn: 멀티 스케일 허프 변환, 선 검출에서는 사용 안 함
- min_theta, max_theta: 검출을 위해 사용할 최대, 최소 각도
예제 )
import cv2
import numpy as np
img = cv2.imread("sudoku.jpg")
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(img_gray, 50, 150)
lines = cv2.HoughLines(edges, 1, np.pi/180, 200)
# 허프변환으로 선을 찾아내면 극좌표로 찾아냄 - 어떤 각도로 부터 얼마나 떨어져있는지 찾아냄
# 그래서 다시 x, y 좌표로 만들어줘야함
for line in lines:
rho, theta = line[0]
a = np.cos(theta)
b = np.sin(theta)
x0 = a * rho
y0 = b * rho
x1 = int(x0 + 1000 * (-b))
y1 = int(y0 + 1000 * (a))
x2 = int(x0 - 1000 * (-b))
y2 = int(y0 - 1000 * (a))
cv2.line(img, (x1,y1), (x2,y2), (0,0,255), 2)
cv2.imshow("Image by Hough", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
결과 )
Canny로 먼저 이미지 처리 후에 선을 검출 했습니다!
확률적 허프 선 변환
앞서 했던 선 검출은 모든 픽셀에 대해 많은 선을 그어 직선을 찾기 때문에 연산량이 많습니다.
그렇지만 확률전 허스 선 변환은 모든 점을 고려하지 않고
확률로 랜덤으로 픽셀을 선정에 변환을 실행하고 증가 시킵니다.
OpenCV 에서는 cv2.HoughLinesP 로 확률적 선 변환을 수행합니다.
- lines = cv2.HoughLinesP(img, rho, theta, threshold, lines, minLineLength, maxLineGap)
minLineLength(optional): 선으로 인정할 최소 길이
maxLineGap(optional): 선으로 판단할 최대 간격
lines: 검출된 선 좌표
이외의 파라미터는 cv2.HoughLines()와 동일
예제)
import cv2
import numpy as np
img = cv2.imread("sudoku_puzzles.jpg")
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(img_gray, 50, 150 , apertureSize=3)
## 선으로 대우를 받고 싶으면 최소길이가 100이어야하고 라인사이 갭은 10이어야한다.
# p가 붙어서 확률 적으로 무작위로 허프변환 해본다
# probabilistic
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100, minLineLength=100, maxLineGap=10)
for line in lines:
## 리스트에서 1,2,3,4, 씩 계속 뽑아옴
x1, y1, x2, y2 = line[0]
cv2.line(img, (x1,y1), (x2,y2), (0,0,255), 2)
cv2.imshow("Image by Hough", img)
cv2.imshow("canny", edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
결과)
Canny로 외곽선을 검출 후 적용하였습니다. 결과로 보면 선 검출을 완벽하게 하지는 못하였지만
속도는 빠른 것을 확인 할 수 있었습니다.
허프 원 변환
원도 허프 변환을 통해 검출 할 수 있습니다.
OpenCV 에서는 cv2.HoughCircles 함수를 제공합니다.
- circle = cv2.HoughCircles(img, method, dp, minDist, circles, param1, param2, minRadius, maxRadius)
- img: 입력 이미지
- method: 검출 방식 선택, cv2.HOUGH_GRADIENT만 가능
- dp: 입력 영상과 경사 누적의 해상도 반비례율, 1: 입력과 동일, 값이 커질수록 부정확
- minDist: 원들 중심 간의 최소 거리 (0: 에러, 0이면 동심원이 검출 불가하므로)
- circles(optional): 검출 원 결과
- param1(optional): 캐니 엣지에 전달할 스레시홀드 최대 값 (최소 값은 최대 값의 2배 작은 값을 전달)
- param2(optional): 경사도 누적 경계 값 (값이 작을수록 잘못된 원 검출)
- minRadius, maxRadius(optional): 원의 최소 반지름, 최대 반지름 (0이면 이미지 전체의 크기)
예제)
import cv2
import numpy as np
img = cv2.imread("circle.jpg")
output = img.copy()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.medianBlur(gray, 7)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 20, param1 = 50, param2= 30, minRadius=0, maxRadius=50)
detected_circles = np.uint16(np.around(circles))
for (x,y,r) in detected_circles[0, :]:
cv2.circle(output, (x,y), r, (0,255,255),3)
cv2.circle(output, (x,y), 2, (0,255,255,),3)
cv2.imshow("output", output)
cv2.imshow("median blur", gray)
cv2.waitKey(0)
cv2.destroyAllWindows()
결과)
미디언 블러를 사용하여 흐리게 만든 후 검출 했습니다. 원 검출에서는 따로 외곽선을 구하지 않았는데
그 이유는 cv2.HoughCircles 함수 안에서 Canny를 사용하기 때문입니다.
OpenCV를 다시 공부하고 있고 이번 포스팅에서는 허프 변환에 대해 알아보았습니다.
질문이 있으시거나 틀린 내용이 있으면 댓글로 남겨주세요 감사합니다! :)
'영상처리' 카테고리의 다른 글
Python - OpenCV (7) : Background Subtraction (0) | 2021.07.11 |
---|---|
Python - OpenCV (6) : Image Inpainting (0) | 2021.07.09 |
Python - OpenCV (4) : 컨투어(contour) 1 (0) | 2020.12.06 |
Python - OpenCV (3) : 모폴로지(morphology) (0) | 2020.12.05 |
Python - OpenCV (2) : 영상 필터 경계(edge) 검출 (0) | 2020.12.03 |