728x90

목표

- 이미지 그라디언트와 에지를 구해봅시다

 

이론

- opencv에서는 sobel, scharr, laplacian 3가지 그라디언트 필터(고주파 통과 필터)를 제공하고 있습니다.

 

 

1. sobel과 shcarr 미분 

- 소벨 연산자는 결합 가우시안 스무딩 + 미분을 수행하므로 노이즈에 강인하나, 미분 방향과 커널 크기를 명시해주어야 합니다.

- scharr 필터는 소벨 필터보다 더 좋은 결과를 내는데 한번 보세요

 

2. 라플라시안 미분

- 이미지 라플라시안을 구하려면 다음의 식을 계산하면 됩니다. 여기서 각각의 미분은 소벨과 동일하게 수행해서 얻을수 있겠습니다.

 

- ksize = 1로 하는 경우 다음의 커널이 필터링에 사용되겠습니다.

 

 

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('C:/Users/do/Documents/github/opencv_python/res/dave.jpg', 0)

laplacian = cv2.Laplacian(img,cv2.CV_64F)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=5)

plt.subplot(2,2,1),plt.imshow(img,cmap = 'gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,2),plt.imshow(laplacian,cmap = 'gray')
plt.title('Laplacian'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,3),plt.imshow(sobelx,cmap = 'gray')
plt.title('Sobel X'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,4),plt.imshow(sobely,cmap = 'gray')
plt.title('Sobel Y'), plt.xticks([]), plt.yticks([])

plt.show()

 

 

 

300x250
728x90

목표

- 침식 erosion, 팽창 dilation, 열림, 닫힘 등 다양한 모폴로지 연산을 사용해봅시다.

 

이론

- 모폴로지 연산은 이미지 형태를 이용한 단순한 연산이라고 할수 있습니다.

- 보통 2진 이미지를 가지고 하는데요.

- 입력은 2개로, 하나는 원본 영상, 그리고 연산 종류를 결정하는 커널(구조 요소)가 됩니다.

- 기본적은 두가지 모폴로지 연산은 침식과 팽창 연산이 있습니다.

- 이들을 이용해서 열림과 닫힘, 그라디언트 같은 연산을 수행할수 있게 됩니다.

 

 

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('C:/Users/do/Documents/github/opencv_python/res/j.png')

kernel = np.ones((5,5),np.uint8)
erosion = cv2.erode(img,kernel,iterations = 1)
dilation = cv2.dilate(img,kernel,iterations = 1)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)

plt.subplot(231),plt.imshow(img),plt.title('origin')
plt.xticks([]), plt.yticks([])
plt.subplot(232),plt.imshow(erosion),plt.title('erosion')
plt.xticks([]), plt.yticks([])
plt.subplot(233),plt.imshow(dilation),plt.title('diliation')
plt.xticks([]), plt.yticks([])
plt.subplot(234),plt.imshow(opening),plt.title('opening')
plt.xticks([]), plt.yticks([])
plt.subplot(235),plt.imshow(closing),plt.title('closing')
plt.xticks([]), plt.yticks([])
plt.subplot(236),plt.imshow(gradient),plt.title('gradient')
plt.xticks([]), plt.yticks([])

plt.show()

 

 

 

300x250
728x90

목표

- 다양한 저주파 통과 필터로 이미지를 뿌옇게 마만들어 봅시다.

- 2차원 콘볼루션을 통해 커스텀 필터를 사용해봅시다.

 

 

2차원 컨벌루션과 필터

- 1차워 신호의 경우 이미지는 다양한 저주파 통과 필터 LPF Low Pass Filter나 고주파 통과 필터 HPF High Pass Filter로 필터링을 할수 있습니다.

- LPF는 노이즈를 제거해주고 영상을 흐리게 만들어 줍니다.

- HPF는 이미지에 존재하는 에지를 찾는데 도와줍니다.

 

 

평균 필터

-opencv에서는 이미지를 커널(마스크)로 컨벌루션할수 있게 cv2.filter2D()함수를 제공하는데요.

- 영상에 평균 필터를 적용해본다면 5x5 크기의 평균 필터 커널은 아래와 같이 정의할수도 있겠습니다.

 

 

필터 수행

- 각 픽셀에 5 x5 크기의 윈도우(필터, 마스크)가 중간에 그 픽셀이 위치하도록 놓고 25개의 필터와 원본 영상의 값들을 곱한 후 합하여 새 영상에 그 픽셀 자리에 컨벌루션한 결과 합을 넣어줍니다.

- 이렇게 윈도우 내부에서 픽셀들의 평균 값이 계산 되며, 모든 픽셀들에 수행하면 필터링된 결과 이미지를 얻게 됩니다.

- 한번 다음 코드를 돌려보세요.

 

 

 

 

 

 

 

 

 

이미지 블러링(이미지 스무딩)

- 이미지 블러링은 저주파 통과 필터를 영상에다가 컨벌루션하여 얻을수 있습니다.

- 이는 노이즈 제거에 좋은 방법이라할수 있는데요.

- 고주파 성분들(노이즈, 에지)들을 영상에서 제거하여 필터링된 결과 블러된 이미지를 얻게 됩니다.

- OPENCV에선 4가지의 블러링 기술들을 제공하고 있어요.

 

 

 

1. 평균 블러링

- 이미지를 정규화된 박스 필터로 컨볼루션해서 얻을수 있습니다.

- 커널 영역에서 모든 픽셀들의 평균을 구하는 방식으로, 이 평균값으로 해당 픽셀의 값을 바꿔줍니다.

- 여기서 사용하는 함수는 cv2.blur()나 cv2.boxFilter()를 사용하며, 3x3크기의 정규화박스 필터는 아래와 같습니다.

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('C:/Users/do/Documents/github/opencv_python/res/opencv_logo.png')

blur = cv2.blur(img,(5,5))

plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur),plt.title('Blurred')
plt.xticks([]), plt.yticks([])
plt.show()

 

 

 

 

 

 

2. 가우시안 블러링

- 이번에는 필터의 모든 계수들이 동일한 박스 필터 대신에 가우시안 필터를 사용해보겠습니다.

- 가우시안 필터는 cv2.GaussianBlur()함수로 사용할수 있는데, X와 Y방향에 표준 편차를 지정해주어야 합니다.

 * 0을 주면 필터 크기로 알아서 주고, sigma X만 명시하는경우 Y도 동일하게 적용됩니다.

- 가우시안 필터는 영상 내부의 가우시안 노이즈를 제거하는대 유용합니다.

 

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('C:/Users/do/Documents/github/opencv_python/res/opencv_logo.png')

blur1 = cv2.GaussianBlur(img,(5,5),0)
blur2 = cv2.GaussianBlur(img,(15,15),0)
blur3 = cv2.GaussianBlur(img,(15,15),10)

plt.subplot(221),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(222),plt.imshow(blur1),plt.title('Blurred 1')
plt.xticks([]), plt.yticks([])
plt.subplot(223),plt.imshow(blur2),plt.title('Blurred 2')
plt.xticks([]), plt.yticks([])
plt.subplot(224),plt.imshow(blur3),plt.title('Blurred 3')
plt.xticks([]), plt.yticks([])
plt.show()

 

 

 

 

 

 

 

 

 

300x250
728x90

목표

-단순 이진화, 적응적 이진화, 오츠 이진화

 

 

단순 이진화

- 이진화는 간단하게 임계값보다 크다면 1, 아니면 0을 주는 간단한 문제

 -> cv2.thresold 함수 사용. 명암영상만 가능

- 둘째 매개변수는 이진화에 사용할 임계값.

- 3번째 매개변수는 픽셀의 최대값

- 냇쨰 파라미터로 아래와 같은 것들이 있음.

   cv2.THRESH_BINARY

   cv2.THRESH_BINARY_INV

   cv2.THRESH_TRUNC

   cv2.THRESH_TOZERO

   cv2.THRESH_TOZERO_INV

 

 

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('C:/Users/do/Documents/github/opencv_python/res/gradient.png',0)
ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
ret,thresh5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)

titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]

for i in xrange(6):
    plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])

plt.show()

 

1. 원본 영상 

2. 이진화 : 명암값 127 기준으로

3. 역이진화 : 127보다 작으면 1

4. truc : 127보다 작으면 0

...

 

 

 

 

 

 

 

적응적 이진화

- 조금전 예제에선 임계치값을 지정해줌

- 빛이 비쳐 그늘 생긴 이미지에선 안좋음 -> 적응적 이진화 사용

- 영상 일부분을 서로 다른 이진화 값 사용 -> 모든 영역에 다른 이진화 값을 적용하여 조명 변화시에도 좋은 결과 나옴

 

적응적 이진화 파라미터

- 적응화 방법

   cv2.ADAPTIVE_THRESH_MEAN_C : 주위 영역의 평균값을 임계치로 사용

   cv2.ADAPTIVE_THRSH_GAUSSIAN_C : 가우시안 윈도우로 주위 픽셀들의 가중치 합을 임계치로 사용

- BLOCK SIZE : 주변 공간 크기

- C : 상수로 평균과 가중치에서 얼마만큼 -할지 지정하는값

* 반환값 ret은 나중에 설명

 

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('C:/Users/do/Documents/github/opencv_python/res/dave.jpg',0)
img = cv2.medianBlur(img,5)

ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
            cv2.THRESH_BINARY,11,2)
th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
            cv2.THRESH_BINARY,11,2)

titles = ['Original Image', 'Global Thresholding (v = 127)',
            'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]

for i in range(4):
    plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()

 

 

 

 

 

 

 

 

오츠 이진화

- 이전에 살펴본 전역적인 이진화에선 특정한 임계값을 사용

  => 이 임계값이 좋은지 나쁜지 알려면 시행착오(trial and error)를 해야함

- 하지만 양봉 이미지(히스토그램상 봉우리가 2개인) 경우를 생각해보면 양 봉우리의 평균을 근사해서 임계치를 사용해야함 -> 오츠 이진화가 수행

 => 이미지 히스토그램으로 자동으로 임계치 계산 해줌

 

오츠 이진화 코드

- cv2.threshold() 함수를 사용. 플래그 cv2.THRESH_OTS 추가. 임계값은 0으로 설정

- 다음 예시에서 노이즈 영상 사용

- 1번째 케이스는 전역 임계치를 127로 설정

- 2번째는 오츠 이진화를 바로 수행

- 셋째는 5 x5 가우시안 커널로 노이즈 제거후 오츠 이진화 수행

 

 

 

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('C:/Users/do/Documents/github/opencv_python/res/noisy2.png',0)

# global thresholding
ret1,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)

# Otsu's thresholding
ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# Otsu's thresholding after Gaussian filtering
blur = cv2.GaussianBlur(img,(5,5),0)
ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# plot all the images and their histograms
images = [img, 0, th1,
          img, 0, th2,
          blur, 0, th3]
titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
          'Original Noisy Image','Histogram',"Otsu's Thresholding",
          'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]

for i in range(3):
    plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')
    plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)
    plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray')
    plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
plt.show()

 

 

 

 

 

 

 

오츠 이진화 동작 방법

- 양봉 이미지에서 오츠 이진화를 수행할떄, 오츠 알고리즘은 두 가중화된 클래스의 분산을 최소화 하는 임계치를 찾음

 

 

=>  두 클래스의 분산이 최소가 되는 값 t를 찾게됨

- 위 식을 아래와 같이 구현할 수 있다.

 

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('C:/Users/do/Documents/github/opencv_python/res/noisy2.png',0)
blur = cv2.GaussianBlur(img,(5,5),0)

# find normalized_histogram, and its cumulative distribution function
hist = cv2.calcHist([blur],[0],None,[256],[0,256])
hist_norm = hist.ravel()/hist.max()
Q = hist_norm.cumsum()

bins = np.arange(256)

fn_min = np.inf
thresh = -1

for i in range(1,256):
    p1,p2 = np.hsplit(hist_norm,[i]) # probabilities
    q1,q2 = Q[i],Q[255]-Q[i] # cum sum of classes
    b1,b2 = np.hsplit(bins,[i]) # weights

    # finding means and variances
    m1,m2 = np.sum(p1*b1)/q1, np.sum(p2*b2)/q2
    v1,v2 = np.sum(((b1-m1)**2)*p1)/q1,np.sum(((b2-m2)**2)*p2)/q2

    # calculates the minimization function
    fn = v1*q1 + v2*q2
    if fn < fn_min:
        fn_min = fn
        thresh = i

# find otsu's threshold value with OpenCV function
ret, otsu = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
print(thresh)
print(ret)

 

 

오츠 이진화 알고리즘 수행과정 

- 수식 

1. 이미지 읽고 블러링

 

2. 히스토그램을 구하고, 정규화 후 누적 확률 분포(위 식에서 q) 얻기

3. 이진화 구간, 파라미터 설정

4. i 값에 따라 정규화 히스토그램, 누적합, 이진화 구간 분리

 

5. 4에서 구한 확률들과 두 클래스의 누적확률분포, 이진화 구간(가중치로 사용)으로 기대값 계산

 

6. 오츠 임계화에 필요한 omega^2구하기

 - [가중치(이진 구간) - 기대값]^2 * i일 확률 / 누적확률분포

 

 

 

7. 오츠 최소화 함수 계산

- 모든 픽셀에 대해 루프 돌면서, 비용 함수가 최소가 될때 오츠값(ft_min)과 임계치(thresh)를 구함

 

300x250
728x90

목표

- 이미지를 가지고 기하학적 변환을(평행이동, 회전, 어파인 등) 해봅시다.

 

대표적인 기하학적 변환 함수

-opencv에서 대표적으로 2가지 변환 함수 제공

- cv2.warpAffine : 어파인 변환= 평행이동 + 회전+ 스케일링

- cv2.warpPerspective : 원근 변환 = 평행 이동 + 회전 + 스케일링 + 원근

 

 

스케일링 변환

- 이미지 크기 조절 -> cv2.resize()

- 사용되는 보간법 -> ex. cv2.INTER_AREA(크기 줄일때), cv2.INTER_CUBIC or cv2.INTER_LINEAR(크기 늘릴떄)

 

파일명 : 01_scaling.py

- 원본 이미지 2배로 늘림. INTER_CUBIC 보간법 사용

import cv2
import numpy as np

img = cv2.imread("C:/Users/do/Documents/github/opencv_python/05day/kimheungkook.jpg")

height, width = img.shape[:2]
res = cv2.resize(img,(2*width, 2*height), interpolation = cv2.INTER_CUBIC)
cv2.imshow('image1',img)
cv2.imshow('image2',res)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

 

 

평행이동 변환

- 이미지를 밀어내는 변환

- (x. y) 좌표계 상에서 (t_x, t_y)만큼 이동시키는 변환 행렬 M은 아래와 같음

=> cv2.warpAffine() 함수에 매개변수로 넣어 100,50 정도 이동

 

- x축으로 100, y축으로 50 만큼 이동

import cv2
import numpy as np

img = cv2.imread("C:/Users/do/Documents/github/opencv_python/05day/kimheungkook.jpg", 0)

rows,cols = img.shape

M = np.float32([[1,0,100],[0,1,50]])
dst = cv2.warpAffine(img,M,(cols,rows))
cv2.imshow('img',img)
cv2.imshow('dst',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

 

 

 

 

회전 rotation 변환

- 각도 theta만큼 이미지를 회전시키는 변환 행렬 M은 아래와 같음

- 하지만 opencv는 중심점을 지정해서 회전 가능

- cv2.getRotationMatrix2D 함수로 위와 같은 회전 변환 행렬을 얻을 수 으며 스케일링 없이 90도 회전한 결과는 아래와 같음

 

import cv2
import numpy as np

img = cv2.imread("C:/Users/do/Documents/github/opencv_python/05day/kimheungkook.jpg", 0)
rows,cols = img.shape

M = cv2.getRotationMatrix2D((cols/2,rows/2),90,1)
dst = cv2.warpAffine(img,M,(cols,rows))
cv2.imshow('img',img)
cv2.imshow('dst',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

 

 

 

 

 

 

 

어파인 변환

- 어파인 변환에서 원근 변형은 생기지 않음.

- 이 변환을 하려면 입력 영상에서 3점과 출력 영상에서 대응할 점 3개를 지정해야함

- cv2.getAffineTransform 함수로 2 x 3 행렬을 만들어 cv2.warpAffine 수행

 * 어파인 변환= 회전, 평행이동, 스케일링이 수행됨

 

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread("C:/Users/do/Documents/github/opencv_python/05day/kimheungkook.jpg")
rows,cols,ch = img.shape

pts1 = np.float32([[50,50],[200,50],[50,200]])
pts2 = np.float32([[10,100],[100,24],[80,200]])

M = cv2.getAffineTransform(pts1,pts2)

dst = cv2.warpAffine(img,M,(cols,rows))

plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()

 

 

 

 

원근변환 perspective transform - 기울어진 사진을 펴기

- 원근 변환 시에는 3 x3의 변환 행렬이 필요합니다. 이 행렬을 구하기 위해선 입력 이미지의 4개의 점과 출력 영상에서 4점이 필요하며, cv2.getPerspectiveTransform 함수로 얻을 수 있습니다.

- 그러고 나서 cv2.warpPerspective 함수로 아까 구한 변환 행렬을 사용하면 원근 변환된 이미지를 얻게 됩니다.

 

 

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread("C:/Users/do/Documents/github/opencv_python/05day/kim_perspective.png")
rows,cols,ch = img.shape

pts1 = np.float32([[11,5],[592,17],[512,438],[90,440]])
pts2 = np.float32([[0,0],[592,0],[592,442],[0,442]])

M = cv2.getPerspectiveTransform(pts1,pts2)

dst = cv2.warpPerspective(img,M,(592,442))


cv2.imshow('img',img)
cv2.imshow('dst',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

- 아래의 사진은 원본 이미지로 592 x 442 크기

- 기존 모서리 : (11,5), (592. 17), (512, 438), (90, 440)

- 변경 후 모서리 : (0,0) (592, 0), (592, 442), (0, 442)

 

300x250
728x90

이미지 기본 연산 다루기

 

1. 목표

 

- 특정 픽셀에 접근해서 값을 바꿔봅시다

- 이미지 속성에 접근해 보겠습니다.

- 이미지 영역 Region Of Interest(ROI)을 설정해봅시다

- 이미지를 나누거나 병합해봅시다.

 

 이번에 학습할 연산들은 opencv보다 넘파이와 관련이 많습니다. 또, opnecv로 최적화된 코드를 작성하기 위해서는 넘파이에 대해 깊이 이해하는게 필요합니다.

 

 

 

2. 특정 픽셀에 접근해서 값을 바꾸기

 

import cv2
import numpy as np

img = cv2.imread('/Users/jdo/git/python_vision/01day/kimheungkook.jpg',cv2.IMREAD_COLOR)


px = img[100, 100]
# bgr 색상모델 값을 출력해줍니다.
print(px)

# 파랑색 요소만 접근해서 출력해봅시다.
blue = img[100, 100, 0]
print (blue)


# 동일한 방법으로 픽셀 값을 바꿀수도 있습니다.
img[100, 100] = [255, 255, 255]
print(img[100, 100])

cv2.imshow("iamge", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

파일명 : 01_pixel.py

- 이미지를 우선 로드하고

- 한 픽셀을 y, x 좌표계로 접근해 봅시다.

- BGR 이미지로 로드한 경우 파랑, 녹색, 빨강 값으로 이루어진 배열이 반환될겁니다.

- 흑백 영상의 경우에는 명암 강도 하나만 반환 됩니다.

 

 

 

 

 

- '나' 사이에 흰 점이 보이죠?

# img[100,100] = [255, 255, 255]

 

 

 

 

 

 

 

 

2. 이미지 속성 접근하기

 

 이미지 속성으로는 행과 열, 채널의 수(shape), 이미지 데이터 타입(dtype), 픽셀의 갯수(size) 등이 있습니다.

 

 각 요소에는 아래의 코드로 접근 가능 합니다.

 

import cv2
import numpy as np

img = cv2.imread('/Users/jdo/git/python_vision/01day/kimheungkook.jpg',cv2.IMREAD_COLOR)


print(img.shape)

print(img.size)

print(img.dtype)

파일명 : 02_property.py

 

 

 

 

 

3. 이미지 관심영역 Image ROI

 

 이미지의 특정 영역을 다루고 싶은 경우도 있습니다. 영상에서 눈 검출을 하는 경우 얼굴을 찾을떄까지 영상 전체에서 얼굴 검출을 수행하게 되는데요. 얼굴을 찾고나면 눈의 위치 찾기를 시작합니다. 얼굴위에는 항상 눈이 있으니까 이 방법으로 정확성을, 작은 영역을 찾으므로 성능을 개선시킬수가 있습니다.

 

 ROI는 넘파이 인덱싱을 사용해서 얻을수 있는데요. 다음과 같이 이미지를 변경시킬수도 있습니다.

 

import cv2
import numpy as np

img = cv2.imread('/Users/jdo/git/python_vision/01day/kimheungkook.jpg',cv2.IMREAD_COLOR)


# y x좌표
name = img[55:85, 30: 150]
img[200:230, 200:320] = name
img[340:370, 200:320] = name


cv2.imshow("iamge", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

파일명 : 03_roi.py

 

- 원본 영상에서 이름 영역 (y,x 좌표상) 55:85(y), 30 : 150(x)의 값들을 name 변수에 담아 지정한 좌표에 담아줬더니

- 이름이 복사된 결과를 학인할 수 있습니다.

 

 

 

 

 

 

 

 

 

300x250
728x90

트랙바를 컬러 팔래트로 사용하기

 

1. 목표

- opencv 윈도우 상에 트랙바를 올리는 방법을 배워봅시다.

- 이번에는 cv2.getTrackbarPos(), cv2.createTrackbar() 등의 함수들을 배워보겠습니다.

 

 

2. 코드 데모

 

 이번 시간에는 지정한 색상을 보여주는 간단한 어플을 만들어 보겠습니다. 우리가 만들 프로그램은 색상을 보여주고 3개의 BGR 컬러를 지정가능한 트랙바를 가진 윈도우를 만들고자 합니다. 트랙바를 슬라이드해서 이와 적합하도록 윈도우 색상이 변하게 될겁니다. 초기에는 검은색으로 초기화 시키도록 하겠습니다.

 

 cv2.getTrackbarPos() 함수는 첫번째 매개변수로 트랙바 이름, 두번째는 이 트랙바가 부착될 윈도우 이름을 지정해주어야하고, 세번째 값으로는 디폴트 값, 네번째는 최대 값, 다섯번째는 트랙바가 변할떄마다 실행될 콜백 함수를 지정해주어야 합니다. 콜백 함수는 트랙바 위치 값을 디폴트 매개변수로 사용하게 됩니다. 하지만 이 케이스에서는 콜백 함수를 사용하지않으므로 단순히 pass 하도록 만들겠습니다.

 

 

 이 어플리케이션에서 다른 중요한 요소중 하나는 버튼(스위치)를 사용하는 것입니다. opencv에선 기능적으로 버튼을 제공하고 있지는 않지만 트랙바를 이용해서 스위치 같은 역활을 하도록 만들겠습니다. 여기서 스위치를 만들어, 스위치가 on이 되어있는 동안 어플이 동작하게 될거고, 그렇지 않으면 스크린이 항상 검은색이 되도록 하겠습니다.

 

import cv2
import numpy as np

def nothing(x):
	pass

#이름이 image인 검은 윈도우를 생성하겠습니다.
img = np.zeros((300, 513, 3), np.uint8)
cv2.namedWindow("image")


# 색사이 바뀌도록 하는 트랙바를 생성해봅시다.
cv2.createTrackbar("R", "image", 0, 255, nothing)
cv2.createTrackbar("G", "image", 0, 255, nothing)
cv2.createTrackbar("B", "image", 0, 255, nothing)

# on/off를하는 스위치를 만들어봅시다.
switch = "0 : OFF \n 1 : ON"
cv2.createTrackbar(switch, "image", 0, 1, nothing)


while (1):
	cv2.imshow("image", img)
	k = cv2.waitKey(1) & 0xFF
	if k == 27:
		break

	# 트랙바값 읽기
	r = cv2.getTrackbarPos("R", "image")
	g = cv2.getTrackbarPos("G", "image")
	b = cv2.getTrackbarPos("B", "image")
	s = cv2.getTrackbarPos(switch, "image")

	# 스위치가 OFF이면 검은화면으로, On이면 색상 띄우기
	if s == 0:
		img[:] = 0
	else:
		img[:] = [b,g,r]

cv2.destroyAllWindows()

파일명 : 04_trackbar.py

 

 

 

 

 

 

 

 

 

 

 

 

 

300x250
728x90

마우스를 패인트 브러쉬로 사용하기

 

 

 

 

 

 

 

 

 

 

1. 목표

- 마우스 이벤트를 핸들링(다루는) 방법을 배워봅시다.

- 여기서 다음 함수를 사용하겠습니다 : cv2.setMouseCallback()

 

 

2. 간단한 데모

 

 이미지에 더블클릭하면 원을 그리는 간단한 어플을 만들어 보겠습니다.

 

- 마우스 콜백 함수를 만듭시다

 

-. 마우스 이벤트가 발생할때마다(왼쪽 마우스 누르거나, 때는 등) 해당 마우스 이벤트의 좌표를 알려줍니다.

 

- 이때 이벤트와 좌표로 아무거나 할수 있습니다. 

 

- 마우스 콜백 함수(이벤트가 발생시 호출할 함수)를 특정한 형식으로 정의해주고, 더블 클릭을 할때 원을 그리는 동작을 하도록 해봅시다.

 

 

 

 

import cv2
import numpy as np

# mouse callback function
def draw_circle(event,x,y,flags,param):
    if event == cv2.EVENT_LBUTTONDBLCLK:
        cv2.circle(img,(x,y),100,(255,0,0),-1)

# Create a black image, a window and bind the function to window
img = np.zeros((512,512,3), np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_circle)

while(1):
    cv2.imshow('image',img)
    if cv2.waitKey(20) & 0xFF == 27:
        break
cv2.destroyAllWindows()

파일명 : 01_simplecallback.py

 

=> 더블 클릭한 자리에 반지름이 100픽셀인 꽉찬 파란색이 생성되었습니다.

 

 

 

 

 

3. 사진에 콜백을 등록해서 원그리기

 

import cv2
import numpy as np

# mouse callback function
def draw_circle(event,x,y,flags,param):
    if event == cv2.EVENT_LBUTTONDBLCLK:
        cv2.circle(img,(x,y),20,(255,0,0),4)

# Create a black image, a window and bind the function to window
img = cv2.imread("/Users/jdo/Documents/GitHub/opencv_python/04day/sarangsonnim.png",cv2.IMREAD_COLOR)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_circle)

while(1):
    cv2.imshow('image',img)
    if cv2.waitKey(20) & 0xFF == 27:
        break
cv2.destroyAllWindows()

파일 명 : 02_demo.py

- 아래의 가족 사진에  반지름 20, 폭이 2인 파란색 원을 그리는 콜백함수 등록 하는 응용프로그램

 

 

 

 

 

 

 

4. 데모 프로그램 개선하기

 

 이번에 더 나은 어플을 만들어 봅시다. 이번에는 설정한 모드에 따라서 사각형을 그리거나 원을 드래그를 해서 그릴수 있도록 구현하겠습니다. 그래서 마우스 콜백 함수에는 2파트로 나뉘게 되는데, 하나는 사각형, 나머지 하나는 원을 그리는 내용들이 되겠습니다

 

 다음 예시가 나중에 물체 추적과 영상 분할같은 상호작용(인터렉티브) 어플을 만들고 이해하는데 많은 도움이 되겠스비다.

 

 

import cv2
import numpy as np
import math

drawing = True # true if mouse is pressed
mode = False # if True, draw rectangle. Press 'm' to toggle to curve
ix,iy = -1,-1

# mouse callback function
def draw_circle(event,x,y,flags,param):
	global ix,iy,drawing,mode

	if event == cv2.EVENT_LBUTTONDOWN:
		drawing = True
		ix,iy = x,y

	elif event == cv2.EVENT_LBUTTONUP:
		drawing = False
		if mode == True:
			cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),5)
		else:
			radius = (ix-x)^2 + (iy - y)^2
			print(radius)
			cv2.circle(img,(x,y),int(radius),(0,0,255),5)


img = cv2.imread("/Users/jdo/Documents/GitHub/opencv_python/04day/sarangsonnim.png",cv2.IMREAD_COLOR)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_circle)

while(1):
    cv2.imshow('image',img)
    k = cv2.waitKey(1) & 0xFF
    if k == ord('m'):
        mode = not mode
    elif k == 27:
        break

cv2.destroyAllWindows()

파일명 ; 03_dragdemo.py

 

1. 사진을 띄웁니다.

2. 마우스 콜백 등록합니다.

3. 마우스 콜백에서 마우스 왼쪽을 누르면 시작점 지정

4. 꾹 누른 상태에서 이동후 마우스 올리면 현재 위치까지 사각형이나 해당 길이를 반지름으로 하는 원이 그려짐

5. 중간에 m키를 누르면 모드가 변경

 

 

300x250
728x90

1. 목표

- opencv로 기하학적 형태를 그리는 방법에 대해서 배워봅시다.

- 여기서 다음의 함수들을 배워보겠습니다.

 ex) cv2.line(), cv2.circle(), cv2.rentagle(). cv2.ellipse(), cv2.putText()

 

 

2. 코드 개요

- 위 함수들을 사용해보기 전에 일반적으로 사용되는 매개변수들에 대한 설명들을 하겠씁니다.

- img : 드로잉을 할 이미지(그림) 파일을 의미합니다.

- color : 색상 값을 BGR 형태로 입력해 줍니다.(명시하지 않으면 하나의 튜플, 즉 그레이스케일로 지정됩니다.)

     예를 들어 (255, 0, 0)을 하면 파란 색이나오고, 그레이 스케일을 사용한다면 스칼라 값 하나를 적어주면 되겠습니다

- thickness 두께 : 두께는 원이나 선의 두꼐를 의미합니다. 기본 값은 1

- lineType : 선의 특징을 지정하며, 8연결성이나 안티에일리어싱 같은게 있습니다. 기본 값은 8연결성으로,

                 cv2.LINE_AA를 줄 경우 곡선에서 더 보기 좋게 만들어 집니다.

 

* 안티 에일리어싱 : 계단현상 방지기능

https://namu.wiki/w/%EC%95%88%ED%8B%B0%EC%97%90%EC%9D%BC%EB%A6%AC%EC%96%B4%EC%8B%B1

 

 

3. 선 그리기

 

 선을 그리려면 시작점과 끝점을 지정해주면 됩니다.

1. 우선 검은색 영상을 생성해주고

2. 왼쪽 위에서 오른쪽 아래까지 파란 선을 그려주겠습니다.

 

import numpy as np
import cv2

# Create a black image
img = np.zeros((512,512,3), np.uint8)

# Draw a diagonal blue line with thickness of 5 px
img = cv2.line(img,(0,0),(511,511),(255,0,0),5)

cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

 파일 명 : 01_drawline.py

 

 

 

4. 사각형 그리기

import numpy as np
import cv2

# Create a black image
img = np.zeros((512,512,3), np.uint8)

img = cv2.rectangle(img,(384,0),(510,128),(0,255,0),3)

cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

파일명 : 02_drawrectangle.py

- 왼쪽 위 코너와 오른쪽 아래 코너, 색상과 두께를 지정해주면 만들어 집니다.

- 이번 예제는 녹색 상자로 두께가 3

 

 

 

5. 원을 그려보자

 

 원을 그리려면 원의 중심과 반지름을 명시해주면 됩니다. 추가로 색상과 두께를 지정해주면 그려지는데 이번 경우에는 두께자리에 -1을 주어 원안을 빨간색으로 채우겠습니다.(BGR 모델)

 

import numpy as np
import cv2

# Create a black image
img = np.zeros((512,512,3), np.uint8)

img = cv2.circle(img,(447,63), 63, (0,0,255), -1)

cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

파일명 : 03draw_circle.py

 

 

 

 

 

300x250
728x90

 

 

 

 

1. 목표

- 영상을 읽고, 돌려보고, 저장하는 방법을 배워봅시다.

- 카메라 영상(웹캠이나, 비디오)을 읽어들이고 출력하는 방법을 배웝보시다.

- 여기서 다음 함수를 배우겠습니다. : cv2.VideoCapture(), cv2.VideoWriter()

 

 

2. 카메라(혹은 웹캠)에서 읽어보기

 

 카메라로부터 실시간 스트리밍이 필요하다면 opencv에서 간단한 인터페이스(함수)를 제공하고 있습니다. 카메라로 부터 비디오 영상들을 캡처하여 이를 회색 영상으로 바꾸고 출력해보도록 하겠습니다.

 

 비디오를 캡처하려면, VideoCapture라고 부르는 객체를 만들어야 합니다. 여기서 매개변수는 읽어들일 비디오 파일 이름이나 카메라 장치의 번호를 주면 됩니다. 장치 번호는 어느 카메라를 선택할건지 명시하는 요소입니다(보통 내장 웹캠은 0, 추가 usb 웹캠은 1, 2, 3 순으로)  비디오 캡처로 읽어들이면 프레임 단위로 확인할수 있으나, 작업이 다끝난후 자원을 해제하는걸 잊지 말아주세요

 

 

 

import cv2

cap = cv2.VideoCapture("/Users/jdo/Documents/GitHub/opencv_python/02day/horangnabi.mp4")

while(True):
	# Capture frame-by-frame
	ret, frame = cap.read()
	print(frame)
	# Our operations on the frame come here
	gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

	# Display the resulting frame
	cv2.imshow('frame',gray)
	if cv2.waitKey(1) & 0xFF == ord('q'):
		break

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

 

파일명 : 01_videocapture.py

- cap.read() 함수는 반환 결과 ret와 영상 한 프레임 frame을 반환합니다(위코드에서)

 

* 맥북에서 웹캠 스트리밍이 안되는 관계로 호랑나비 영상으로 대체

 

 

 

 

3, 비디오 저장하기

 

 캡처한 비디오를 저장하는 방법은 간단하게도 cv2.imwrite()함수를 사용ㅎ가ㅣ만 하면 됩니다. 단지 여기서 추가적인 작업만 몇개 더함녀 되는데, videowrite 객체를 생성해 주면 됩니다. 여기서 출력할 파일 명을 명시해주고(ex. output.avi) FourCC를 정의하면 됩니다.

 

  FourCC는 비디오 코덱을 설정하기 위한 4바이트 암호화기(?)로 fourcc.org에서 상세한 정보를 확인하실수 있겠습니다.

 다음의 코덱들이 저의 경우에 사용가능 했었습니다.

 

 

  • In Fedora: DIVX, XVID, MJPG, X264, WMV1, WMV2. (XVID is more preferable. MJPG results in high size video. X264 gives very small size video)
  • In Windows: DIVX (More to be tested and added)
  • In OSX : (I don’t have access to OSX. Can some one fill this?)

 

 FourCC 암호화기는 MJPG로 비디오를 저장하고자 할때 다음과 같이 명시하시면 되겠습니다.

-> cv2.VideoWriter_fourcc('M','J','P','G')

-> cv2.VideoWriter_fourcc(*'MJPG) 

 

import numpy as np
import cv2

cap = cv2.VideoCapture("/Users/jdo/Documents/GitHub/opencv_python/02day/horangnabi.mp4")

# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
out = cv2.VideoWriter('output.mp4',fourcc, 10.0, (492,360))

while(cap.isOpened()):
	ret, frame = cap.read()
	#print(frame.shape)
	if ret==True:
		frame = cv2.flip(frame,0)

		# write the flipped frame
		out.write(frame)

		cv2.imshow('frame',frame)
		if cv2.waitKey(1) & 0xFF == ord('q'):
			break
	else:
		break

# Release everything if job is finished
cap.release()
out.release()
cv2.destroyAllWindows()

파일명 ; 02_savingvideo.mp4

- cv2.videowriter()를 명시할떄, 원본 영상과 동일한 해상도를 지정해 주어야 합니다.

=> 안하면 영상 저장이 제대로 안됨

 

 

 

 

 

300x250

+ Recent posts