[AI] OpenCV Blur부터 Haar Cascade까지

심지혜·2024년 3월 27일
0
post-thumbnail

Blur, Canny, Erode, Dilation과 같은 기본적인 이미지 처리 방법와 Haar Cascade를 활용한 얼굴 인식에 대해서 알아보자.

Blur

이미지에 블러 효과를 주어 디테일을 줄이고, 노이즈를 제거하는 테크닉

사진에서 배경을 흐리게 하거나, 얼굴 식별을 어렵게 만드는 등의 용도로 사용된다.
사진이나 영상이 너무 선명해서 안 좋을 때도 눈에 덜 거슬리고 보기 좋도록 쓰기도 한다.

Canny Edge Detection

이미지에서 엣지(경계선)를 검출하는 알고리즘

Canny Edge Detection은 사진에서 중요한 선을 찾아주는 건데, 사람 얼굴이나 물체의 경계선을 드러낸다.
이미지의 높은 변화율을 찾아내어 객체의 외곽선 추출이나, 형태 분석에 유용하다.

Erode과 Dilation

모폴로지 기법: 영상 내부 객체의 형태와 구조를 분석하고 처리하는 기법

둘을 묶어 모폴로지 기법이라 부른다.
Erode(침식)는 필터 내에 검은색이 하나라도 있다면 검은색을 반환하여 결과적으로 이미지의 흰색 부분을 침식한다.
Dilation(팽창)는 필터 내에 흰색이 하나라도 있다면 흰색을 반환하여 결과적으로 이미지의 흰색 부분을 확장시킨다.
보통 사진에서 잡다한 부분을 치우고 중요한 부분만 부각시킬 때 사용한다.

여러가지 affine

affine 변환: 이미지를 평행 이동, 회전, 크기 변환 등을 통해 변형하는 변환

  • 이동(Translation)
    이미지나 객체를 특정 방향으로 이동시킨다. 좌표를 특정하게 변환하여 이미지를 이동한다.
  • 회전(Rotation)
    이미지나 객체를 특정 각도만큼 회전시킨다. 이미지의 중심점을 기준으로 회전한다.
  • 크기 변환(Scaling)
    이미지나 객체의 크기를 조절. 크기 조정은 이미지나 객체의 폭과 높이를 각각 다른 비율로 확대 또는 축소하여 수행된다.

Contour

이미지에서 연속된 동일한 색상 또는 강도를 가지고 있는 영역의 경계를 나타내는 것

cv2.findContours(src, mode, method, offset) → contours, hierarchy 함수를 사용하여 외곽선을 검출한다. 외곽선을 통해 객체의 넓이, 둘레 길이, 바운딩 박스 등 다양한 특징을 추출할 수 있다. 이를 통해 객체의 크기, 모양 등을 분석할 수 있다~

아래의 노트북 사진에서 도형을 추출해 보자.

1

import cv2
import numpy as np
# 이미지를 불러오고 크기 조정
img = cv2.imread('data/tablet.jpg')
img = cv2.resize(img, (800, 500))
# 이미지를 그레이스케일로 변환
imgGrey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Canny 엣지 검출기를 사용하여 엣지 검출
canny = cv2.Canny(imgGrey, 150, 150)
# 팽창 연산을 적용하여 엣지 더 뚜렷하게
kernal = np.ones((5,5), np.uint8)
dilation = cv2.dilate(canny, kernal, iterations = 1)
# 침식 연산을 적용하여 팽창된 엣지 세밀하게
eroded = cv2.erode(dilation, kernal, iterations = 1)
# 결과를 보여줍니다.
cv2.imshow("eroded", eroded)

# 이진화를 통해 배경과 전경 분리
_, thrash = cv2.threshold(eroded, 200, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(thrash, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 이진화된 이미지
cv2.imshow("thrash", thrash)

for contour in contours:
    if cv2.contourArea(contour) < 100:
        continue
    # 윤곽선을 근사화하여 도형을 인식
    approx = cv2.approxPolyDP(contour, 0.01* cv2.arcLength(contour, True), True)
    # 인식된 도형을 이미지에 그림
    cv2.drawContours(img, [approx], 0, (0, 255, 0), 5)
    # 도형의 이름을 표시할 위치
    x = approx.ravel()[0]
    y = approx.ravel()[1] - 5
    
    # 꼭짓점의 개수에 따라 도형의 이름을 결정, 이미지에 표시
    if len(approx) == 3:
        cv2.putText(img, "Triangle", (x, y), cv2.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 0))
    elif len(approx) == 4:
        x1, y1, w, h = cv2.boundingRect(approx)
        aspectRatio = float(w)/h
        print(aspectRatio)
        if aspectRatio >= 0.95 and aspectRatio <= 1.05:
            cv2.putText(img, "square", (x, y), cv2.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 0))
        else:
            cv2.putText(img, "rectangle", (x, y), cv2.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 0))
    elif len(approx) == 5:
        cv2.putText(img, "Pentagon", (x, y), cv2.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 0))
    elif len(approx) == 10:
        cv2.putText(img, "Star", (x, y), cv2.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 0))
    else:
        cv2.putText(img, "Circle", (x, y), cv2.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 0))

# 이미지 출력
cv2.imshow("shapes", img)
cv2.waitKey()
cv2.waitKey(1)
cv2.waitKey(1)
cv2.waitKey(1)
cv2.waitKey(1)
cv2.destroyAllWindows()

Haar Cascade

객체 검출을 위한 기계 학습 기반의 접근 방식 중 하나

얼굴 검출에 많이 사용되며, 여러 단계의 분류기를 거쳐 객체를 검출한다.
빠르고 효율적으로 이미지 내에서 얼굴과 같은 객체를 찾을 수 있으며, 이는 보안, 모니터링, 인터랙티브 미디어 등 다양한 분야에서 활용될 수 있다.

얼굴 모자이크를 감상하러 가보자.

2

import cv2

# 얼굴 감지를 위한 Haar Cascade 분류기 로드
faceCascade = cv2.CascadeClassifier("data/haarcascade_frontalface_default.xml")

# 카메라 장치 열기 (0은 기본 카메라를 의미)
cap = cv2.VideoCapture(0)

# 비디오 파일 저장을 위한 설정 (코덱, 파일명, FPS, 해상도)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640, 480))

while(cap.isOpened()):
    ret, frame = cap.read()
        if ret == True: 
        # 프레임을 그레이스케일로 변환
        imgGray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
                # 그레이스케일 이미지에서 얼굴 감지
        faces = faceCascade.detectMultiScale(imgGray, 1.1, 4)
        for (x, y, w, h) in faces:
            # 얼굴 영역(Region of Interest, ROI) 추출
            roi = frame[y:y+h, x:x+w]
            # 모자이크 효과 적용: ROI를 축소했다가 원래 크기로 확대
            factor = 30
            small_roi = cv2.resize(roi, (w//factor, h//factor))
            mosaic_roi = cv2.resize(small_roi, (w, h), interpolation=cv2.INTER_NEAREST)
            # 원본 프레임에 모자이크 처리된 ROI를 다시 적용
            frame[y:y+h, x:x+w] = mosaic_roi
        # 모자이크 처리된 프레임을 화면에 표시
        cv2.imshow('frame', frame)
    
        # 'q' 키를 누르면 끝
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

cap.release()
out.release()
cv2.destroyAllWindows()

모자이크가 잘 된다.

이번엔 affine까지 해서 노트북 사진에 canny로 외곽선 따고, 외곽선 잘 뜨게 하고, 사진 삐딱한 거 projective 써서 직사각형으로 만들어보겠다.

3

import cv2
import numpy as np

# 이미지 불러오기
img = cv2.imread('data/notebook.jpg')

# 이미지 크기 조정
img = cv2.resize(img, (800, 600))

# Canny로 외곽선 따기
imgGrey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
canny = cv2.Canny(imgGrey, 150, 150)

# 외곽선을 더 뚜렷하게 만들기
kernal = np.ones((5,5), np.uint8)
dilation = cv2.dilate(canny, kernal, iterations=1)
eroded = cv2.erode(dilation, kernal, iterations=1)
blurred = cv2.GaussianBlur(eroded, (5, 5), cv2.BORDER_DEFAULT)

# 원근 변환을 위한 소스 및 목표 좌표 설정
# 주의: 아래의 pts1과 pts2는 예시 값입니다. 실제 이미지에 맞게 조정해야 합니다.
pts1 = np.float32([[320, 15], [700, 215], [85, 610], [530, 780]])
pts2 = np.float32([[0, 0], [800, 0], [0, 600], [800, 600]])

# 원근 변환 행렬 계산
matrix = cv2.getPerspectiveTransform(pts1, pts2)

# 원근 변환 적용
result = cv2.warpPerspective(img, matrix, (800, 600))

cv2.imshow("Original Image", img)
cv2.imshow("Canny Edge", canny)
cv2.imshow("Dilation + Erosion", eroded)
cv2.imshow("Blurred Edge", blurred)
cv2.imshow("Perspective Transform", result)
cv2.waitKey(0)
cv2.destroyAllWindows()

끝~

0개의 댓글