다양한 외곽선 함수
외곽선 길이 구하기 - cv2.arclength
retval = cv2.arcLength(curve, closed)
- curve : 외곽선 좌표. numpy.ndarray.
shape=(K, 1, 2) - closed : True이면 폐곡선으로 간주
- retval : 외곽선 길이
면적 구하기 - cv2.contourArea
retval = cv2.contourArea(contour, oriented=None)
- contour : 외곽선 좌표. numpy.ndarray.
shape=(K, 1, 2) - oriented : True이면 외곽선 진행 방향에 따라 부호 있는 면적을 반환.
기본값은 False - retval : 외곽선으로 구성된 영역의 면적
바운딩 박스(외곽선을 외접하여 둘러싸는 가장 작은 사각형) 구하기 - cv2.boundingRect
retval = cv2.boundingRect(array)
- array : 외곽선 좌표. numpy.ndarray.
shape=(K, 1, 2) - retval : 사각형 정보. (x, y, w, h) 튜플
바운딩 서클(외곽선을 외접하여 둘러싸는 가장 작은 원) 구하기 - cv2.minEnclosingCircle
center, radius = cv2.minEnclosingCircle(points)
- points : 외곽선 좌표. numpy.ndarray.shape=(K, 1, 2)
- center : 바운딩 서클 중심 좌표. (x, y) 튜플
- radius : 바운딩 서클 반지름. 실수.
최소 면적 사각형 함수(윤곽선의 경계면을 둘러싸는 최소 크기의 사각형) - cv2.minAreaRect
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(img,[box],0,(0,0,255),2)
윤곽선에 가장 근사한 원 구하기 - cv.minEnclosingCircle
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
cv2.circle(img,center,radius,(0,255,0),2)
외곽선 근사화 - cv2.approxPolyDP
retval = cv2.approxPolyDP(curve, epsilon, closed, approxCurve=None)
- curve : 입력 곡선 좌표. numpy.ndarray.shape=(K, 1, 2)
- epsilon : 근사화 정밀도 조절. 입력 곡선과 근사화 곡선 간의 최대 거리.
- ex) cv2.arcLength(curve) * 0.02
- closed : True를 전달하면 폐곡선으로 인식
- approxCurve : 근사화된 곡선 좌표. numpy.ndarray.shape=(K', 1, 2)
- 참고사항
- 더글라스-포이커 알고리즘 (Douglas-peucker algorithm)
윤곽선에 근접한 타원 구하기 - cv2.fitEllipse
ellipse = cv2.fitEllipse(cnt)
cv2.ellipse(img,ellipse,(0,255,0),2)
주어진 점에 적합한 직선 그리기 - cv2.fitLine
rows, cols = img.shape[:2]
[vx, vy, x, y] = cv2.fitLine(cnt, cv.DIST_L2, 0, 0.01, 0.01)
lefty = int((-x*vy/vx) + y)
righty = int(((cols-x)*vy/vx)+y)
cv2.line(img, (cols-1, righty), (0, lefty), (0, 255, 0), 2)
Convex 검사
retval = cv2.isContourConvex(contour)
- contour : 입력 곡선 좌표. numpy.ndarray.
shape=(K, 1, 2) - retval : 컨벡스이면 True, 아니면 False.
윤곽선의 경계면을 둘러싸는 다각형 구하기 - cv2.convexHull
for i in contours:
hull = cv2.convexHull(i, clockwise=True)
cv2.drawContours(dst, [hull], 0, (0, 0, 255), 2)
- 윤곽선은 윤곽선 검출 함수에서 반환되는 구조를 사용
- 방향은 검출된 볼록 껍질의 볼록점들의 인덱스 순서를 의미
블록 껍질 함수는 단일 형태에서만 검출이 가능하다.
- 윤곽선 구조는 윤곽선 검출 함수의 반환값과 형태가 동일하다면, 임의의 배열에서도 검출이 가능하다.
- 방향이 True라면 시계 방향, False라면 반시계 방향으로 정렬된다.
Contour에 볼록 결함(Convexity Defect)가 있는지 확인 -cv2.convexityDefects
convexityDefects = cv2.convexityDefects(contour, convexhull[, convexityDefects])
- contour : convexHull을 진행했던 Contours를 그대로 인자로 받는다.
- convexhull : 볼록체를 만든 Contour Points의 인덱스를 포함한 convexHull를 인자로 받는다.
convexityDefects는 Contour의 각 인덱스마다 다음 4가지를 계산하여 반환한다.
- start point : Convex Hull를 이루는 시작 인덱스
- end point : Convex Hull를 이루기 위해 그 다음으로 연결되는 점의 인덱스
- farthest point : start와 end를 연결한 직선과 가장 멀리 떨어져 있는 Contour 상의 인덱스
- approximate distance to farthest point : farthest point와 Convex Hull 사이의 거리
다각형 검출 프로그램
- 다양한 다각형 객체 영상에서 삼각형, 사각형, 원 찾기
- 구현 순서
- 이진화
- 외곽선 찾기
- 외곽선 근사화
- 너무 작은 객체와 컨벡스가 아닌 객체 제외
- 꼭지점 개수 확인
- 삼각형, 사각형 검출
- 원 판별
원 판별하기
- 정해진 외곽선 길이에 대한 넓이 비율이 가장 큰 형태가 원
→ 도형의 넓이(A)와 외곽선 길이(P)의 비율을 검사
따라서 $\frac{A}{P^2}$로 만들어 비율을 계산해준다. - 의 경우 약분하면 이 남게 되어 비율이 상수로 떨어지지 않는다.
$4\pi \frac{A}{P^2}$ 의 값이 1에 가까울수록 원으로 판단한다.
length = cv2.arcLength(pts, True)
area = cv2.contourArea(pts)
ratio = 4. * math.pi * area / (length * lenght)
if ratio > 0.05:
setLabel(img, pts, 'CIR') # 원
💬 다각형 판별 프로그램 예제
import math
import cv2
def setLabel(img, pts, label):
(x, y, w, h) = cv2.boundingRect(pts)
pt1 = (x, y)
pt2 = (x + w, y + h)
cv2.rectangle(img, pt1, pt2, (0, 0, 255), 1)
cv2.putText(img, label, pt1, cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 255))
def main():
img = cv2.imread('polygon.bmp', cv2.IMREAD_COLOR)
if img is None:
print('Image load failed!')
return
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, img_bin = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
contours, _ = cv2.findContours(img_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
for pts in contours:
if cv2.contourArea(pts) < 400: # 너무 작으면 무시
continue
approx = cv2.approxPolyDP(pts, cv2.arcLength(pts, True)*0.02, True)
vtc = len(approx)
if vtc == 3:
setLabel(img, pts, 'TRI')
elif vtc == 4:
setLabel(img, pts, 'RECT')
else:
length = cv2.arcLength(pts, True)
area = cv2.contourArea(pts)
ratio = 4. * math.pi * area / (length * length)
if ratio > 0.85:
setLabel(img, pts, 'CIR')
cv2.imshow('img', img)
cv2.waitKey()
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
'OpenCV' 카테고리의 다른 글
[OpenCV with Python] 영상 분할과 객체 검출 : 모멘트 기반 객체 검출 (0) | 2022.02.04 |
---|---|
[OpenCV with Python] 영상 분할과 객체 검출 : 그랩컷 - cv2.grabCut (0) | 2022.02.04 |
[OpenCV with Python] 이진 영상 처리 : 외곽선 검출 (0) | 2022.02.04 |
[OpenCV with Python] 이진 영상 처리 : 레이블링 (0) | 2022.02.04 |
[OpenCV with Python] 이진 영상 처리 : 모폴로지(Morphology) - 열기와 닫기 (0) | 2022.02.04 |