오늘은 openCV를 이용해서 싸그리 검열해보자.
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('data/lena.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
kernal = np.ones((5,5), np.uint8)
blur = cv2.blur(img, (5, 5))
canny = cv2.Canny(img, 100, 200)
dilation = cv2.dilate(canny, kernal, iterations = 1)
eroded = cv2.erode(dilation, kernal, iterations = 1)
cv2.imshow('Blur', blur)
cv2.imshow('Canny', canny)
cv2.imshow('Dilation', dilation)
cv2.imshow('Erode', eroded)
cv2.waitKey()
cv2.destroyAllWindows()
위 코드는 Blur, Canny, Erode,Dilation 를 사진에 적용한 코드다.
Blur는 이미지의 노이즈를 감소시키거나 선명도를 줄이는 데 사용된다. 주로 이미지를 부드럽게 만들어 더 이상한 노이즈나 세부적인 구조를 감춘다. 이를 위해 이미지의 각 픽셀을 중심으로 주변 픽셀을 고려하여 값을 평균화한다. 이렇게 함으로써 이미지의 부드러움을 증가시키고 경계를 흐리게 만든다.
Canny는 엣지 검출기는 이미지의 엣지를 검출하는 데 사용된다. 이는 이미지에서 갑작스러운 밝기 변화를 찾아내어 엣지로 추정한다. 이러한 엣지는 물체의 경계를 나타내는 데 유용하다. 캐니 엣지 검출은 여러 단계로 이루어지며, 노이즈 제거, 경계 강도 추정, 비최대 억제, 이중 임계값 처리 및 엣지 연결이 포함된다.
Erode는 이미지 처리에서 모양을 축소시키는 데 사용된다. 이는 이미지에서 작은 세부 정보를 제거하거나 물체를 축소하는 데 유용하다. 이 작업은 이미지의 각 픽셀을 중심으로 커널(필터)을 슬라이딩하고 주변 픽셀 값 중 가장 작은 값을 선택하여 중심 픽셀의 값을 대체함으로써 수행된다.
Dilation은 Erode와 반대로 이미지에서 모양을 확장시키는 데 사용된다. 이는 물체의 크기를 키우거나 작은 구멍을 메우는 데 유용하다. 이 작업은 이미지의 각 픽셀을 중심으로 커널(필터)을 슬라이딩하고 주변 픽셀 값 중 가장 큰 값을 선택하여 중심 픽셀의 값을 대체함으로써 수행된다.
애핀 변환(Affine Transformation)은 기하학적인 변환 중 하나로, 원래의 객체를 층이나 크기를 조정하거나 회전시키는 것을 포함한다. 이 변환은 선의 평행성을 보존하며 직선은 직선으로 변환된다. 여러 가지 형태의 애핀 변환에는 다음과 같은 것들이 있다.
이동은 객체를 지정된 벡터만큼 평행 이동시키는 변환이며, 각 점의 좌표에 일정한 값을 더하거나 뺌으로써 수행된다. 예를 들어, (x, y) 좌표가 (dx, dy)만큼 이동하면 새로운 좌표는 (x+dx, y+dy)가 된다.
회전은 객체를 지정된 각도만큼 회전시키는 변환이며, 중심점을 중심으로 수행된다. 회전 변환은 원점을 기준으로 공식을 사용하여 새로운 좌표를 계산하여 수행된다.
크기 조절은 객체의 크기를 변경하는 변환이다. 이는 각 좌표에 대해 스케일링 요인을 곱함으로써 수행된다. 이 때, 각 차원(가로 및 세로)별로 다른 스케일링 요소를 사용할 수 있다.
전단은 객체를 지정된 방향으로 기울이는 변환이다. 이는 각 좌표에 대해 추가적인 값을 더함으로써 수행된다. 전단 변환은 가로 또는 세로 방향으로만 수행될 수도 있다.
애핀 변환은 이미지 처리, 컴퓨터 비전, 그래픽스 및 기타 관련 분야에서 널리 사용된다. 예를 들어, 이미지의 크기를 조절하거나 회전시키는 데 사용되며, 이미지의 일부 영역을 왜곡하여 특정 작업에 더 적합하게 만드는 데에도 활용될 수 있다.
import cv2
img = cv2.imread('data/god.jpg')
print(img.shape)
imgResize = cv2.resize(img, (1000, 500))
imgCropped = img[0:200, 200:500]
cv2.imshow('image',img)
cv2.imshow('Resized',imgResize)
cv2.imshow('Cropped',imgCropped)
cv2.waitKey()
cv2.destroyAllWindows()
위와 같이 코드를 짜면 사진을 크롭할 수 있다.
import cv2
import numpy as np
img = cv2.imread('data/god.jpg',0)
rows,cols = img.shape
M1 = np.float32([[1,0,100],[0,1,50]])
dst1 = cv2.warpAffine(img,M1,(cols,rows))
M2 = cv2.getRotationMatrix2D((cols/2,rows/2),90,1)
dst2 = cv2.warpAffine(img,M2,(cols,rows))
cv2.imshow('img',img)
cv2.imshow('dst1',dst1)
cv2.imshow('dst2',dst2)
cv2.waitKey(0)
cv2.destroyAllWindows()
이렇게 기하학적 변환도 줄 수 있다.
Contour은 이미지에서 연속된 점으로 이루어진 동일한 색상 또는 강도를 가진 영역의 경계를 나타낸다. 윤곽선은 객체의 외형을 파악하고 분석하는 데 사용된다. openCV와 같은 이미지 처리 라이브러리에서 윤곽선을 찾고 분석하는 기능이 많이 제공된다.
윤곽선을 찾는 과정은 다음과 같다.
전처리(Preprocessing)
이미지를 그레이스케일 또는 이진화하여 윤곽선을 더 쉽게 검출할 수 있도록 전처리를 수행한다.
윤곽선 검출(Finding Contours):
전처리된 이미지에서 윤곽선을 검출한다. 이를 위해 주로 흑백 이미지에서 빛이 밝은 영역의 윤곽선을 찾는 방법이 사용된다. OpenCV에서는 findContours 함수를 사용하여 윤곽선을 검출할 수 있다.
윤곽선 표시(Visualizing Contours):
검출된 윤곽선을 이미지에 표시한다. 이를 통해 윤곽선을 시각적으로 확인할 수 있다.
윤곽선 특성 추출(Extracting Contour Features):
윤곽선의 특성(예: 면적, 둘레, 중심점 등)을 추출하여 객체를 식별하거나 분석하는 데 사용된다.
내 친구 노트북 사진을 마구마구 찹찹해보자.
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('data/chin9.jpg')
imgResize = cv2.resize(img, (1000, 500))
kernal = np.ones((5,5), np.uint8)
canny = cv2.Canny(imgResize, 100, 200)
cv2.imshow('Canny', canny)
cv2.waitKey()
cv2.destroyAllWindows()
import cv2
import numpy as np
img = cv2.imread('data/notebook.jpg')
imgResize = cv2.resize(img, (800, 800))
rows, cols = imgResize.shape[:2]
center = (cols / 2, rows / 2)
angle = -55
scale = 1.0
rotation_matrix = cv2.getRotationMatrix2D(center, angle, scale)
rotated_img = cv2.warpAffine(imgResize, rotation_matrix, (cols, rows))
cv2.imshow('Rotated', rotated_img)
cv2.waitKey()
cv2.destroyAllWindows()
노트북을 벌떡 세워봤다.
친구 노트북이 어떻게 생겨먹은 녀석인지 알아보자.
import cv2
import matplotlib.pyplot as plt
block_size = 9
C = 5
img = cv2.imread('data/notebook.jpg', cv2.IMREAD_GRAYSCALE)
img = cv2.resize(img, (800, 500))
img = cv2.blur(img, (5,7))
img = cv2.adaptiveThreshold(img, 205, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, block_size, C)
contours, _ = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
for contour in contours:
approx = cv2.approxPolyDP(contour, 0.01* cv2.arcLength(contour, True), True)
cnt = approx
area = cv2.contourArea(cnt)
if area < 4700:
continue;
cv2.drawContours(img, [approx], 0, (0, 123, 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(0)
cv2.destroyAllWindows()
이렇게 하면 사진에서 도형을 검출할 수 있다.
Rectangle이라 한다.
Haar Cascade는 객체 인식을 위한 컴퓨터 비전 및 이미지 처리 기술 중 하나다. 특히, 얼굴, 눈, 손가락, 차량 번호판 등과 같은 객체를 식별하는 데 널리 사용된다. 이 기술은 머신 러닝 기술 중 하나인 기계 학습을 기반으로 한다.
Haar Cascade는 특정 객체의 특징을 나타내는 학습된 XML 파일이다. 이러한 파일은 학습된 객체에 대한 패턴을 정의하고, 이 패턴을 사용하여 이미지에서 해당 객체를 식별한다. 일반적으로, Haar Cascade는 다음과 같은 단계로 구성된다
Haar Cascade를 생성하기 위해 양성 이미지(찾으려는 객체가 포함된 이미지)를 수집한다.
양성 이미지와 유사한 크기와 해상도를 가진 음성 이미지(찾으려는 객체가 없는 이미지)를 수집한다.
양성 및 음성 이미지에서 Haar 특징을 계산한다. 이러한 특징은 객체의 특징을 설명하는데 사용된다. 이러한 특징은 각각의 픽셀의 높이, 너비, 밝기 등에 기반한다.
Adaboost 알고리즘을 사용하여 Haar 특징을 기반으로 하는 분류기를 학습한다. 이 분류기는 양성 및 음성 이미지를 구별하도록 학습된다.
다수의 Adaboost 분류기를 결합하여 Cascade를 생성한다. Cascade는 다단계 검출 프로세스를 나타낸다. 각 단계는 특정 정확도를 가지고 객체를 거부하거나 검출하는 역할을 수행한다.
학습된 Haar Cascade를 사용하여 새로운 이미지에서 객체를 검출한다
. 이미지에서 슬라이딩 윈도우 기법을 사용하여 객체 후보를 생성하고, 각 후보가 Cascade를 통과하여 실제 객체인지 판별된다.
이제 사람들 얼굴이란 얼굴은 싸그리빡빡 가려버리는 모자이크 프로그램을 짜보자.
import cv2
# 웹캠 비디오 스트림 열기
cap = cv2.VideoCapture(0)
# 얼굴 감지를 위한 Haar Cascade 분류기 불러오기
faceCascade = cv2.CascadeClassifier("data/haarcascade_frontalface_default.xml")
# 무한 반복
while True:
# 비디오 프레임 읽기
ret, frame = cap.read()
# 그레이스케일로 변환
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 얼굴 감지
faces = faceCascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
# 감지된 얼굴 주위에 재미있는 효과 적용
for (x, y, w, h) in faces:
# 얼굴 영역 잘라내기
roi = frame[y:y+h, x:x+w]
# 얼굴 영역 축소 후 확대하여 특별한 효과 적용
small_roi = cv2.resize(roi, (0, 0), fx=0.05, fy=0.05)
large_roi = cv2.resize(small_roi, (w, h), interpolation=cv2.INTER_NEAREST)
# 특별한 효과를 적용한 영역 다시 원본 크기로 복원
frame[y:y+h, x:x+w] = large_roi
# 프레임 화면에 표시
cv2.imshow('Webcam Face Detection', frame)
# 'q' 키를 누르면 종료
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 비디오 스트림 및 창 해제
cap.release()
cv2.destroyAllWindows()
위와같이 범위를 정해서 확대했다가 다시 축소시키면 화질이 깨져서 모자이크가 되는 원리다. 잘생긴 얼굴이 보이지 않아서 아쉽겠지만 다음 글에서 돌아오겠다.