
*이 글을 읽기전에 작성자 개인의견이 있으니, 다른 블로그와 교차로 읽는것을 권장합니다.*
1. 영상의 변환
- 영상을 구성하는 픽셀의 배치 구조를 변경함으로써, 전체 영상의 모양을 바꾸는 작업
이미지 이동(translate)
원래 있던 좌표에 이동시키려는 거리만큼 연산
변환행렬
M = [ 1 0 a ]
[ 0 1 b ]
->x축으로 a만큼 y방향으로 b만큼 이동하는 행렬
cv2.warpaffine()
* (0, 0)을 매개변수로 전달하면 입력 영상과 크기가 같은 행렬을 반환
import cv2
import numpy as np
img = cv2.imread('./dog.bmp')
aff = np.array([[1,0,150], [0,1,100]], dtype=np.float32)
dst = cv2.warpAffine(img, aff, (0,0))
cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey()


* 보간법 알고리즘
cv2.INTER_LINEAR: 인접한 4개의 픽셀값에 거리 가중치를 사용(속도는 빠르지만, 퀄리티가 떨어짐)
cv2.INTER_NEAREST: 가장 가까운 픽셀값을 사용
cv2.INTER_AREA: 픽셀영역 관계를 이용한 재샘플링(영역적인 정보를 추출해서 영상을 세팅하기때문에 다운 샘플링시 효과적) ->보통 이미지를 축소하면 깨짐 발생, area사용시 효과적 축소됨
cv2.INTER_CUBIC: 인접한 16개의 픽셀값에 가중치를 사용(퀄리티는 가장 높지만, 속도가 떨어짐)
크기 변환(resize)
영상의 크기를 원본 영상보다 크게 또는 작게 만드는 변환
cv2.resize()
import cv2
img = cv2.imread('./dog.bmp')
dst1 = cv2.resize(img, (1280,1024), interpolation=cv2.INTER_NEAREST)
dst2 = cv2.resize(img, (1280,1024), interpolation=cv2.INTER_CUBIC)
cv2.imshow('img', img)
cv2.imshow('dst1', dst1[400:800, 200:600])
cv2.imshow('dst2', dst2[400:800, 200:600])
cv2.waitKey()



2. 회전(rotation)
영상을 특정 각도만큼 회전시키는 변환(반시계 반향, 음수는 시계방향)
cv2.getRotationMatrix2D() ->affine 행렬
확대비율: 0~1 사이의 실수
import cv2
img = cv2.imread('./dog.bmp')
cp = (img.shape[1] / 2, img.shape[0] / 2)
rot = cv2.getRotationMatrix2D(cp, 30, 0.7)
dst = cv2.warpAffine(img, rot, (0,0))
cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey()


3. 투시 변환(perspective)
- 직사각형 형태의 영상을 임의의 입체감 있는 사각형 형태로 변환
- 원본 영상에 있는 직선은 결과 영상에서 그대로 유지되지 않고, 평행관계가 깨질 수 있음
- 투시 변환은 보통 3*3크기의 실수행렬로 표현
cv2.getPerspectiveTransform(영상, 4개의 결과 좌표점) -> 투시변환 행렬
cv2.warpPerspective(영상, 투시변환행렬, 결과영상크기)
필터링 연산
커널 또는 필터라고 하는 행렬을 정의하고 이미지 위에서 이동해가며 커널과 겹쳐진 이미지 영역과 연산을 한 후, 그 결과값을 픽셀을 대신하여 새로운 이미지로 만드는 연산
cv.filter2D(영상, -1, 커널, 중심점 좌표, 추가될 값, 가장자리 화소처리)
-1 : 입력과 동일한 크기의 영상
커널 : 3*3, 5*5, ...
가장자리 화소처리
BORDER_CONSTANT: 000abcdef000
BORDER_REPLICATE: aaaabcdeffff
...
import cv2
import numpy as np
img = cv2.imread('./pic.jpg')
w, h = 600, 400
srcQuad = np.array([[369, 172], [1229, 156], [1424,846],[207, 801]], np.float32)
dstQuad = np.array([[0,0],[w,0],[w,h],[0,h]], np.float32)
pers = cv2.getPerspectiveTransform(srcQuad, dstQuad)
dst = cv2.warpPerspective(img, pers, (w,h))
cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey()


import cv2
import numpy as np
import sys
img = cv2.imread('./namecard.jpg')
h, w = img.shape[:2]
dh = 500
# A4용지 크기: 210*297mm
dw = round(dh * 297 / 210)
srcQuad = np.array([[30, 30], [30, h-30], [w-30, h-30], [w-30, 30]], np.float32)
dstQuad = np.array([[0, 0], [0, dh], [dw, dh], [dw, 0]], np.float32)
dragSrc = [False, False, False, False]
def drawROI(img, corners):
cpy = img.copy()
c1 = (192, 192, 255)
c2 = (128, 128, 255)
for pt in corners:
cv2.circle(cpy, tuple(pt.astype(int)), 25, c1, -1)
cv2.line(cpy, tuple(corners[0].astype(int)), tuple(corners[1].astype(int)), c2, 2)
cv2.line(cpy, tuple(corners[1].astype(int)), tuple(corners[2].astype(int)), c2, 2)
cv2.line(cpy, tuple(corners[2].astype(int)), tuple(corners[3].astype(int)), c2, 2)
cv2.line(cpy, tuple(corners[3].astype(int)), tuple(corners[0].astype(int)), c2, 2)
return cpy
def onMouse(event, x, y, flags, param):
global srcQuad, dragSrc, ptOld, img
if event == cv2.EVENT_LBUTTONDOWN:
for i in range(4):
if cv2.norm(srcQuad[i] - (x, y)) < 25:
dragSrc[i] = True
ptOld = (x, y)
break
if event == cv2.EVENT_LBUTTONUP:
for i in range(4):
dragSrc[i] = False
if event == cv2.EVENT_MOUSEMOVE:
for i in range(4):
if dragSrc[i]:
srcQuad[i] = (x, y)
cpy = drawROI(img, srcQuad)
cv2.imshow('img', cpy)
ptOld = (x, y)
break
disp = drawROI(img, srcQuad)
cv2.namedWindow('img')
cv2.setMouseCallback('img', onMouse)
cv2.imshow('img', disp)
while True:
key = cv2.waitKey()
if key == 13:
break
elif key == 27:
sys.exit()
pers = cv2.getPerspectiveTransform(srcQuad, dstQuad)
dst = cv2.warpPerspective(img, pers, (dw, dh), flags=cv2.INTER_CUBIC)
cv2.imshow('dst', dst)
cv2.waitKey()


4. 블러링(Blurring)
초점이 맞지 않은 듯 영상을 흐릿하게 하는 작업
import cv2
import matplotlib.pyplot as plt
import numpy as np
img = cv2.imread('./dog.bmp')
dst1 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
dst2 = cv2.blur(img, (7, 7))
cv2.imshow('img', img)
cv2.imshow('dst2', dst2)
cv2.waitKey()
plt.figure(figsize=(10, 5))
for i, k in enumerate([5, 7, 9]):
kernel = np.ones((k, k)) / k ** 2
filtering = cv2.filter2D(dst1, -1, kernel)
plt.subplot(1, 3, i+1)
plt.imshow(filtering)
plt.title('kernel size: {}'.format(k))
plt.axis('off')
plt.show()
cv2.waitKey()




- 평균 블러링 : 가장 일반적인 블러링 방법. 균일한 값을 정규화된 커널을 이용한 이미지 필터링 방법
- 커널 영역 내에서 평균 값으로 해당 픽셀을 대체함
- 주변 픽셀들의 평균값을 적용하면 픽셀 간 차이가 적어져 선명도가 떨어지므로 전체적으로 흐려짐
- 필터의 크기가 클수록 평균 블러링을 적용했을 때 선명도가 더 떨어짐
- 가우시안 블러링: 가우시안 분포를 갖는 커널로 블러링 하는 것
- 대상 픽셀에 가까울수록 많은 영향을 주고, 멀어질수록 적은 영향을 주기 때문에 원래의 영상과 비슷하면서도 노이즈를 제거하는 효과가 있음
import cv2
img = cv2.imread('./dog.bmp', cv2.IMREAD_GRAYSCALE)
dst1 = cv2.GaussianBlur(img, (0,0), 2)
dst2 = cv2.blur(img, (5,5))
cv2.imshow('img', img)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.waitKey()



- 미디언 블러링: 커널의 픽셀값 중 중앙값을 선택
- 소금-후추 잡음을 제거하는 효과
import cv2
img = cv2.imread('./noise.bmp', cv2.IMREAD_GRAYSCALE)
dst = cv2.medianBlur(img, 3)
cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey()


- 바이레터럴 필터: 기존 블러링의 문제점을 해결하기 위한 방법
- 잡음을 제거하는 효과는 뛰어났지만, 해당 잡음의 경계도 흐릿하게 만드는 문제를 해결
- 경계도 뚜렷하고 노이즈도 제거되는 효과가 있지만 속도가 느림
- cv2.bilateralFilter(영상, 픽셀의 거리, 시그마 컬러 범위, 시그마 스페이스 범위)
import cv2
img = cv2.imread('./gaussian_noise.jpg', cv2.IMREAD_GRAYSCALE)
dst1 = cv2.GaussianBlur(img, (5,5), 1)
dst2 = cv2.bilateralFilter(img, 5, 80, 80)
cv2.imshow('img', img)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.waitKey()



5. 에지(edge) 검출
- 영상에서 화소의 밝기가 급격하게 변한는 부분
- 물체의 윤곽선(경계선)이 해당
- 에지를 검출할 수 있으면 물체의 윤곽선을 알 수 있음
- "케니 에지 검출"은 상당한 수준으로 에지를 신뢰성있게 검출하는 방법
cv2.Canny(영상, 최소임계값, 최대임계값, 커널)
최소임계값, 최대임계값: 두 개의 경계 값(Max, Min)을 지정해서 경계에 있는 영역 픽셀을 찾음
import cv2
import numpy as np
img = cv2.imread('./dog.bmp')
med_val = np.median(img)
lower = int(max(0, 0.7*med_val))
upper = int(min(255, 1.3*med_val))
print(lower)
print(upper)
dst = cv2.GaussianBlur(img, (3,3), 0)
dst = cv2.Canny(dst, lower, upper, 3)
cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey()


문제
웹캠 영상에서 필터링을 적용(스페이스바를 누를 때마다)하는 프로그램을 작성
- 일반영상 -> 가우시안 필터링 -> 캐니 필터링 -> 일반영상
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
def blur_filter(img):
img = cv2.GaussianBlur(img, (0, 0), 3)
return img
def canny_filter(img):
med_val = np.median(img)
lower = int(max(0, 0.7*med_val))
upper = int(min(255, 1.3*med_val))
dst = cv2.GaussianBlur(img, (3, 3), 0, 0)
dst = cv2.Canny(dst, lower, upper, 3)
return dst
cam_mode = 0
while True:
ret, frame = cap.read()
if cam_mode == 1:
frame = blur_filter(frame)
elif cam_mode == 2:
frame = canny_filter(frame)
cv2.imshow('frame', frame)
key = cv2.waitKey(10)
if key == 27:
break
elif key == ord(' '):
cam_mode += 1
if cam_mode == 3:
cam_mode = 0
cap.release()
'Python > 컴퓨터 비전' 카테고리의 다른 글
Python(55)- 이진 분류 모델, VGG19 모델 (0) | 2024.07.24 |
---|---|
Python(54)- 모폴로지 처리, 레이블링, 테서렉트 (0) | 2024.07.23 |
Python(52)- ROI, 이진화(threshold, otsu) (0) | 2024.07.23 |
Python(51)- CLAHE(평탄화), 색상추출, hist (0) | 2024.07.23 |
Python(50)- OpenCV (0) | 2024.07.16 |