[ML Research]Python을 이용한 데이터 분석과 이미지 처리(1)
업데이트:
안녕하세요~ 여러분! 😄
오늘은 Python을 이용한 데이터 분석과 이미지 처리에 대해 알아보도록 하겠습니다.
✍ 목차는 다음과 같습니다.
📖 목차
본문은 동빈나 유튜브의 ‘Python 데이터 분석과 이미지 처리’ 강의(7~18)를 참고하여 재구성하였으며 대부분의 실습은 CoLab 과 PyCharm을 이용하였습니다.
🌱 우선 OpenCV에 대해서 하나씩 살펴보도록 하겠습니다!
📱 OpenCV 소개
Open Source Computer Vision Library
컴퓨터 비전을 위한 오픈소스 라이브러리를 말합니다.
- 이미지 처리에 초점
- C, C++, Python 등에서 사용 가능
다음으로 OpenCV의 기본적인 사용법에 대해 살펴보겠습니다!
OpenCV의 기본적인 함수
OpenCV에서는 다음과 같은 함수를 자주 사용합니다.
cv2.imread(fileName, flag) : 이미지를 읽어 Numpy 객체로 만드는 함수
cv2.imshow(title, image) : 특정한 이미지를 화면에 출력하는 함수
cv2.imwrite(fileName, image) : 특정한 이미지를 파일로 저장하는 함수
cv2.waitKey(time) : 키보드 입력을 처리하는 함수
cv2.destroyAllWindows() : 화면의 모든 윈도우를 닫는 함수
💡 보충 ) CoLab에서의 이미지 출력
- CoLab은 Jupyter Notebook을 기반으로 동작하므로 Matplotib를 이용하여 이미지를 출력합니다.
- OpenCV는 BGR을 기준으로, Matplotlib은 RGB를 기준으로 한다는 차이가 있습니다.
import cv2
import matplotlib.pyplot as plt
img_basic = cv2.imread('cat.jpg', cv2.IMREAD_COLOR)
plt.imshow(cv2.cvtColor(img_basic, cv2.COLOR_BGR2RGB))
plt.show()
img_basic = cv2.cvtColor(img_basic, cv2.COLOR_BGR2GRAY)
plt.imshow(cv2.cvtColor(img_basic, cv2.COLOR_GRAY2RGB))
plt.show()
📷 OpenCV 이미지 처리 방법
🌱 이제 OpenCV를 이용하여 기본적인 이미지를 처리하는 방법에 대하여 하나씩 알아보겠습니다!
글은 전반적으로 간단한 설명과 예제 위주로 서술하였습니다. 자세한 설명은 강의를 참고하시기 바랍니다.
➕➖ OpenCV 이미지 연산
OpenCV를 활용한 이미지 크기 및 픽셀 정보 확인
import cv2
image = cv2.imread('cat.jpg')
# 픽셀 수 및 이미지 크기 확인
print(image.shape)
print(image.size)
# 이미지 Numpy 객체의 특정 픽셀을 가리킵니다.
px = image[100, 100]
# B, G, R 순서로 출력됩니다.
# (단, Gray Scale인 경우에는 B, G, R로 구분되지 않습니다.)
print(px)
# R 값만 출력하기
print(px[2])
(380, 441, 3)
502740
[111 151 179]
179
OpenCV를 활용한 특정 범위 픽셀 변경
아래에 두 연산을 비교해보면 동일하게 특정 범위의 값을 바꾸지만 아래의 슬라이싱연산 처리속도가 더 빠르다는 것을 알 수 있습니다.
import cv2
import matplotlib.pyplot as plt
import time
image = cv2.imread('cat.jpg')
start_time = time.time()
for i in range(0, 100):
for j in range(0, 100):
image[i, j] = [255, 255, 255]
print("--- %s seconds ---" % (time.time() - start_time))
start_time = time.time()
image[0:100, 0:100] = [0, 0, 0]
print("--- %s seconds ---" % (time.time() - start_time))
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.show()
-– 0.016465187072753906 seconds —
-– 0.0002148151397705078 seconds —
OpenCV를 활용한 ROI (Region of Interest: 관심 영역) 추출 및 복사
관심 영역을 지정하여 그 부분을 복사하여 추출하는 것이 가능합니다.
import cv2
import matplotlib.pyplot as plt
image = cv2.imread('cat.jpg')
# Numpy Slicing: ROI 처리 가능
roi = image[200:350, 50:200]
# ROI 단위로 이미지 복사하기
image[0:150, 0:150] = roi
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.show()
OpenCV를 활용한 픽셀별 색상 다루기
아래 예제는 R 값을 0으로 하여 G, B 값만으로 나타내었습니다.
import cv2
import matplotlib.pyplot as plt
image = cv2.imread('cat.jpg')
image[:, :, 2] = 0
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.show()
🎞 OpenCV 이미지 변형
이미지 크기 조절
- 💡 보간법(Interpolation) 이란 ?
크기가 변할 때 중간값을 가지거나 특정한 분포를 따르게 하여 매끄럽게 픽셀 사이의 값을 조절하는 방법을 말합니다.
cv2.resize(image, dsize, fx, fy, interpolation) : 이미지의 크기를 조절합니다.
- dsize : Manual Size
- fx : 가로 비율
- fy : 세로 비율
1) INTER_CUBIC : 사이즈를 크게 할 때 주로 사용합니다.
2) INTER_AREA : 사이즈를 작게 할 때 주로 사용합니다.
import cv2
import matplotlib.pyplot as plt
image = cv2.imread('cat.jpg')
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.show()
expand = cv2.resize(image, None, fx=2.0, fy=2.0, interpolation=cv2.INTER_CUBIC)
plt.imshow(cv2.cvtColor(expand, cv2.COLOR_BGR2RGB))
plt.show()
shrink = cv2.resize(image, None, fx=0.8, fy=0.8, interpolation=cv2.INTER_AREA)
plt.imshow(cv2.cvtColor(shrink, cv2.COLOR_BGR2RGB))
plt.show()
이미지 위치 변경
다음 함수를 사용하여 이미지 위치를 변경합니다.
cv2.warpAffine(image, M, dsize) : 이미지의 위치를 변경합니다.
- M : 변환 행렬
- dsize : Manual Size
💡 보충 ) 변환 행렬과 변환
- 변환 행렬의 다음과 같은 형태로 정의되고
- 이미지의 모든 좌표(a, b)는 다음의 좌표로 이동됩니다.
import cv2
import numpy as np
import matplotlib.pyplot as plt
image = cv2.imread('cat.jpg')
# 행과 열 정보만 저장합니다.
height, width = image.shape[:2]
M = np.float32([[1, 0, 50], [0, 1, 10]])
dst = cv2.warpAffine(image, M, (width, height))
plt.imshow(cv2.cvtColor(dst, cv2.COLOR_BGR2RGB))
plt.show()
🌀 이미지 회전
이미지 회전을 위해 다음 함수를 사용합니다.
cv2.getRotationMatrix2D(center, angle, scale) : 이미지 회전을 위한 변환 행렬을 생성합니다.
- center : 회전 중심
- angle : 회전 각도
- scale : Scale Factor
💡 보충 ) 회전 변환을 위한 행렬
- 회전 변환을 위한 행렬은 다음과 같습니다.
- 이때 무게 중심을 적용할 수 있는 회전 변환 식은 다음과 같이 정의할 수 있습니다.
import cv2
import numpy as np
import matplotlib.pyplot as plt
image = cv2.imread('cat.jpg')
# 행과 열 정보만 저장합니다.
height, width = image.shape[:2]
M = cv2.getRotationMatrix2D((width / 2, height / 2), 90, 0.5)
dst = cv2.warpAffine(image, M, (width, height))
plt.imshow(cv2.cvtColor(dst, cv2.COLOR_BGR2RGB))
plt.show()
🔰 OpenCV 이미지 합치기
다음 두 이미지를 합쳐보도록 하겠습니다.
이미지를 합치는 2가지 방법
아래의 두 함수를 이용하여 각각 이미지를 합쳐보도록 하겠습니다.
cv2.add() : Saturation 연산을 수행합니다.
- 0보다 작은면 0, 255보다 크면 255로 표현
np.add() : Modulo 연산을 수행합니다.
- 256은 0, 257은 1로 표현
import cv2
import matplotlib.pyplot as plt
image_1 = cv2.imread('image_1.jpg')
image_2 = cv2.imread('image_2.png')
result = cv2.add(image_1, image_2)
plt.imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
plt.show()
result = image_1 + image_2
plt.imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
plt.show()
〽 OpenCV 임계점 처리하기
다음과 같은 방법을 통하여 이미지의 임계점을 처리할 수 있습니다.
이미지의 기본 이진화
cv2.threshold(image, thresh, max_value, type) : 임계값을 기준으로 흑/백으로 분류하는 함수
- image : 처리할 Gray Scale 이미지
- thresh : 임계 값 (전체 픽셀에 적용)
- max_value : 임계 값을 넘었을 때 적용할 값
- type : 임계점을 처리하는 방식
1) THRESH_BINARY : 임계 값보다 크면 max_value, 작으면 0
2) THRESH_BINARY_INV : 임계 값보다 작으면 max_value, 크면 0
3) THRESH_TRUNC : 임계 값보다 크면 임계 값, 작으면 그대로
4) THRESH_TOZERO : 임계 값보다 크면 그대로, 작으면 0
5) THRESH_TOZERO_INV : 임계 값보다 크면 0, 작으면 그대로
import cv2
import matplotlib.pyplot as plt
image = cv2.imread('gray_image.jpg', cv2.IMREAD_GRAYSCALE)
images = []
ret, thres1 = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY)
ret, thres2 = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY_INV)
ret, thres3 = cv2.threshold(image, 127, 255, cv2.THRESH_TRUNC)
ret, thres4 = cv2.threshold(image, 127, 255, cv2.THRESH_TOZERO)
ret, thres5 = cv2.threshold(image, 127, 255, cv2.THRESH_TOZERO_INV)
images.append(thres1)
images.append(thres2)
images.append(thres3)
images.append(thres4)
images.append(thres5)
for i in images:
plt.imshow(cv2.cvtColor(i, cv2.COLOR_GRAY2RGB))
plt.show()
이미지의 적응 임계점 처리
하나의 이미지에 다수의 조명 상태가 존재하는 경우 적용하는 방법입니다.
cv2.adaptiveThreshold(image, max_value, adaptive_method, type, block_size, C) : 적응 임계점 처리 함수
- max_value : 임계 값을 넘었을 때 적용할 값
- adaptive_method : 임계 값을 결정하는 계산 방법
ADAPTIVE_THRESH_MEAN_C : 주변영역의 평균값으로 결정
ADAPTIVE_THRESH_GAUSSIAN_C - type : 임계점을 처리하는 방식
- block_size : 임계 값을 적용할 영역의 크기
- C: 평균이나 가중 평균에서 차감할 값
Adaptive Threshold를 이용하면, 전체 픽셀을 기준으로 임계 값을 적용하지 않습니다.
💡 ADAPTIVE_THRESH_MEAN_C
- 적용할 픽셀 (x,y)를 중심으로 하는 Block Size * Block Size 안에 있는 픽셀 값의 평균에서 C를 뺀 값을 임계점으로 설정합니다.
💡 ADAPTIVE_THRESH_GAUSSIAN_C
- 적용할 픽셀 (x,y)를 중심으로 하는 Block Size * Block Size 안에 있는 Gaussian 윈도우 기반의 가중치들의 합에서 C를 뺀 값을 임계점으로 설정합니다.
import cv2
image = cv2.imread('hand_writing_image.jpg', cv2.IMREAD_GRAYSCALE)
ret, thres1 = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY)
thres2 = cv2.adaptiveThreshold(image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 21, 3)
plt.imshow(cv2.cvtColor(image, cv2.COLOR_GRAY2RGB))
plt.show()
plt.imshow(cv2.cvtColor(thres1, cv2.COLOR_GRAY2RGB))
plt.show()
plt.imshow(cv2.cvtColor(thres2, cv2.COLOR_GRAY2RGB))
plt.show()
⏸ OpenCV Tracker
Tracker 란 사용자가 값을 편하게 슬라이드 바를 이용하여 움직여보면서 바꿀 수 있는 기능입니다.
Tracker 사용방법
cv2.createTracker(track_bar, name, window_name, value, count, on_change) : Tracker를 생성하는 함수
- value : 초기 값
- count : Max 값 (Min: 0)
- on_change : 값이 변경될 때 호출되는 Callback 함수
cv2.getTrackerPos(track_bar, name, window_name) : Tracker로부터 값을 얻어 오는 함수
이번 실습은 PyCharm을 이용합니다.
import cv2
import numpy as np
def change_color(x):
r = cv2.getTrackbarPos("R", "Image")
g = cv2.getTrackbarPos("G", "Image")
b = cv2.getTrackbarPos("B", "Image")
image = np.zeros((600, 400, 3), np.uint8)
cv2.namedWindow("Image")
image[:] = [b, g, r]
cv2.imshow('Image', image)
cv2.createTrackbar("R", "Image", 0, 255, change_color)
cv2.createTrackbar("G", "Image", 0, 255, change_color)
cv2.createTrackbar("B", "Image", 0, 255, change_color)
cv2.imshow('Image', image)
cv2.waitKey(0)
🔸 OpenCV 도형 그리기
OpenCV에서는 다양한 도형을 그릴 수 있습니다.
직선 그리기
cv2.line(image, start, end, color, thickness) : 하나의 직선을 그리는 함수
- start : 시작 좌표 (2차원)
- end : 종료 좌표 (2차원)
- thickness : 선의 두께
import cv2
import numpy as np
import matplotlib.pyplot as plt
image = np.full((512, 512, 3), 255, np.uint8)
image = cv2.line(image, (0, 0), (255, 255), (255, 0, 0), 3)
plt.imshow(image)
plt.show()
사각형 그리기
cv2.rectangle(image, start, end, color, thickness) : 하나의 사각형을 그리는 함수
- start : 시작 좌표 (2차원)
- end : 종료 좌표 (2차원)
- thickness : 선의 두께 (채우기: -1)
import cv2
import numpy as np
import matplotlib.pyplot as plt
image = np.full((512, 512, 3), 255, np.uint8)
image = cv2.rectangle(image, (20, 20), (255, 255), (255, 0, 0), 3)
plt.imshow(image)
plt.show()
원 그리기
cv2.circle(image, center, radian, color, thickness) : 하나의 원을 그리는 함수
- center : 원의 중심 (2차원)
- radian : 반지름
- thickness : 선의 두께 (채우기: -1)
import cv2
import numpy as np
import matplotlib.pyplot as plt
image = np.full((512, 512, 3), 255, np.uint8)
image = cv2.circle(image, (255, 255), 30, (255, 0, 0), 3)
plt.imshow(image)
plt.show()
다각형 그리기
cv2.polylines(image, points, is_closed, color, thickness) : 하나의 다각형을 그리는 함수
- points : 꼭지점들
- is_closed : 닫힌 도형 여부
- thickness : 선의 두께 (채우기: -1)
import cv2
import numpy as np
import matplotlib.pyplot as plt
image = np.full((512, 512, 3), 255, np.uint8)
points = np.array([[5, 5], [128, 258], [483, 444], [400, 150]])
image = cv2.polylines(image, [points], True, (0, 0, 255), 4)
plt.imshow(image)
plt.show()
텍스트 그리기
cv2.putText(image, text, position, font_type, font_scale, color) : 하나의 텍스트를 그리는 함수
- position : 텍스트가 출력될 위치
- font_type : 글씨체
- font_scale : 글씨 크기 가중치
import cv2
import numpy as np
import matplotlib.pyplot as plt
image = np.full((512, 512, 3), 255, np.uint8)
image = cv2.putText(image, 'Hello World', (0, 200), cv2.FONT_ITALIC, 2, (255, 0, 0))
plt.imshow(image)
plt.show()
📪 OpenCV Contours
Contour란 윤곽, 테두리을 말합니다.
Contours 찾기
cv2.findContours(image, mode, method) : 이미지에서 Contour들을 찾는 함수
- mode : Contour들을 찾는 방법
1) RETR_EXTERNAL : 바깥쪽 Line만 찾기
2) RETR_LIST : 모든 Line을 찾지만, Hierarchy 구성 X
3) RETR_TREE : 모든 Line을 찾으며, 모든 Hierarchy 구성 O
- method : Contour들을 찾는 근사치 방법
1) CHAIN_APPROX_NONE : 모든 Contour 포인트 저장
2) CHAIN_APPROX_SIMPLE : Contour Line을 그릴 수 있는 포인트만 저장
입력 이미지는 Gray Scale Threshold 전처리 과정이 필요합니다.
cv2.drawContours(image, contours, contour_index, color, thickness) : Contour들을 그리는 함수
- contour_index : 그리고자 하는 Contours Line (전체: -1)
import cv2
import matplotlib.pyplot as plt
image = cv2.imread('gray_image.jpg')
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(image_gray, 127, 255, 0)
plt.imshow(cv2.cvtColor(thresh, cv2.COLOR_GRAY2RGB))
plt.show()
contours = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[1]
image = cv2.drawContours(image, contours, -1, (0, 255, 0), 4)
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.show()
📬 OpenCV Contours 처리
Contour의 사각형 외각 찾기
cv2.boundingRect(contour): Contour를 포함하는 사각형을 그립니다.
- 사각형의 X, Y 좌표와 너비, 높이를 반환합니다.
import cv2
import matplotlib.pyplot as plt
image = cv2.imread('digit\_image.png')
image\_gray = cv2.cvtColor(image, cv2.COLOR\_BGR2GRAY)
ret, thresh = cv2.threshold(image\_gray, 230, 255, 0)
thresh = cv2.bitwise\_not(thresh)
plt.imshow(cv2.cvtColor(thresh, cv2.COLOR\_GRAY2RGB))
plt.show()
contours = cv2.findContours(thresh, cv2.RETR\_TREE, cv2.CHAIN\_APPROX\_SIMPLE)\[1\]
image = cv2.drawContours(image, contours, -1, (0, 0, 255), 4)
plt.imshow(cv2.cvtColor(image, cv2.COLOR\_BGR2RGB))
plt.show()
contour = contours\[0\]
x, y, w, h = cv2.boundingRect(contour)
image = cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 3)
plt.imshow(cv2.cvtColor(image, cv2.COLOR\_BGR2RGB))
plt.show()
Contour의 Convex Hull
cv2.convexHull(contour) : Convex Hull 알고리즘으로 외곽을 구하는 함수
- 대략적인 형태의 Contour 외곽을 빠르게 구할 수 있습니다. (단일 Contour 반환)
import cv2
import matplotlib.pyplot as plt
image = cv2.imread('digit_image.png')
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(image_gray, 230, 255, 0)
thresh = cv2.bitwise_not(thresh)
contours = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[1]
image = cv2.drawContours(image, contours, -1, (0, 0, 255), 4)
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.show()
contour = contours[0]
hull = cv2.convexHull(contour)
image = cv2.drawContours(image, [hull], -1, (255, 0, 0), 4)
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.show()
Contour의 유사 다각형 구하기
cv2.approxPolyDP(curve, epsilon, closed) : 근사치 Contour를 구합니다.
- curve : Contour
- epsilon : 최대 거리 (클수록 Point 개수 감소)
- closed : 폐곡선 여부
import cv2
import matplotlib.pyplot as plt
image = cv2.imread('digit_image.png')
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(image_gray, 230, 255, 0)
thresh = cv2.bitwise_not(thresh)
contours = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[1]
image = cv2.drawContours(image, contours, -1, (0, 0, 255), 4)
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.show()
contour = contours[0]
epsilon = 0.01 * cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, epsilon, True)
image = cv2.drawContours(image, [approx], -1, (0, 255, 0), 4)
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.show()
Contour의 기본정보
cv2.contourArea(contour) : Contour의 면적을 구합니다.
cv2.arcLength(contour) : Contour의 둘레를 구합니다.
cv2.moments(contour) : Contour의 특징을 추출합니다.
import cv2
import matplotlib.pyplot as plt
image = cv2.imread('digit_image.png')
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(image_gray, 230, 255, 0)
thresh = cv2.bitwise_not(thresh)
contours = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[1]
image = cv2.drawContours(image, contours, -1, (0, 0, 255), 4)
contour = contours[0]
area = cv2.contourArea(contour)
print(area)
length = cv2.arcLength(contour, True)
print(length)
M = cv2.moments(contour)
print(M)
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.show()
9637.5
1112.1046812534332
{‘m00’: 9637.5, ‘m10’: 2328654.1666666665, ‘m01’: 525860.6666666666, ‘m20’: 592439950.25, ‘m11’: 125395340.54166666, ‘m02’: 32616659.75, ‘m30’: 157199366984.05002, ‘m21’: 31597487112.5, ‘m12’: 7677332730.433333, ‘m03’: 2223038890.5, ‘mu20’: 29780523.227014065, ‘mu11’: -1665373.5978347063, ‘mu02’: 3923591.96819859, ‘mu30’: -339915780.7390442, ‘mu21’: 76375946.41720533, ‘mu12’: -21905836.49518633, ‘mu03’: 15169233.760740757, ‘nu20’: 0.3206295471760697, ‘nu11’: -0.01793010748946005, ‘nu02’: 0.04224302932750429, ‘nu30’: -0.03727866486560947, ‘nu21’: 0.008376172780476334, ‘nu12’: -0.0024024196097321344, ‘nu03’: 0.001663614382378067}
💈 OpenCV Filtering
필터링이란?
이미지에 커널을 적용하여 이미지를 흐리게(Blurring = Smoothing) 처리하는 것을 말합니다. 이러한 과정을 통해 이미지를 흐리게 만들면 노이즈 및 손상을 줄일 수 있습니다.
컨볼루션 계산
특정한 이미지에서 커널(Kernel)을 적용해 컨볼루션 계산하여 필터링을 수행할 수 있습니다.
직접 커널을 생성하여 필터 적용하기
import cv2
import matplotlib.pyplot as plt
import numpy as np
image = cv2.imread('gray_image.jpg')
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.show()
size = 4
kernel = np.ones((size, size), np.float32) / (size ** 2)
print(kernel)
dst = cv2.filter2D(image, -1, kernel)
plt.imshow(cv2.cvtColor(dst, cv2.COLOR_BGR2RGB))
plt.show()
[[0.0625 0.0625 0.0625 0.0625]
[0.0625 0.0625 0.0625 0.0625]
[0.0625 0.0625 0.0625 0.0625]
[0.0625 0.0625 0.0625 0.0625]]
Basic Blurring
import cv2
import matplotlib.pyplot as plt
image = cv2.imread('gray_image.jpg')
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.show()
dst = cv2.blur(image, (4, 4))
plt.imshow(cv2.cvtColor(dst, cv2.COLOR_BGR2RGB))
plt.show()
Gaussian Blur
import cv2
image = cv2.imread('gray_image.jpg')
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.show()
# kernel_size: 홀수
dst = cv2.GaussianBlur(image, (5, 5), 0)
plt.imshow(cv2.cvtColor(dst, cv2.COLOR_BGR2RGB))
plt.show()
이제까지 OpenCV의 기본적인 이미지처리에 대해 알아보았습니다!
🌱 다음은 OpenCV에서 간단한 머신러닝 알고리즘인 KNN이 어떻게 적용되는지 살펴보겠습니다.
🧮 KNN Algorithm
KNN(K-Nearest Neighbor)이란?
KNN은 머신러닝 알고리즘으로
비지도학습(Unsupervised Learning)의 가장 간단한 예시입니다. 다양한 레이블의 데이터 중에서, 자신과 가까운 데이터를 찾아 자신의 레이블을 결정하는 방식입니다.
예시
- K가 3일 때, 주위에 빨간색 2개, 파란색 1개를 찾아서 별 모양을 빨간색으로 결정하게 됩니다.
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 각 데이터의 위치: 25 X 2 크기에 각각 0 ~ 100
trainData = np.random.randint(0, 100, (25, 2)).astype(np.float32)
# 각 데이터는 0 or 1
response = np.random.randint(0, 2, (25, 1)).astype(np.float32)
# 값이 0인 데이터를 각각 (x, y) 위치에 빨간색으로 칠합니다.
red = trainData[response.ravel() == 0]
plt.scatter(red[:, 0], red[:, 1], 80, 'r', '^')
# 값이 1인 데이터를 각각 (x, y) 위치에 파란색으로 칠합니다.
blue = trainData[response.ravel() == 1]
plt.scatter(blue[:, 0], blue[:, 1], 80, 'b', 's')
# (0 ~ 100, 0 ~ 100) 위치의 데이터를 하나 생성해 칠합니다.
newcomer = np.random.randint(0, 100, (1, 2)).astype(np.float32)
plt.scatter(newcomer[:, 0], newcomer[:, 1], 80, 'g', 'o')
knn = cv2.ml.KNearest_create()
knn.train(trainData, cv2.ml.ROW_SAMPLE, response)
ret, results, neighbours, dist = knn.findNearest(newcomer, 3)
# 가까운 3개를 찾고, 거리를 고려하여 자신을 정합니다.
print("result : ", results)
print("neighbours :", neighbours)
print("distance: ", dist)
plt.show()
result : [[1.]]
neighbours : [[1. 0. 1.]]
distance: [[ 25. 97. 148.]]
KNN 숫자 인식 예제
숫자 이미지 분류하여 저장하기
import cv2
import numpy as np
img = cv2.imread('digits.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 세로로 50줄, 가로로 100줄로 사진을 나눕니다.
cells = [np.hsplit(row, 100) for row in np.vsplit(gray, 50)]
x = np.array(cells)
# 각 (20 X 20) 크기의 사진을 한 줄(1 X 400)으로 바꿉니다.
train = x[:, :].reshape(-1, 400).astype(np.float32)
# 0이 500개, 1이 500개, ... 로 총 5,000개가 들어가는 (1 x 5000) 배열을 만듭니다.
k = np.arange(10)
train_labels = np.repeat(k, 500)[:, np.newaxis]
np.savez("trained.npz", train=train, train_labels=train_labels)
import matplotlib.pyplot as plt
# 다음과 같이 하나씩 글자를 출력할 수 있습니다.
plt.imshow(cv2.cvtColor(x[0, 0], cv2.COLOR_GRAY2RGB))
plt.show()
# 다음과 같이 하나씩 글자를 저장할 수 있습니다.
cv2.imwrite('test_0.png', x[0, 0])
cv2.imwrite('test_1.png', x[5, 0])
cv2.imwrite('test_2.png', x[10, 0])
cv2.imwrite('test_3.png', x[15, 0])
cv2.imwrite('test_4.png', x[20, 0])
cv2.imwrite('test_5.png', x[25, 0])
cv2.imwrite('test_6.png', x[30, 0])
cv2.imwrite('test_7.png', x[35, 0])
cv2.imwrite('test_8.png', x[40, 0])
cv2.imwrite('test_9.png', x[45, 0])
Out[43]: True
KNN 숫자 인식
import cv2
import numpy as np
import glob
FILE_NAME = 'trained.npz'
# 파일로부터 학습 데이터를 불러옵니다.
def load_train_data(file_name):
with np.load(file_name) as data:
train = data['train']
train_labels = data['train_labels']
return train, train_labels
# 손 글씨 이미지를 (20 x 20) 크기로 Scaling합니다.
def resize20(image):
img = cv2.imread(image)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray_resize = cv2.resize(gray, (20, 20))
plt.imshow(cv2.cvtColor(gray_resize, cv2.COLOR_GRAY2RGB))
plt.show()
# 최종적으로는 (1 x 400) 크기로 반환합니다.
return gray_resize.reshape(-1, 400).astype(np.float32)
def check(test, train, train_labels):
knn = cv2.ml.KNearest_create()
knn.train(train, cv2.ml.ROW_SAMPLE, train_labels)
# 가장 가까운 5개의 글자를 찾아, 어떤 숫자에 해당하는지 찾습니다.
ret, result, neighbours, dist = knn.findNearest(test, k=5)
return result
train, train_labels = load_train_data(FILE_NAME)
for file_name in glob.glob('./test_*.png'):
test = resize20(file_name)
result = check(test, train, train_labels)
print(result)
[[5.]]
[[3.]]
[[6.]]
[[8.]]
[[4.]]
[[2.]]
[[7.]]
[[0.]]
[[1.]]
[[9.]]
🤝 마치며
이상 Python을 이용한 데이터 분석과 이미지 처리에 대해 알아보았습니다. 이 포스트 내용 이외에 더 궁금하신 분은 아래의 글을 참고해주시길 바랍니다.
Reference
https://www.youtube.com/watch?v=F2FRpmh9sQo&list=PLRx0vPvlEmdBx9X5xSgcEk4CEbzEiws8C&index=7
글쓴이
DSC Yonsei 오세빈
E-mail:osb3372@yonsei.ac.kr