이미지의 특정 영역을 다루고 싶은 경우도 있습니다. 영상에서 눈 검출을 하는 경우 얼굴을 찾을떄까지 영상 전체에서 얼굴 검출을 수행하게 되는데요. 얼굴을 찾고나면 눈의 위치 찾기를 시작합니다. 얼굴위에는 항상 눈이 있으니까 이 방법으로 정확성을, 작은 영역을 찾으므로 성능을 개선시킬수가 있습니다.
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 변수에 담아 지정한 좌표에 담아줬더니
- 이번에는 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()
-. 마우스 이벤트가 발생할때마다(왼쪽 마우스 누르거나, 때는 등) 해당 마우스 이벤트의 좌표를 알려줍니다.
- 이때 이벤트와 좌표로 아무거나 할수 있습니다.
- 마우스 콜백 함수(이벤트가 발생시 호출할 함수)를 특정한 형식으로 정의해주고, 더블 클릭을 할때 원을 그리는 동작을 하도록 해봅시다.
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. 꾹 누른 상태에서 이동후 마우스 올리면 현재 위치까지 사각형이나 해당 길이를 반지름으로 하는 원이 그려짐
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()
- 여기서 다음 함수를 배우겠습니다. : 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()
- 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()를 명시할떄, 원본 영상과 동일한 해상도를 지정해 주어야 합니다.