OpenCV Review 07

2400·2025년 3월 16일
post-thumbnail

이미지 세그멘테이션

  1. 필요한 라이브러리 임포트
import cv2 as cv
import numpy as np
  1. 이미지 로드 및 초기 설정
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)    # 좌클릭(전경) 및 우클릭(배경) 표시 색상
  1. 마우스 이벤트 처리 함수 정의
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)    # 표시 이미지 업데이트
  1. event: 마우스 이벤트 타입을 나타내는 정수값

    • cv.EVENT_LBUTTONDOWN: 왼쪽 버튼 클릭이 발생했을 때
    • cv.EVENT_RBUTTONDOWN: 오른쪽 버튼 클릭이 발생했을 때
    • cv.EVENT_MOUSEMOVE: 마우스 이동이 발생했을 때
  2. x, y: 이벤트가 발생한 픽셀 좌표

    • 이미지 내의 마우스 커서 위치를 나타냄
    • x는 수평 좌표(열), y는 수직 좌표(행)
    • 좌표 원점(0,0)은 이미지의 좌측 상단
  3. flags: 마우스 이벤트와 함께 발생한 상태 플래그

    • cv.EVENT_FLAG_LBUTTON: 왼쪽 버튼이 눌린 상태
    • cv.EVENT_FLAG_RBUTTON: 오른쪽 버튼이 눌린 상태
    • cv.EVENT_FLAG_MBUTTON: 가운데 버튼이 눌린 상태
  4. param: 사용자 정의 파라미터

    • cv.setMouseCallback의 세 번째 인자로 전달된 추가 데이터
    • 이 코드에서는 사용되지 않았지만, 필요시 추가 데이터를 콜백 함수에 전달할 수 있음
    • 예를 들어, 여러 이미지 작업 시 현재 작업 중인 이미지 참조 등을 전달할 수 있음
  • 왼쪽 마우스 버튼 이벤트: 전경으로 표시할 영역을 파란색(LColor)으로 마킹하고, 마스크에 cv.GC_FGD(확실한 전경) 값을 설정
  • 오른쪽 마우스 버튼 이벤트: 배경으로 표시할 영역을 빨간색(RColor)으로 마킹하고, 마스크에 cv.GC_BGD(확실한 배경) 값을 설정
  • 드래그 동작도 같은 방식으로 처리하되 연속적인 마우스 이동 이벤트와 버튼 상태 확인을 통해 구현

cv.circle 함수의 -1 매개변수는 원을 채우도록 지정하여, 브러시 효과를 구현하는 데 사용

  1. 윈도우 설정 및 메인 루프
cv.namedWindow('painting')    # 윈도우 생성
cv.setMouseCallback('painting', painting)    # 마우스 이벤트 콜백 함수 설정

while(True):    # 'q' 키를 누를 때까지 대기
    if cv.waitKey(1) == ord('q'):
        break
  1. GrabCut 알고리즘 실행
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)    # 결과 이미지 표시
  1. 프로그램 종료 대기
cv.waitKey()    # 키 입력 대기
cv.destroyAllWindows()    # 모든 창 닫기

이진 영역 특징 추출

  1. 필요한 라이브러리 임포트 및 이미지 준비
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)  # 변환된 이미지 표시
  1. 외곽선 검출
contours, hierarchy = cv.findContours(img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE)
  • cv.RETR_EXTERNAL: 가장 바깥쪽 외곽선만 검출
  • cv.CHAIN_APPROX_NONE: 모든 외곽선 점을 보존
  1. 검출된 외곽선 시각화
img2 = cv.cvtColor(img, cv.COLOR_GRAY2BGR)  # 그레이스케일 이미지를 BGR 컬러로 변환
cv.drawContours(img2, contours, -1, (255,0,255), 2)  # 모든 외곽선을 핑크색으로 그림
cv.imshow('Horse with contour', img2)
  1. 영역 특징 계산
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)  # 원형도 계산
  • 모멘트: 객체의 형태에 관한 통계적 측정값
  • 무게중심: 객체의 중심점
  • 원형도: 값이 1에 가까울수록 완벽한 원에 가까움
  1. 특징값 출력
print('area=', area, '\n center=', cx, cy, '\n perimeter', perimeter, 'roundness', roundness)
  1. 다각형 근사화 및 볼록 껍질 계산
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: 객체를 둘러싸는 볼록한 형태의 껍질 계산
  1. 결과 표시 및 창 닫기
cv.imshow('horse with line segments and convex hull', img3)
cv.waitKey()
cv.destroyAllWindows()

정리

1. GrabCut 알고리즘

GrabCut은 이미지 세그멘테이션을 위한 대화형 알고리즘으로, 사용자가 제공하는 힌트를 바탕으로 전경과 배경을 분리한다.

작동 원리:

  • 가우시안 혼합 모델(GMM)을 사용하여 전경과 배경의 색상 분포를 모델링
  • 그래프 컷(Graph Cut) 최적화 기법을 적용하여 전경과 배경을 최적으로 분리
  • 각 픽셀을 네 가지 상태(확실한 배경, 확실한 전경, 배경 가능성, 전경 가능성)로 분류
  • 사용자 입력에 따라 반복적으로 세그멘테이션을 개선

장점:

  • 복잡한 배경에서도 정확한 세그멘테이션이 가능하다
  • 최소한의 사용자 상호작용으로 높은 품질의 결과를 제공한다

2. 외곽선 검출 알고리즘 (findContours)

이진화된 이미지에서 객체의 경계를 찾아내는 알고리즘

작동 원리:

  • 이진 이미지를 스캔하여 객체의 경계점을 추적
  • 연결된 픽셀들의 집합으로 외곽선을 표현
  • 다양한 계층 구조(hierarchy) 옵션을 통해 내부 외곽선과 외부 외곽선 관계를 설정가능

주요 옵션:

  • RETR_EXTERNAL: 가장 바깥쪽 외곽선만 검출
  • CHAIN_APPROX_NONE: 모든 외곽선 점을 보존

3. 모멘트 계산 (moments)

객체의 형태와 분포를 통계적으로 설명하는 값들을 계산

주요 모멘트:

  • 공간 모멘트(m00, m10, m01 등): 객체의 면적과 무게중심을 계산하는 데 사용
  • 중심 모멘트: 객체의 회전에 불변한 특성 제공
  • 표준화된 중심 모멘트: 크기 변화에도 불변한 특성 제공

응용:

  • 무게중심 계산: cx = m10/m00, cy = m01/m00
  • 객체 인식 및 분류에 사용되는 형태 기술자 생성

4. 다각형 근사화 (approxPolyDP)

복잡한 외곽선을 더 단순한 다각형으로 근사화하는 알고리즘

작동 원리:

  • Douglas-Peucker 알고리즘을 사용하여 외곽선을 근사화
  • 지정된 정확도(epsilon) 내에서 가능한 적은 수의 점으로 외곽선을 표현
  • 정확도 매개변수로 근사화의 정밀도를 조절 가능

응용:

  • 형태 단순화
  • 특징 추출
  • 컴퓨팅 효율성 향상

5. 볼록 껍질 계산 (convexHull)

객체를 완전히 둘러싸는 가장 작은 볼록 다각형을 찾는 알고리즘

작동 원리:

  • 모든 점을 포함하는 가장 작은 볼록 다각형을 계산
  • Graham scan 또는 Jarvis march와 같은 알고리즘을 사용

응용:

  • 오목한 부분의 식별
  • 결함 검출
  • 모양 분석

6. 원형도 계산

객체가 얼마나 원에 가까운지 측정하는 지표

계산 방법:

roundness = (4.0 * np.pi * area) / (perimeter * perimeter)

특징:

  • 값이 1에 가까울수록 완벽한 원에 가깝다.
  • 값이 작을수록 비원형(길쭉하거나 복잡한 형태)임을 나타낸다.
  • 스케일 및 회전에 불변하는 특성
profile
시즌 2의 공부기록 - Artificial Intelligence & AeroSpace

0개의 댓글