본문 바로가기

AI 개론

AI 개론 _ OpenCV를 이용한 컴퓨터 비전2 + OpenCV를 이용한 기하학적 변환 실습

728x90

영상 필터링

 

블러링 : 평균값 필터

 

가우시안 필터

 

Gaussian filtering

 

가우시안 필터 적용 결과

 

샤프닝 필터 구현

 

샤프닝 필터

 

 

양방향 필터

 

OpenCV Bitwise

 

기하학적 변환

 

Affine transform

  • 𝐿𝑖𝑛𝑒𝑎𝑟 𝑡𝑟𝑎𝑛𝑠𝑓𝑜𝑟𝑚
  • 휘어짐이 없고 평행한 선들은 평행을 유지하는 변환
    • 이동, 회전, 스케일 및 이들의 조합에 의한 변환
  •  𝑥'  = 𝑎0𝑥 + 𝑎1𝑦 + 𝑎2, 𝑦'  = 𝑏0𝑥 + 𝑏1𝑦 + 𝑏2
    • ℎ𝑜𝑚𝑜𝑔𝑒𝑛𝑒𝑜𝑢𝑠 𝑐𝑜𝑜𝑟𝑑𝑖𝑛𝑎𝑡𝑒 𝑠𝑦𝑠𝑡𝑒𝑚 사용

 

위치 이동

 

회전 이동

 

영상 확대

전단 변환 (Shearing)

 

Warping

  • Nonlinear transform (rubber sheet transform)
  • pixel별로 이동 정도를 다르게 할 수 있어서 고무판 위에 그려진 영상을 임의대로 구부리는 것과 같은 효과를 낼 수 있음
  • 고차항을 사용하여 일반화된 다항식으로 표현

 

Interpolation 이란?

  • 결과 픽셀에 정확하게 대응되는 입력 픽셀이 없는 경우 주변 픽셀들을 고려하여 새로운 값을 생성하는 방법

Interpolation 종류

  • 최근접 이웃 보간법(Nearest neighbor interpolation)
  • 이웃 평균 보간법(Neighbor averaging interpolation)
  • 양선형 보간법(Bilinear interpolation)
  • 고차 보간법 (Higher order interpolation)

 

Nearest neighbor interpolation

  • 계산한 위치에서 가장 가까운 원시 픽셀을 선택하는 방법
  • 처리 속도는 빠르지만 결과 영상의 질이 좋지 않음
  • (e.g.)  I(10,11) -> d(9.8,9.2) ~~ d(10,9)=55

 

Neighbor averaging interpolation

  • 이웃들의 평균 계산 (2차원의 경우 4개 이웃 사용)
  • 최근접 이웃 보간법에 비해 계산량은 많지만 조금 더 만족스러운 결과 제공
  •  (e.g.) I(10,11) -> d(9.8,9.2) = (50+44+55+48)/4 ~~ 49

 

Bilinear interpolation

  • 새로운 픽셀을 생성하기 위해 네 개의 가장 가까운 픽셀들에 가중치를 곱한 값들의 합을 사용
  • 조금 더 자연스러운 영상을 산출

 

OpenCV를 이용한 기하학적 변환

import numpy as np
import cv2
import sys
import matplotlib.pyplot as plt
from pathlib import Path

영상 필터링 (Filtering)

2D Convolution

# cv2.filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]]) -> dst
# src: 입력영상
# ddepth: 출력영상의 타입 (cv2.CV_8U, cv2.CV_32F, cv2.CV_64F), 
#     -1 => 입력영상과 같은 타입
# kernel: filter 행렬, 실수형
# anchor: (-1, -1)  필터의 중앙점
# delta:   더할 값
# borderType: 가장자리 픽셀확장 방식
# dst: 출력영상

# blur(src, ksize[, dst[, anchor[, borderType]]]) -> dst
# src: 입력영상
# ksize: mean filter kernel size
folder = "fig"
## 영역처리, 영상 필터링, Convolution

# src = cv2.imread("./fig/blue_eyes.png", cv2.IMREAD_REDUCED_COLOR_2)
src = cv2.imread(Path(folder, "blue_eyes.png"), cv2.IMREAD_REDUCED_COLOR_2)


kernel_3 = np.ones((3, 3), dtype = np.float64)/9.
dst_kernel = cv2.filter2D(src, -1, kernel_3)

dst_blur = cv2.blur(src, (3, 3))

cv2.imshow('src', src)
cv2.imshow('dst_kernel', dst_kernel)
cv2.imshow("dst_blur", dst_blur)

cv2.waitKey()
cv2.destroyAllWindows()
src = cv2.imread(Path(folder, "blue_eyes.png"), cv2.IMREAD_REDUCED_COLOR_2)
cv2.imshow("src", src)

for ksize in (3, 5, 7, 9, 12, 15, 23):
    dst = cv2.blur(src, (ksize, ksize))
    text = '{} x {}'.format(ksize, ksize)
    cv2.putText(dst, text, (20, 30), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 0, 255), 2, cv2.LINE_AA)

    cv2.imshow('mean filter', dst)
    cv2.waitKey()

cv2.destroyAllWindows()

가우시안 필터

# GaussianBlur(src, (ksize), sigmaX[, dst[, sigmaY[, borderType]]]) -> dst
# src: 입력영상
# ksize: mean filter kernel size, (0, 0) 자동으로 결정
# sigmaX:  gaussian x 방향의 sigma
# sigmaY:  gaussian y 방향의 sigma
## 가우시안 필터

src = cv2.imread(Path(folder, "blue_eyes.png"), cv2.IMREAD_COLOR)

dst_Gaussian1 = cv2.GaussianBlur(src, (0, 0), 1)
dst_mean = cv2.blur(src, (5,5))
# dst_Gaussian2 = cv2.GaussianBlur(src, (0, 0), 2)
# dst_Gaussian3 = cv2.GaussianBlur(src, (0, 0), 3)

cv2.imshow('src', src)
cv2.imshow("Gaussian1", dst_Gaussian1)
cv2.imshow("dst_mean", dst_mean)
# cv2.imshow("Gaussian2", dst_Gaussian2)
# cv2.imshow("Gaussian3", dst_Gaussian3)

cv2.waitKey()
cv2.destroyAllWindows()

사프닝 필터링

## Sharpening filter

src = cv2.imread(Path(folder, "blue_eyes.png"), cv2.IMREAD_REDUCED_COLOR_2)

blr = cv2.GaussianBlur(src, (0, 0), 1)
blr2 = cv2.GaussianBlur(src, (0, 0), 2)
blr3 = cv2.GaussianBlur(src, (0, 0), 3)

dst = cv2.addWeighted(src, 2, blr, -1, 0.0)
dst2 = cv2.addWeighted(src, 2, blr2, -1, 0.0)
dst3 = cv2.addWeighted(src, 2, blr3, -1, 0.0)

cv2.imshow('src', src)
cv2.imshow("blr", blr)
cv2.imshow("sharpening1", dst)
cv2.imshow("sharpening2", dst2)
cv2.imshow("sharpening3", dst3)

cv2.waitKey()
cv2.destroyAllWindows()

# [[ 0. -1.  0.]
#  [-1.  5. -1.]
#  [ 0. -1.  0.]]

# [[-0.2 -0.8 -0.2]
#  [-0.8  5.  -0.8]
#  [-0.2 -0.8 -0.2]]

# src = cv2.imread('blue_eyes.png', cv2.IMREAD_REDUCED_COLOR_2)
# kernel = np.ones((3, 3), dtype = np.float64)*-1
# kernel[1,1] = 9
# #print(kernel)
# dst = cv2.filter2D(src, -1, kernel)
# cv2_imshow(src)
# cv2_imshow(dst)
## sharpen filter
src = cv2.imread(Path(folder, "blue_eyes.png"))

kernel_3 = np.ones((3, 3), dtype = np.float64)*-.5
kernel_3[1, 1] = 5

dst_kernel = cv2.filter2D(src, -1, kernel_3)

cv2.imshow('src', src)
cv2.imshow('dst_kernel', dst_kernel)

plt.imshow(kernel_3, cmap="seismic")
plt.colorbar()
plt.show()
# cv2.imshow("dst_blur", dst_blur)

cv2.waitKey()
cv2.destroyAllWindows()
print(kernel_3)

 

중앙값 필터링

## median filter
src = cv2.imread(Path(folder, "blue_eyes.png"), cv2.IMREAD_GRAYSCALE)
salt_noise = np.random.choice((0, 255), src.shape, p = (0.99, 0.01)).astype(np.uint8)
pepper_noise = np.random.choice((0, 255), src.shape, p = (0.99, 0.01)).astype(np.uint8)
dst = cv2.add(src, salt_noise)
dst = cv2.subtract(dst, pepper_noise)

dst_median = cv2.medianBlur(dst, 3)
# dst_Gaussian = cv2.GaussianBlur(dst, (0, 0), 1)

cv2.imshow("src", src)
# cv2.imshow("salt_noise", salt_noise)
# cv2.imshow("pepper_noise", pepper_noise)
cv2.imshow("dst", dst)
cv2.imshow("dst_median", dst_median)
# cv2.imshow("dst_Gaussian", dst_Gaussian)


while True:
    if cv2.waitKey() == ord("q"):
        break
    
cv2.destroyAllWindows()

 

양방향 필터 (Bilateral filter)

# bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]]) -> dst
# src: 입력영상
# d: -1로 설정
# sigmaColor: 색공간의 표준편차
# sigmaSpace: 좌표공간의표준편차
# dst:
# borderType: 가장자리 픽셀확장 방식

카툰 필터

## bitwise operator
src1 = np.zeros((256, 256), np.uint8)
cv2.rectangle(src1, (10, 10), (127, 245), 255, -1)
src2 = np.zeros((256, 256), np.uint8)
cv2.circle(src2, (127, 127), 100, 128, -1)

dst1 = cv2.bitwise_and(src1, src2)
dst2 = cv2.bitwise_or(src1, src2)
dst3 = cv2.bitwise_xor(src1, src2)
dst4 = cv2.bitwise_not(src2)

cv2.imshow("src1", src1)
cv2.imshow('src2', src2)
cv2.imshow("AND", dst1)
cv2.imshow("OR", dst2)
cv2.imshow("XOR", dst3)
cv2.imshow("NOT", dst4)

cv2.waitKey()
cv2.destroyAllWindows()
## Cartoon 필터

time = cv2.TickMeter()

# src = cv2.imread("./fig/son.jpg")
src = cv2.imread(Path(folder, "son.jpg"))

time.start()

### 연산 구간
for i in range(100):
    blr = cv2.GaussianBlur(src, (0, 0), 2)
    edge = 255 - cv2.Canny(src, 100, 200)
    edge = cv2.cvtColor(edge, cv2.COLOR_GRAY2BGR)
    dst = cv2.bitwise_and(blr, edge)
###

time.stop()

cv2.imshow("son", src)
cv2.imshow("blr", blr)
cv2.imshow("edge", edge)
cv2.imshow("dst", dst)
print(time.getTimeMilli(), "ms")
time.reset()

cv2.waitKey()
cv2.destroyAllWindows()
260.1467 ms

기하학적 변환 (Geometric transform)

영상 이동 (Translation)

# warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) -> dst
# src: 입력영상
# M: affine transform matrix (size: 2 x 3)
# dsize: 출력영상 크기, (0, 0) = 입력영상크기로 출력
# borderValue: 값이 없는 영역을 채우는 값, default  = 0
## 영상 이동 (Translation)

# src = cv2.imread("./fig/dog.bmp")
src = cv2.imread(Path(folder, "dog.bmp"))


## affine matrix
affine = np.array([[1, 0, 50],
                   [0, 1, 200]], np.float32)

print("affine matrix: \n", affine)
# print(affine.dtype)

dst = cv2.warpAffine(src, affine, (0, 0), 
                     borderMode = cv2.BORDER_CONSTANT, 
                     borderValue=(255, 255, 255))

# dst = cv2.warpAffine(src, affine, (0, 0))

cv2.imshow("src", src)
cv2.imshow("dst", dst)

cv2.waitKey()
cv2.destroyAllWindows()
affine matrix: 
 [[  1.   0.  50.]
 [  0.   1. 200.]]

 

영상 회전 (Rotation)

# warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) -> dst
# src: 입력영상
# M: affine transform matrix (size: 2 x 3)
# dsize: 출력영상 크기, (0, 0) = 입력영상크기로 출력
# borderValue: 값이 없는 영역을 채우는 값, default  = 0

# getRotationMatrix2D(center, angle, scale) -> retval
# center: 영상의 center
# angle: 회전각도
# scale: 확대율
## 회전 변환 (Rotation)

src = cv2.imread(Path(folder, "dog.bmp"))

cp = (src.shape[1]/2, src.shape[0]/2)
affine = cv2.getRotationMatrix2D(cp,  30, 1.)
dst = cv2.warpAffine(src, affine, (0, 0))

cv2.imshow("src", src)
cv2.imshow("dst", dst)

cv2.waitKey()
cv2.destroyAllWindows()

영상 확대 (Scaling)

## 영상 확대 (Scaling)
# src = cv2.imread("./fig/rose.jpg")
src = cv2.imread(Path(folder, "rose.jpg"))

print("src shape : ", src.shape)

dst1 = cv2.resize(src, (1900, 1300), interpolation=cv2.INTER_NEAREST)
dst2 = cv2.resize(src, (1900, 1300), interpolation=cv2.INTER_LINEAR)
dst3 = cv2.resize(src, (1900, 1300), interpolation=cv2.INTER_CUBIC)

cv2.imshow("src", src)
cv2.imshow('INTER_NEAREST', dst1[800:1600, 800:1200])
cv2.imshow('INTER_LINEAR', dst2[800:1600, 800:1200])
cv2.imshow('INTER_CUBIC', dst3[800:1600, 800:1200])


cv2.waitKey()
cv2.destroyAllWindows()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[3], line 3
      1 ## 영상 확대 (Scaling)
      2 # src = cv2.imread("./fig/rose.jpg")
----> 3 src = cv2.imread(Path(folder, "rose.jpg"))
      5 print("src shape : ", src.shape)
      7 dst1 = cv2.resize(src, (1900, 1300), interpolation=cv2.INTER_NEAREST)

NameError: name 'folder' is not defined

 

영상 전단 (Shearing)

## Shearing
src = cv2.imread(Path(folder, "dog.bmp"))

affine  = np.array([[1, 0.2, 0],
                    [0.2, 1, 0 ]], np.float32)

dst = cv2.warpAffine(src, affine, (0, 0))

cv2.imshow("src", src)
cv2.imshow("dst", dst)

cv2.waitKey()
cv2.destroyAllWindows()

 

비선형 변환 (Perspective transform)

# getPerspectiveTransform(src, dst[, solveMethod]) -> retval
# src: 입력영상의 4개 좌표점, numpy array shape(4,2)
# dst: 출력영상의 4개 좌표점, numpy array shape(4,2)
## Non linear warping

# src = cv2.imread("./fig/checkerboard.png")
src = cv2.imread(Path(folder, "checkerboard.png"))


h, w = src.shape[:2]

srcPoint = np.array([[218, 48], [691, 47], [830, 518], [67, 527]], np.float32)
dstPoint = np.array([[0, 0], [w-1, 0], [w-1, h-1], [0, h-1]], np.float32)

pers = cv2.getPerspectiveTransform(srcPoint, dstPoint)
# array([[ 2.13264257e+00,  6.72294421e-01, -4.97186212e+02],
#        [ 4.08735101e-03,  1.93331703e+00, -9.36902599e+01],
#        [-1.86504523e-05,  1.36282733e-03,  1.00000000e+00]])

dst = cv2.warpPerspective(src, pers, (w, h))
# a, b, c, d = cv2.selectROI(src)
# print(a, b, c, d)

print("width = ", w, "height = ", h)
cv2.imshow("src", src)
cv2.imshow("dst", dst)

cv2.waitKey()
cv2.destroyAllWindows()
width =  960 height =  540

 

비선형 리매핑

# remap(src, map1, map2, interpolation[, dst[, borderMode[, borderValue]]]) -> dst

 

## remapping
# src = cv2.imread("./fig/bamboo.jpg")
src = cv2.imread(Path(folder, "bamboo.jpg"))


h, w = src.shape[:2]

map2, map1 = np.indices((h, w), np.float32)
# print(map1)
print("")
print(map2)

map1 = map1 + 10*np.sin(map2/32)

dst = cv2.remap(src, map1, map2, cv2.INTER_CUBIC)

cv2.imshow('src', src)
cv2.imshow('dst', dst)

cv2.waitKey()
cv2.destroyAllWindows()
[[  0.   0.   0. ...   0.   0.   0.]
 [  1.   1.   1. ...   1.   1.   1.]
 [  2.   2.   2. ...   2.   2.   2.]
 ...
 [597. 597. 597. ... 597. 597. 597.]
 [598. 598. 598. ... 598. 598. 598.]
 [599. 599. 599. ... 599. 599. 599.]]
728x90