Skip to main content

도형 검출

직선 검출

src = cv.imread("road.webp")
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# 윤곽선 추출
canny = cv.Canny(gray, 5000, 1500, apertureSize = 5, L2gradient = True)

허프 변환

  • 윤곽선을 이루는 점들을 지나는 직선의 방정식을 찾음
  • 여러 개의 직선들 중에 가장 조건에 맞는 직선들만 골라냄

멀티 스케일 허프 변환 Multi-Scale Hough Transform

lines = cv.HoughLines(
canny,
0.8, # 거리 측정 해상도, 0~1
np.pi / 180, # 각도의 해상도(라디안)
150, # 임계값(키울 수록 정확도 증가하고 검출되는 직선의 수는 감소)
srn = 100, # 거리의 약수(≥0), 허프 변환을 좀 더 정확하게 하기 위한 값
stn = 200, # 각도의 약수(≥0), 허프 변환을 좀 더 정확하게 하기 위한 값
min_theta = 0, # 최소 각도
max_theta = np.pi) # 최대 각도

시각화

dst = src.copy()
for i in lines:
rho, theta = i[0][0], i[0][1]
a, b = np.cos(theta), np.sin(theta)
x0, y0 = int(a*rho), int(b*rho)
scale = src.shape[0] + src.shape[1]
x1 = int(x0 + scale * -b)
y1 = int(y0 + scale * a)
x2 = int(x0 - scale * -b)
y2 = int(y0 - scale * a)
cv.line(dst, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv.circle(dst, (x0, y0), 3, (255, 0, 0), 5, cv.FILLED)

점진성 확률적 허프 변환 Progressive Probabilistic Hough Transform

# 속도는 빠르지만 정확성은 떨어지는 방식
lines = cv.HoughLinesP(
canny,
0.8, # 거리 측정 해상도, 0~1
np.pi / 180, # 각도의 해상도(라디안)
90, # 임계값(키울 수록 정확도 증가하고 검출되는 직선의 수는 감소)
minLineLength = 10, # 검출할 직선의 최소 길이
maxLineGap = 100) # 최대 허용 간격(이 간격 내에 있는 직선은 검출 안함)

시각화

dst = src.copy()
lines = lines.astype(int, copy=False)
for i in lines:
cv.line(
dst,
(i[0][0], i[0][1]), # 시작
(i[0][2], i[0][3]), # 끝
(0, 255, 0), # 색깔
2) # 굵기

원 검출

src = cv.imread("balls.webp") # 예제 이미지
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)

circles = cv.HoughCircles(# 허프 변환
gray,
cv.HOUGH_GRADIENT, # 검출 방법, HOUGH_GRADIENT_ALT도 있음
1, # 해상도 비율
100, # 원의 중심 간 최소 거리
param1 = 250, # 검출 방법의 매개 변수
param2 = 10, # 검출 방법의 매개 변수
minRadius = 80, # 최소 반지름
maxRadius = 120) # 최대 반지름

시각화

dst = src.copy()
circles = circles.astype(int)
for i in circles[0]:
cv.circle(dst, (i[0], i[1]), i[2], (255, 255, 255), 5)

볼록 껍질

어떤 도형을 둘러싼 볼록한 다각형 찾기
src = cv.imread("convex.webp") # 예제 데이터
dst = src.copy()
gray = cv.cvtColor(src, cv.COLOR_RGB2GRAY)
ret, binary = cv.threshold(gray, 150, 255, cv.THRESH_BINARY_INV) # 이진화
contours, hierarchy = cv.findContours(# 윤곽선
binary, cv.RETR_CCOMP, cv.CHAIN_APPROX_NONE)
for i in contours:
hull = cv.convexHull(i, clockwise=True) # 볼록 껍질 찾기(True: 시계 방향)
cv.drawContours(dst, [hull], 0, (0, 0, 255), 2)

윤곽선 관련 기타 함수들

  • cv.contourArea 윤곽선이 감싸는 영역의 면적
  • cv.fitLine 주어진 점에 적합한 직선
  • cv.minEnclosingTriangle 주어진 점을 감싸는 최소 크기 삼각형
  • cv.boundingRect 주어진 점을 감싸는 최소 크기 사각형
  • cv.minAreaRect 주어진 점을 감싸는 최소 크기 회전된 사각형
  • cv.minEnclosingCircle 주어진 점을 감싸는 최소 크기 원
  • cv.fitEllipse 주어진 점을 감싸는 타원
  • cv.isContourConvex 볼록 여부
  • cv.convexityDefects 볼록 껍질에서 가장 안으로 들어간 점

퀴즈