Opencv

7-3-4 라즈베리파이 컴퓨터 비전으로 직행하기 위한 Opencv 3.3의 기초 사용법-III

coding art 2019. 12. 22. 19:50
728x90

Opencv의 기초 사용법은 반드시 Opencv가 아니더라도 그래픽이나 이미지 처리를 지원하는 웬만한 라이브러리라면 제공이 가능한 기능들이지만 인공지능 또는 머신 러닝을 위해 사용 가능한 Opencv만의 특수한 기능들을 알아보자. 카메라에 찍히는 개개의 이미지 프레임이나 이미지 파일에 담겨 있는 오브젝트를 형상이나 픽셀 차원에서 검출하여 오브젝트의 수를 체크하고 각 오브젝트별로 기하학적인 세부 모양새를 파악하기 위해서 Edge 검출(Detection)이 가능해야 한다. 한편 오브젝트의 Edge의 광학적 특성 상 오브젝트의 컬러 자체 보다는 급격히 밝기가 변화하는 영역을 찾아내거나 추적하면 되므로 굳이 컴퓨팅 부담이 클 수도 있는 3 channel 의 컬러 이미지를 사용할 필요는 없으며 흑백으로 변환된 이미지(gray scaled image)를 사용해도 충분하다. 고양이와 같은 포유류에는 색상을 구별하는 시각세포가 없음에도 야간 사냥에 아무런 문제가 없다는 점을 참고하자.

 

 

결국 오브젝트들의 Edge 검출이 가능하다면 결국 Contour를 확정할 수 있으며 이 Contour 형상을 대상으로 크기를 축소시키든지(Erosion) 반대로 확대(Dilatation) 시킬 수 있을 것이다. Edge 라는 것은 오브젝트 물체의 윤곽선으로서 그 물리적 특징이랄까 또는 광학적 특징이랄까 주변(Neighborhood) 와 비교 시 빛의 밝기 변화가 심하게 일어나는데 포유류의 시각 피질인 cortex 시스템의 특징이 이 Edge에 민감하게 반응한다는 점이다. 이러한 사실은 1959년 하바드 의대의 노벨상 수상자인 후벨 박사에 의해 연구가 시작된 이래 머신러닝의 핵심이랄 수 있는 CNN(Convolutionary Neural Network) 알고리듬의 바탕이 되었다.

 

 

 

Grayscaled 된 이미지르 관찰해 보면 배경은 흰색이므로 값이 255 이며 회색은 0255 사이 값을 가지며 검정색은 0이 된다. grayscaled 이미지를 대상으로 Threshold를 적용해 보자. Threshold란 뉴론에서 시냅스를 통해 웨이팅 되어 입력된 신호의 합을 대상으로 threshold 값 이상이면 “H” 이하이면 “L” 처리하듯이 threshold 값을 인위적으로 설정하여 tetris 이미지를 처리해 보자.

두 번째 파라메터 값 225는 최소 treshold 기준 값이며 3번째 파라메터 255는 최대 값을 뜻한다. 4번째 파라메터는 binary_inv binary가 있는데 아래 그림은 binary_inv로서 원래 값의 욕으로 계산한 것이다.

 

 

Edge 검출 기능과 Threshold 기능은 머신 러닝 중에서 픽셀 단위로 학습을 시키는 Semantic Segmentation 작업에 필수적인 요소이다.

 

이미지가 Threshold 처리가 되어 있어야 findContours drawContours 가 가능하다. imutils.grab_contours 명령은 Contour 의 총 갯수 값을 뜻한다.

 

 

Erodeiterations 수만큼 Contour 라인의 선 굵기만큼 지우는 명령이다.

 

 

반면에 Dilateiterations 수만큼 Contour 라인의 선 굵기만큼 덧붙이는 명령이다

 

 

 

bitwise_and 는 두 이미지의 AND 한 결과 이미지를 출력하되 mask 가 있으면 적용한다.

mask는 이미 언급했듯이 Threshold 처리에 의해 준비한 것을 사용하면 아래 그림에서처럼 원래의 컬러가 다시 살아나게 되며 나머지는 mask 의 배경색인 검정색으로 처리 된다.

 

 

 

#opencv_tutorial_02.py

# import the necessary packages

import argparse

import imutils

import cv2

 

# construct the argument parser and parse the arguments

ap = argparse.ArgumentParser()

ap.add_argument("-i", "--image", required=True,

help="path to input image")

args = vars(ap.parse_args())

 

# load the input image (whose path was supplied via command line

# argument) and display the image to our screen

image = cv2.imread(args["image"])

cv2.imshow("Image", image)

cv2.waitKey(0)

 

# convert the image to grayscale

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

cv2.imshow("Gray", gray)

cv2.waitKey(0)

 

# applying edge detection we can find the outlines of objects in

# images

edged = cv2.Canny(gray, 30, 150)

cv2.imshow("Edged", edged)

cv2.waitKey(0)

 

# threshold the image by setting all pixel values less than 225

# to 255 (white; foreground) and all pixel values >= 225 to 255

# (black; background), thereby segmenting the image

thresh = cv2.threshold(gray, 225, 255, cv2.THRESH_BINARY_INV)[1]

cv2.imshow("Thresh", thresh)

cv2.waitKey(0)

 

# find contours (i.e., outlines) of the foreground objects in the

# thresholded image

cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,

cv2.CHAIN_APPROX_SIMPLE)

cnts = imutils.grab_contours(cnts)

output = image.copy()

 

# loop over the contours

for c in cnts:

# draw each contour on the output image with a 3px thick purple

# outline, then display the output contours one at a time

cv2.drawContours(output, [c], -1, (240, 0, 159), 3)

cv2.imshow("Contours", output)

cv2.waitKey(0)

 

# draw the total number of contours found in purple

text = "I found {} objects!".format(len(cnts))

cv2.putText(output, text, (10, 25),  cv2.FONT_HERSHEY_SIMPLEX, 0.7,

(240, 0, 159), 2)

cv2.imshow("Contours", output)

cv2.waitKey(0)

 

# we apply erosions to reduce the size of foreground objects

mask = thresh.copy()

mask = cv2.erode(mask, None, iterations=0)

cv2.imshow("Eroded", mask)

cv2.waitKey(0)

 

# similarly, dilations can increase the size of the ground objects

mask = thresh.copy()

mask = cv2.dilate(mask, None, iterations=0)

cv2.imshow("Dilated", mask)

cv2.waitKey(0)

 

# a typical operation we may want to apply is to take our mask and

# apply a bitwise AND to our input image, keeping only the masked

# regions

mask = thresh.copy()

output = cv2.bitwise_and(image, image, mask=mask)

cv2.imshow("Output", output)

 

cv2.waitKey(0)