Blur, Canny, Erode, Dilation과 같은 기본적인 이미지 처리 방법와 Haar Cascade를 활용한 얼굴 인식에 대해서 알아보자.
이미지에 블러 효과를 주어 디테일을 줄이고, 노이즈를 제거하는 테크닉
사진에서 배경을 흐리게 하거나, 얼굴 식별을 어렵게 만드는 등의 용도로 사용된다.
사진이나 영상이 너무 선명해서 안 좋을 때도 눈에 덜 거슬리고 보기 좋도록 쓰기도 한다.
이미지에서 엣지(경계선)를 검출하는 알고리즘
Canny Edge Detection은 사진에서 중요한 선을 찾아주는 건데, 사람 얼굴이나 물체의 경계선을 드러낸다.
이미지의 높은 변화율을 찾아내어 객체의 외곽선 추출이나, 형태 분석에 유용하다.
모폴로지 기법: 영상 내부 객체의 형태와 구조를 분석하고 처리하는 기법
둘을 묶어 모폴로지 기법이라 부른다.
Erode(침식)는 필터 내에 검은색이 하나라도 있다면 검은색을 반환하여 결과적으로 이미지의 흰색 부분을 침식한다.
Dilation(팽창)는 필터 내에 흰색이 하나라도 있다면 흰색을 반환하여 결과적으로 이미지의 흰색 부분을 확장시킨다.
보통 사진에서 잡다한 부분을 치우고 중요한 부분만 부각시킬 때 사용한다.
affine 변환: 이미지를 평행 이동, 회전, 크기 변환 등을 통해 변형하는 변환
이미지에서 연속된 동일한 색상 또는 강도를 가지고 있는 영역의 경계를 나타내는 것
cv2.findContours(src, mode, method, offset) → contours, hierarchy 함수를 사용하여 외곽선을 검출한다. 외곽선을 통해 객체의 넓이, 둘레 길이, 바운딩 박스 등 다양한 특징을 추출할 수 있다. 이를 통해 객체의 크기, 모양 등을 분석할 수 있다~
아래의 노트북 사진에서 도형을 추출해 보자.
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()
객체 검출을 위한 기계 학습 기반의 접근 방식 중 하나
얼굴 검출에 많이 사용되며, 여러 단계의 분류기를 거쳐 객체를 검출한다.
빠르고 효율적으로 이미지 내에서 얼굴과 같은 객체를 찾을 수 있으며, 이는 보안, 모니터링, 인터랙티브 미디어 등 다양한 분야에서 활용될 수 있다.
얼굴 모자이크를 감상하러 가보자.
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 써서 직사각형으로 만들어보겠다.
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()
끝~