import cv2 as cv
import numpy as np
img = cv.imread('./.data/frieren.png')
img_show = np.copy(img) # 시각화를 위한 이미지 복사본 생성
mask = np.zeros((img.shape[0], img.shape[1]), np.uint8) # 마스크 초기화
mask[:,:] = cv.GC_PR_BGD # 모든 픽셀을 '배경일 가능성이 높음'으로 설정(GrabCut 알고리즘의 '배경일 가능성이 높음(Probable Background)'을 나타내는 상수값)
BrushSize = 9 # 브러시 크기 설정
LColor, RColor = (255,0,0), (0,0,255) # 좌클릭(전경) 및 우클릭(배경) 표시 색상
def painting(event, x, y, flags, param):
if event == cv.EVENT_LBUTTONDOWN: # 좌클릭 - 전경 표시
cv.circle(img_show, (x,y), BrushSize, LColor, -1)
cv.circle(mask, (x,y), BrushSize, cv.GC_FGD, -1)
elif event == cv.EVENT_RBUTTONDOWN: # 우클릭 - 배경 표시
cv.circle(img_show, (x,y), BrushSize, RColor, -1)
cv.circle(mask, (x,y), BrushSize, cv.GC_BGD, -1)
elif event == cv.EVENT_MOUSEMOVE and flags == cv.EVENT_FLAG_LBUTTON: # 좌클릭 드래그
cv.circle(img_show, (x,y), BrushSize, LColor, -1)
cv.circle(mask, (x,y), BrushSize, cv.GC_FGD, -1)
elif event == cv.EVENT_MOUSEMOVE and flags == cv.EVENT_FLAG_RBUTTON: # 우클릭 드래그
cv.circle(img_show, (x,y), BrushSize, RColor, -1)
cv.circle(mask, (x,y), BrushSize, cv.GC_BGD, -1)
cv.imshow('painting', img_show) # 표시 이미지 업데이트
event: 마우스 이벤트 타입을 나타내는 정수값
cv.EVENT_LBUTTONDOWN: 왼쪽 버튼 클릭이 발생했을 때cv.EVENT_RBUTTONDOWN: 오른쪽 버튼 클릭이 발생했을 때cv.EVENT_MOUSEMOVE: 마우스 이동이 발생했을 때x, y: 이벤트가 발생한 픽셀 좌표
flags: 마우스 이벤트와 함께 발생한 상태 플래그
cv.EVENT_FLAG_LBUTTON: 왼쪽 버튼이 눌린 상태cv.EVENT_FLAG_RBUTTON: 오른쪽 버튼이 눌린 상태cv.EVENT_FLAG_MBUTTON: 가운데 버튼이 눌린 상태param: 사용자 정의 파라미터
cv.setMouseCallback의 세 번째 인자로 전달된 추가 데이터LColor)으로 마킹하고, 마스크에 cv.GC_FGD(확실한 전경) 값을 설정RColor)으로 마킹하고, 마스크에 cv.GC_BGD(확실한 배경) 값을 설정cv.circle 함수의 -1 매개변수는 원을 채우도록 지정하여, 브러시 효과를 구현하는 데 사용
cv.namedWindow('painting') # 윈도우 생성
cv.setMouseCallback('painting', painting) # 마우스 이벤트 콜백 함수 설정
while(True): # 'q' 키를 누를 때까지 대기
if cv.waitKey(1) == ord('q'):
break
background = np.zeros((1,65), np.float64) # 배경 모델 초기화
foreground = np.zeros((1,65), np.float64) # 전경 모델 초기화
# 사용자가 표시한 마스크를 기반으로 GrabCut 실행
cv.grabCut(img, mask, None, background, foreground, 5, cv.GC_INIT_WITH_MASK)
# 최종 마스크 생성 (배경=0, 전경=1)
mask2 = np.where((mask == cv.GC_BGD)|(mask == cv.GC_PR_BGD), 0, 1).astype('uint8')
# 원본 이미지에 마스크 적용하여 배경 제거
grab = img * mask2[:,:,np.newaxis]
cv.imshow('Grab cut image', grab) # 결과 이미지 표시
cv.waitKey() # 키 입력 대기
cv.destroyAllWindows() # 모든 창 닫기
import skimage
import numpy as np
import cv2 as cv
orig = skimage.data.horse() # scikit-image 라이브러리에서 말 이미지 로드
img = 255 - np.uint8(orig) * 255 # 이미지 반전 및 8비트 정수형으로 변환
cv.imshow('Horse', img) # 변환된 이미지 표시
contours, hierarchy = cv.findContours(img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE)
cv.RETR_EXTERNAL: 가장 바깥쪽 외곽선만 검출cv.CHAIN_APPROX_NONE: 모든 외곽선 점을 보존img2 = cv.cvtColor(img, cv.COLOR_GRAY2BGR) # 그레이스케일 이미지를 BGR 컬러로 변환
cv.drawContours(img2, contours, -1, (255,0,255), 2) # 모든 외곽선을 핑크색으로 그림
cv.imshow('Horse with contour', img2)
contour = contours[0] # 첫 번째(그리고 이 경우 유일한) 외곽선 선택
m = cv.moments(contour) # 모멘트 계산
area = cv.contourArea(contour) # 면적 계산
cx, cy = m['m10']/m['m00'], m['m01']/m['m00'] # 무게중심 좌표 계산
perimeter = cv.arcLength(contour, True) # 둘레 길이 계산
roundness = (4.0 * np.pi * area)/(perimeter * perimeter) # 원형도 계산
print('area=', area, '\n center=', cx, cy, '\n perimeter', perimeter, 'roundness', roundness)
img3 = cv.cvtColor(img, cv.COLOR_GRAY2BGR) # 그레이스케일 이미지를 BGR 컬러로 변환
# 외곽선을 단순화하여 다각형으로 근사화
contour_approx = cv.approxPolyDP(contour, 8, True)
cv.drawContours(img3, [contour_approx], -1, (0,255,0), 2) # 녹색으로 그림
# 볼록 껍질 계산
hull = cv.convexHull(contour)
hull = hull.reshape(1, hull.shape[0], hull.shape[2])
cv.drawContours(img3, hull, -1, (0,0,255), 2) # 빨간색으로 그림
approxPolyDP: 외곽선을 더 적은 수의 점으로 근사화 (값 8은 근사화 정확도)convexHull: 객체를 둘러싸는 볼록한 형태의 껍질 계산cv.imshow('horse with line segments and convex hull', img3)
cv.waitKey()
cv.destroyAllWindows()
GrabCut은 이미지 세그멘테이션을 위한 대화형 알고리즘으로, 사용자가 제공하는 힌트를 바탕으로 전경과 배경을 분리한다.
작동 원리:
장점:
이진화된 이미지에서 객체의 경계를 찾아내는 알고리즘
작동 원리:
주요 옵션:
RETR_EXTERNAL: 가장 바깥쪽 외곽선만 검출CHAIN_APPROX_NONE: 모든 외곽선 점을 보존객체의 형태와 분포를 통계적으로 설명하는 값들을 계산
주요 모멘트:
응용:
cx = m10/m00, cy = m01/m00복잡한 외곽선을 더 단순한 다각형으로 근사화하는 알고리즘
작동 원리:
응용:
객체를 완전히 둘러싸는 가장 작은 볼록 다각형을 찾는 알고리즘
작동 원리:
응용:
객체가 얼마나 원에 가까운지 측정하는 지표
계산 방법:
roundness = (4.0 * np.pi * area) / (perimeter * perimeter)
특징: