참고 글
18. 윤곽선 (Image Contours)
윤곽선(Contours)은 동일한 색 또는 동일한 강도를 가지고 있는 영역의 경계선을 연결한 선으로 대상의 외형을 파악하는데 유용하게 사용된다.
윤곽선을 그리는 과정
윤곽선을 그릴 때는 원본 이미지의 훼손을 방지하기 위해 copy 이미지를 사용한다. 또한 윤곽선을 좀 더 정확하게 찾아내기 위해 Binary Image를 사용한다. 이때 threshold 또는 canny edge를 선처리로 수행한다. 그다음 윤곽선을 그리기 위해서 윤곽선을 찾는 cv2.findContours 함수와 윤곽선을 그리는 cv2.drawContours 함수를 사용한다.
Image copy - Binarizaion - Find contours - Drawcontours
Find Contours
윤곽선을 찾기 위해 cv2.findContours()함수를 사용한다. 함수를 사용해 윤곽선 정보(coutours)와 계층구조(hierarchy)를 반환한다.
cv2.findContours(image, mode, method)
mode의 경우 countours를 찾는 방법을 지정하는 다음과 같은 옵션이 있다.
- cv2.RETR_EXTERNAL : contours line중 가장 바깥쪽 라인만 찾음
- cv2.RETR_LIST : 모든 contours line을 찾지만 계층구조 관계를 구성하지 않음
- cv2.RETR_CCOMP : 모든 contours line을 찾으며 2-level의 계층구조 관계를 구성함
- cv2.RETR_TREE : 모든 contours line을 찾으며 모든 계층구조 관계를 구성함
method는 contours를 찾을 때 사용하는 근사화 방법으로, 다음과 같은 옵션이 있다.
- cv2.CHAIN_APPROX_NONE : 모든 contours point를 저장
- cv2.CHAIN_APPROX_SIMPLE : contours line을 그릴 수 있는 point만 저장 (ex. 사각형은 4개의 point)
- cv2.CHAIN_APPROX_TC89_L1 : contours point를 찾는 알고리즘
- cv2.CHAIN_APPROX_TC89_KCOS : contours point를 찾는 알고리즘
Draw Contours
이미지에 윤곽선을 그리기 위해선 cv2.drawContours()함수를 사용한다.
cv2.drawContours(image, contours, contourIdx, color, thickness)
contourIdx는 contours line type이 몇번째 윤곽선에서 그릴 것인지 정한다. -1일 경우 전체에 그리는 것을 의미한다.
위 과정을 바탕으로 이미지의 윤곽선을 그려보면 다음과 같다.
1. RETR_LIST 방법으로 contours를 찾는 경우
# EX. RETR_LIST
import cv2
img = cv2.imread("card.png")
# 원본을 copy한 사본이미지 사용
target_img = img.copy()
# 윤곽선 검출에서 정확도를 높히기 위해 binary Image를 사용한다.
# binarizaion 방법으로 otsu 알고리즘을 사용한다.
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, otsu = cv2.threshold(gray, -1, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
# cv2.findContours : 윤곽선 정보, 윤곽선간의 계층 구조를 반환
contours, hierarchy = cv2.findContours(otsu, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
#cv2.drawContours : 윤곽선 그리기
color = (0, 200, 0)
cv2.drawContours(target_img, contours, -1, color, 2)
# 원본에 그릴 경우 원본이 훼손되기 때문에 copy된 사본 이미지에 그린다.
cv2.imshow("origin", img)
cv2.imshow("gray", gray)
cv2.imshow("otsu", otsu)
cv2.imshow("contour", target_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
countours을 찾는 방법 중cv2.RETR_LIST 방법은 위의 마지막 결과처럼 모든 윤곽선을 찾는다.
2. cv2.RETR_EXTERNAL 방법으로 contours를 찾는 경우
# EX. RETR_EXTERNAL
import cv2
img = cv2.imread("card.png")
target_img = img.copy()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, otsu = cv2.threshold(gray, -1, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
contours, hierarchy = cv2.findContours(otsu, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
color = (0, 200, 0)
cv2.drawContours(target_img, contours, -1, color, 2)
cv2.imshow("origin", img)
cv2.imshow("gray", gray)
cv2.imshow("otsu", otsu)
cv2.imshow("contour", target_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.RETR_EXTERNAL 방법으로 contours를 찾는 경우 위의 결과처럼 가장 외곽의 윤곽선만을 찾는다.
3. cv2. RETR_TREE 방법으로 contours를 찾는 경우
cv2.RETR_LIST 방법으로 contours를 찾게 되면 cv2.RETR_LIST와 같은 결과를 출력한다. 다만 cv2. RETR_TREE의 경우 계층 정보를 트리구조로 생성한다는 차이점이 있다. 이 트리구조를 hierarchy에서 확인할 수 있다.
print(hierarchy)
[[[ 1 -1 -1 -1]
[ 2 0 -1 -1]
[10 1 3 -1]
...
[-1 34 -1 -1]]]
이 길이를 출력해보면 36개가 발견된다.
print(f'총 발견 갯수 : {len(contours)}')
총 발견 갯수 : 36
계층구조는 윤곽선을 포함관계의 여부를 나타낸다. 즉 외곽 윤곽선, 내곽 윤곽선, 같은 계층구조를 구별할 수 있다. 여기서 첫번째 계층구조는 각 4개의 값을 갖는데, 이는 [다음 윤곽선, 이전 윤곽선, 내곽윤곽선, 외곽윤곽선]에 대한 인덱스 정보를 포함하고 있다.
'Study > ML | DL' 카테고리의 다른 글
[혼공머신]1주차_머신러닝을 찍먹해보자! (0) | 2024.07.07 |
---|---|
[혼공머신]0주차_일단 저지르고 수습하는 사람의 인생 (0) | 2024.07.07 |
[Python] OpenCV를 이용한 이미지/영상 처리 - 이미지 경계선 (0) | 2023.06.16 |
[Python] OpenCV를 이용한 이미지/영상 처리 - 모폴로지 변환(Opening & Closing) (0) | 2023.06.14 |
[Python] OpenCV를 이용한 이미지/영상 처리 - 모폴로지 변환(dilate, erode) (1) | 2023.06.13 |