In [1]:
from Custom.mediahelper import show_image_with_pil # 개발자 정의 모듈
In [2]:
import cv2
img = cv2.imread('../Media/images/card.png')
img_copy = img.copy() # 사본
show_image_with_pil(img, 'img')
'img'
1. 그레이 스케일 변환¶
- 그레이스케일 이미지는 색 정보를 제거하고 밝기 정보만 남김.
- 윤곽선 검출을 할 때 색상보다 밝기(명도) 정보가 중요.
In [3]:
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
show_image_with_pil(gray, 'gray')
'gray'
2. Otsu 이진화 적용 (자동으로 최적의 임계값)¶
cv2.threshold()
- Otsu 방법을 사용할 때 threshold 값을 -1로 설정하면, OpenCV가 자동으로 최적의 임계값을 계산.
- 255: 픽셀이 임계값을 넘으면 255(흰색)으로 설정됨.
- cv2.THRESH_BINARY: 이진화 방법을 지정. 픽셀 값이 임계값보다 크면 흰색(255), 작으면 검은색(0)으로 변환.
- cv2.THRESH_OTSU: Otsu의 이진화 방법을 적용하여 최적의 임계값을 자동으로 결정.
In [4]:
ret, otsu = cv2.threshold(gray, -1, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
show_image_with_pil(otsu, 'otsu') # 카드 그림자 제거됨
'otsu'
3. 윤곽선 검출¶
cv2.findContours()
- 두 번째 인자 (윤곽선 찾기 모드)
- cv2.RETR_LIST : 모든 윤곽선 찾음 (계층 정보 없음)
- cv2.RETR_TREE : 모든 윤곽선 찾음 (계층 정보를 트리 구조로 생성)
- cv2.RETR_EXTERNAL : 가장 외곽의 윤곽선만 찾음
- 세 번째 인자
- cv2.CHAIN_APPROX_NONE: 윤곽선의 모든 좌표를 반환.
- cv2.CHAIN_APPROX_SIMPLE: 꼭지점만 반환.
In [5]:
contours, hierarchy = cv2.findContours(otsu, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
# contours: 윤곽선 정보
# hierarchy: 계층 구조
In [6]:
COLOR = (0,200,0) # 녹색
cv2.drawContours(img_copy, contours, -1, COLOR, 2) # 윤곽선 그리기
cv2.imshow('img_copy',img_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()
show_image_with_pil(img_copy, 'img_copy')
'img_copy'
윤곽선 찾기 모드¶
- cv2.RETR_LIST : 모든 윤곽선 찾음 (계층 정보 없음)
- cv2.RETR_TREE : 모든 윤곽선 찾음 (계층 정보를 트리 구조로 생성)
- cv2.RETR_EXTERNAL : 가장 외곽의 윤곽선만 찾음
In [7]:
import cv2
img = cv2.imread('../Media/images/card.png')
img_copy1 = img.copy()
img_copy2 = img.copy()
img_copy3 = img.copy()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, otsu = cv2.threshold(gray, -1, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
contours1, hierarchy1 = cv2.findContours(otsu, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
contours2, hierarchy3 = cv2.findContours(otsu, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
contours3, hierarchy2 = cv2.findContours(otsu, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
print("hierarchy1 총 발견 갯수 :", len(contours1))
print(hierarchy1)
print("hierarchy2 총 발견 갯수 :", len(contours2))
print(hierarchy3)
print("hierarchy3 총 발견 갯수 :", len(contours3))
print(hierarchy3)
COLOR = (0,200,0) # 녹색
cv2.drawContours(img_copy1, contours1, -1, COLOR, 2) # 윤곽선 그리기
cv2.drawContours(img_copy2, contours2, -1, COLOR, 2) # 윤곽선 그리기
cv2.drawContours(img_copy3, contours3, -1, COLOR, 2) # 윤곽선 그리기
# 대상이미지, 윤곽선 정보, 인덱스(-1 이면 전체), 색깔, 두께
cv2.imshow('img_copy1',img_copy1)
cv2.imshow('img_copy2',img_copy2)
cv2.imshow('img_copy3',img_copy3)
cv2.waitKey(0)
cv2.destroyAllWindows()
show_image_with_pil(img_copy1, 'img_copy1')
show_image_with_pil(img_copy2, 'img_copy2')
show_image_with_pil(img_copy3, 'img_copy3')
hierarchy1 총 발견 갯수 : 36 [[[ 1 -1 -1 -1] [ 2 0 -1 -1] [ 3 1 -1 -1] [ 4 2 -1 -1] [ 5 3 -1 -1] [ 6 4 -1 -1] [ 7 5 -1 -1] [ 8 6 -1 -1] [ 9 7 -1 -1] [10 8 -1 -1] [11 9 -1 -1] [12 10 -1 -1] [13 11 -1 -1] [14 12 -1 -1] [15 13 -1 -1] [16 14 -1 -1] [17 15 -1 -1] [18 16 -1 -1] [19 17 -1 -1] [20 18 -1 -1] [21 19 -1 -1] [22 20 -1 -1] [23 21 -1 -1] [24 22 -1 -1] [25 23 -1 -1] [26 24 -1 -1] [27 25 -1 -1] [28 26 -1 -1] [29 27 -1 -1] [30 28 -1 -1] [31 29 -1 -1] [32 30 -1 -1] [33 31 -1 -1] [34 32 -1 -1] [35 33 -1 -1] [-1 34 -1 -1]]] hierarchy2 총 발견 갯수 : 36 [[[ 1 -1 -1 -1] [ 2 0 -1 -1] [10 1 3 -1] [ 5 -1 4 2] [-1 -1 -1 3] [ 6 3 -1 2] [ 7 5 -1 2] [ 8 6 -1 2] [-1 7 9 2] [-1 -1 -1 8] [18 2 11 -1] [13 -1 12 10] [-1 -1 -1 11] [14 11 -1 10] [15 13 -1 10] [16 14 -1 10] [-1 15 17 10] [-1 -1 -1 16] [26 10 19 -1] [21 -1 20 18] [-1 -1 -1 19] [22 19 -1 18] [23 21 -1 18] [24 22 -1 18] [-1 23 25 18] [-1 -1 -1 24] [34 18 27 -1] [29 -1 28 26] [-1 -1 -1 27] [30 27 -1 26] [31 29 -1 26] [32 30 -1 26] [-1 31 33 26] [-1 -1 -1 32] [35 26 -1 -1] [-1 34 -1 -1]]] hierarchy3 총 발견 갯수 : 8 [[[ 1 -1 -1 -1] [ 2 0 -1 -1] [10 1 3 -1] [ 5 -1 4 2] [-1 -1 -1 3] [ 6 3 -1 2] [ 7 5 -1 2] [ 8 6 -1 2] [-1 7 9 2] [-1 -1 -1 8] [18 2 11 -1] [13 -1 12 10] [-1 -1 -1 11] [14 11 -1 10] [15 13 -1 10] [16 14 -1 10] [-1 15 17 10] [-1 -1 -1 16] [26 10 19 -1] [21 -1 20 18] [-1 -1 -1 19] [22 19 -1 18] [23 21 -1 18] [24 22 -1 18] [-1 23 25 18] [-1 -1 -1 24] [34 18 27 -1] [29 -1 28 26] [-1 -1 -1 27] [30 27 -1 26] [31 29 -1 26] [32 30 -1 26] [-1 31 33 26] [-1 -1 -1 32] [35 26 -1 -1] [-1 34 -1 -1]]] 'img_copy1'
'img_copy2'
'img_copy3'
In [8]:
import cv2
img = cv2.imread('../Media/images/card.png')
img_copy = 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_LIST, cv2.CHAIN_APPROX_NONE)
COLOR = (0,200,0) # 녹색
for cnt in contours:
# 각 윤곽선에 대해 최소 크기의 사각형을 그려 객체를 감쌉.
x, y, width, height = cv2.boundingRect(cnt)
cv2.rectangle(img_copy, (x,y), (x+width, y+height), COLOR, 2) # 사각형 그림, 왼쪽 위 꼭짓점 좌표, 오른쪽 아래 꼭짓점 좌표, 컬러, 두께
cv2.imshow('img_copy',img_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()
show_image_with_pil(img_copy, 'img_copy')
'img_copy'
면적 설정¶
contourArea()
In [9]:
import cv2
img = cv2.imread('../Media/images/card.png')
img_copy = 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_LIST, cv2.CHAIN_APPROX_NONE)
COLOR = (0,200,0) # 녹색
for cnt in contours:
# 면적 설정
if cv2.contourArea(cnt) > 25000: # 가로 130 * 세로 205 = 26,650 (카드한장 사이)
x, y, width, height = cv2.boundingRect(cnt)
cv2.rectangle(img_copy, (x,y), (x+width, y+height), COLOR, 2) # 사각형 그림
cv2.imshow('img_copy',img_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()
show_image_with_pil(img_copy, 'img_copy')
'img_copy'
'Python > OpenCV' 카테고리의 다른 글
16. 이미지 검출(경계선) (0) | 2024.11.19 |
---|---|
15. 이미지 변환(열림 & 닫힘) (0) | 2024.11.19 |
14. 이미지 변환(팽창) (0) | 2024.11.18 |
13_2. 이미지 변형(이진화) (0) | 2024.11.18 |
13_1. 이미지 변형(이진화) (0) | 2024.11.18 |