본문 바로가기

IT/Python

【OpenCV 4】Day2_주요 기능

※ Jupyter Notebook을 사용함

카메라와 동영상 파일 다루기

드로이드캠 영상

안드로이드 스마트폰 앱 중 DroidCam을 이용하면 스마트폰 카메라에서 촬영한 영상을 소켓 통신을 통해 보내고 받을 수 있다.

- 사용 순서
1. 플레이스토어에서 DroidCam 설치(아이폰의 경우 App Store)
2. 스마트폰에서 DroidCam 앱을 실행하고 와이파이 IP, 포트 번호, 'mpegfeed'를 사용해 VideoCapture 객체 cap을 생성(http://IP:port/mjpegfeed')
3. 와이파이 IP, 포트 번호는 스마트폰 및 와이파이 환경에 따라 다르고, 'mjpegfeed' 문자열은 앱에 따라 다를 수 있음.
아이폰의 경우 (http://IP:port/video')


import cv2
import sys
#VideoCapture클래스 - 카메라 또는 동영상 파일로부터 정지영상 프레임을 받아올수 있다. 
cap = cv2.VideoCapture('http://192.XXX.0.XXX:4747/video') # 카메라 디바이스, 동영상 파일명, 스트리밍 주소

if not cap.isOpened():
    print("Camera open failed!!")
    sys.exit()


w, h = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS)

print("frame width, height:", w, h)

fourcc = cv2.VideoWriter_fourcc(*"DIVX")
outputVideo1 = cv2.VideoWriter('./out/droid_frame.avi', fourcc, fps, (w, h))
outputVideo2 = cv2.VideoWriter('./out/droid_inverse.avi', fourcc, fps, (w, h))

while True:
    ret, frame = cap.read()
    
    if not ret:
        break
    
    inversed = ~frame
    
    outputVideo1.write(frame)
    outputVideo2.write(inversed)
    
    cv2.imshow("frame", frame)
    cv2.imshow("inversed", inversed)
    
    if cv2.waitKey(10) == 27: #sleep 효과
        break

if cap.isOpened():
    cap.release()
    
outputVideo1.release()
outputVideo2.release()
cv2.destroyAllWindows()

### 유튜브 영상

pafy : 비디오에서 메타데이터 획득, 비디오/오디오를 다운로드 하는 패키지 youtube_dl : patfy의 backend에서 유튜브 동영상을 다운로드

설치방법 pip install pafy pip install youtube_dl

import pafy

url = 'https://www.youtube.com/watch?v=9SmQOZWNyWE&list=RD9SmQOZWNyWE&index=1'

video = pafy.new(url)
print("title:", video.title)
print("rating:", video.rating)
print("duration:", video.duration)

best = video.getbest()
# best.url : download 가능한 url
# best.resolution : video의 해상도
-->
title: BTS - "Permission to Dance" performed at the United Nations General Assembly | SDGs | Official Video
rating: None
duration: 00:03:43
best.url
--> 
'https://rr5---sn-ab02a0nfpgxapox-jwws.googlevideo.com/videoplayback?expire=1641279979&ei=i53TYYimHaiRvcAPytGWiAQ&ip=112.220.17.226&id=o-ACAcwwEKI-N3p-B_CO8_0G45U7F-LrYzFKhmR5lcquQP&itag=18&source=youtube&requiressl=yes&mh=e9&mm=31%2C26&mn=sn-ab02a0nfpgxapox-jwws%2Csn-o097znz7&ms=au%2Conr&mv=m&mvi=5&pl=24&initcwndbps=472500&vprv=1&mime=video%2Fmp4&ns=d3t95BJC3u3y4sNfS22RkKUG&gir=yes&clen=19255716&ratebypass=yes&dur=223.445&lmt=1632650578912066&mt=1641258061&fvip=5&fexp=24001373%2C24007246&c=WEB&txp=5530434&n=xd87H6e0UHZEXTHb&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cvprv%2Cmime%2Cns%2Cgir%2Cclen%2Cratebypass%2Cdur%2Clmt&sig=AOq0QJ8wRgIhALMisAkX4P-vlvm9Mn7Hw5qiZjRXxmcHtDlLgxoXSxv2AiEA4J5vC63bfOdZW_FBUbiGVFdIn5B03MkxlVV3g97kQMU%3D&lsparams=mh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&lsig=AG3C_xAwRQIhAJAWNJEqvp9p35Hu8I7s3pF7GwottMJq9KID-0_6U9mzAiAERHEIsgJ-DXXLiYkjMyHjdBRyMGF-4e7gGz_TS_LFsQ%3D%3D'
cap = cv2.VideoCapture(best.url) # 카메라 디바이스, 동영상 파일명, 스트리밍 주소

if not cap.isOpened():
    print("Camera open failed!!")
    sys.exit()


w, h = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS)

print("frame width, height:", w, h)

fourcc = cv2.VideoWriter_fourcc(*"DIVX")
outputVideo1 = cv2.VideoWriter('./out/youtube_frame.avi', fourcc, fps, (w, h))
outputVideo2 = cv2.VideoWriter('./out/youtube_edge.avi', fourcc, fps, (w, h), isColor=False)

delay = round(1000/fps)
while True:
    ret, frame = cap.read()
    
    if not ret:
        break
    
    #inversed = ~frame
    
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    edge = cv2.Canny(gray, 100, 200)
    
    outputVideo1.write(frame)
    outputVideo2.write(edge)
    
    cv2.imshow("frame", frame)
    cv2.imshow("edge", edge)
    
    if cv2.waitKey(delay) == 27: #sleep 효과
        break

if cap.isOpened():
    cap.release()
outputVideo1.release()
outputVideo2.release()
cv2.destroyAllWindows()
--> 
frame width, height: 640 360

주요 함수와 클래스

VideCapture클래스

VideoCapture::VideoCapture(const String& filename, int apiPreference = CAP_ANY);
bool VideoCapture::open(const String& filename, int apiPreference = CAP_ANY);
카메라 또는 동영상 파일로 부터 정지영상 프레임을 받아 올 수 있다. 
・filename - 동영상 파일 이름
・apiPreference - 사용할 비디오 캡쳐 API백엔드
・반환값 -  (VideoCapture::open()함수)열기가 성공하면 true, 실패하면false
VideoCaptureAPIs열거형 상수
・CAP_ANY - 자동선택
・CAP_V4L, CAP_V4L2 - V4L/V4L2(리눅스)
・CAP_FIREWIRE, CAP_FIREWARE, CAP_IEEE1394 - IEEE1394드라이버
등등....

VideoCapture::VideoCapture(int index, int apiPreference = CAP_ANY);
bool VideoCapture::open(int index,int apiPreference = CAP_ANY);
컴퓨터에 연결된 카메라 장치를 사용하는 클래스
・filename - 동영상 파일 이름
・apiPreference - 사용할 비디오 캡쳐 API백엔드
・반환값 -  (VideoCapture::open()함수)열기가 성공하면 true, 실패하면false
VideoCapture::open() 함수에 전닿나느 정수값 index는 
index = camera_id + domain_offset_id
camera_id(한대의 경우 : 0, 두대 이상의 경우 : 0보다 같거나 큰 정수를 ID로 가진다)
domain_offset_id(카메라 장치를 사용하는 방식을 표현하는 정수값 VideoCaptureAPIs열거형 상수를 지정함)

bool VideoCapture::isOpened() const;
isOpened()멤버 함수를 이용하여 열기 작업이 성공적으로 수행되었는지 확인
・반환값 - 카메라 또는 동영상 파일이 사용 가능하면 true, 그렇지 않으면 false

virtual void VideoCapture::release();
release()함수를 호출하여 사용하던 자원을 해제

VideoCapture& VideoCapture::operator >> (Mat& image);
bool VideoCapture::read(OutputArray image);
VideoCapture클래스에서  한 프레임을 받아올때 사용.
・image - 다음 비디오 프레임, 만약 더 가져올 프레임이 없다면 비어 있는 행렬로 설정됨
・반환값 - 프레임을 받아 올 수 없으면 false 반환

double VideoCapture::get(int propId) const;
현재 열려 있는 카메라 장치 또는 동영상 파일로 부터 여러가지 정보를 받아 오기 위한 함수
・propId - 속성ID, VideoCaptureProperties 열거형 중 하나를 지정합니다.
・반환값 - 지정한 속성 값, 만약 지정한 속성을  얻을 수 없으면 0을 반환합니다.
VideoCaptureProperties 열거형 상수
・CAP_PROP_POS_MSEC - 비디오 파일에서 현재 위치(밀리초 단위)
・CAP_PROP_POS_FRAMES - 현재 프레임 위치(0-기반)
・CAP_PROP_POS_AVI_PATIO - [0, 1]구간으로 표현한  동영상 프레임의 상대적 위치(0: 시작, 1:끝)
・CAP_PROP_FRAME_WIDTH - 비디오 프레임의 가로 크기
・CAP_PROP_FRAME_HEIGHT - 비디오 프레임의 세로 크기
・CAP_PROP_FPS - 초당 프레임 수
・CAP_PROP_FOURCC - fourcc코드(코덱을 표현하는 정수값)
・CAP_PROP_FRAME_COUNT - 비디오 파일의 전체 프레임 수
・CAP_PROP_BRIGHTNESS - (카메라에서 지원하는 경우) 밝기 조절
・CAP_PROP_CONTRAST - (카메라에서 지원하는 경우) 명암비 조절
・CAP_PROP_SATURATION - (카메라에서 지원하는 경우) 채도 조절
・CAP_PROP_HUE - (카메라에서 지원하는 경우) 색상 조절
・CAP_PROP_GAIN - (카메라에서 지원하는 경우) 감도 조절
・CAP_PROP_EXPSURE - (카메라에서 지원하는 경우) 노출 조절
・CAP_PROP_ZOOM - (카메라에서 지원하는 경우) 줌 조절
・CAP_PROP_FOCUS - (카메라에서 지원하는 경우) 초점 조절

bool VideCapture::set(int propId, double value);
현재 열려 있는 카메라 또는 비디오 파일 재생과 관련된 속성값을 설정할 때 사용하는 함수
・propId - 속성ID, VideoCaptureProperties 열거형 중 하나를 지정합니다.
・value - 지정할 속성 값
・반환값 - 속성 지정이 가능하면 true, 아니면 false

 

카메라 입력 처리하기

동영상 파일 처리하기

동영상 파일 처리하기

https://github.com/sunkyoo/opencv4cvml/blob/master/python/ch04/video.py

 

GitHub - sunkyoo/opencv4cvml: "OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝" (길벗, 2019) 책 소스 코드입니

"OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝" (길벗, 2019) 책 소스 코드입니다. - GitHub - sunkyoo/opencv4cvml: "OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝" (길벗, 2019) 책 소스 코드입니다.

github.com

 

동영상 파일 저장하기

VideoWriter::VideoWriter(sonst String& filename, int fourcc, double fps, Size frameSize, bool isColor = true);
bool VideoWriter::open(const String& filename, int fourcc, double fps, Size frameSize, bool isColor = true);
VideoWirter 객체를 생성하였으면 open()멤버 함수를 이용하여 저장할 동영상 파일을 쓰기모드로 열어야합니다.
・filename - 저장할 동영상 파일 이름
・fourcc - 동영상 압축 코덱을 표현하는 4-문자코드
・fps - 저장할 동영사의 초당 프레임수
・frameSize - 동영상 프레임의 가로 및 세로 크기
・isColor - 이 값이 true이면 컬러 동영상으로 저장하고, false이면 그레이스케일 동영상으로 저장합니다. 이 플래그는 windows운영 체제에서만 지원 합니다.
・반환값 - (VideoWriter::open() 함수)열기사 성고하면 true, 실패하면 false

static int VideoWrier::fourcc(char c1, char c2, char c3, char c4)
fourcc는 동영상 파일의 코덱, 압축 방식, 색상 색상혹은 픽셀 포맷 등을 정의 하는 정수 값으로 코덱을 표현하는 네 개의 문자를 묶어서 fourcc를 생성하는 함수
・c1, c2, c3, c4 - 코덱을 표현하는 1byte 문자 네 개
・반환값 - 정수형 4-문자코드
fourcc코드 생성 방법
VideoWrier::fourcc('D', 'I', 'V', 'X') - DivX MPEG-4코덱
VideoWrier::fourcc('X', 'V', 'I', 'D') - XVID MPEG-5코덱 
VideoWrier::fourcc('F', 'M', 'P', '4') - FFMPEG MPEG4 코덱
등등

VideoWriter& VideoWriter::operator << (const Mat& image);
void VideoWriter::write(InputArray image);
열려있는 동영상 파일에 새로운 프레임으 추가하기 위해서는 << 연산자 재정의 또는 write()함수를 사용
・image - 추가할 프레임

virtual void VideoWriter::release();
영상 저장이 완료되면 열려있던 파일을 닫는 함수

# 다양한 그리기 함수

### 직선 그리기

import numpy as np
# 참고 (행렬의 색인순서는 y축, 즉 행부터)
mat = np.array([[1, 2, 3],[4,5,6], [7,8,9], [10, 11, 12]])
mat[3, 0]
--> Out :
10
img = np.full((400, 400, 3), 255, np.uint8)

cv2.line(img, (50, 50), (200, 50), (0, 0, 255))
cv2.line(img, (50, 100), (200, 100), (255, 0, 255), 3)
cv2.line(img, (50, 150), (200, 150), (255, 0, 0), 10)

cv2.line(img, (250, 50), (350, 100), (0, 0, 255), 1, cv2.LINE_4)
cv2.line(img, (250, 70), (350, 120), (255, 0, 255), 1, cv2.LINE_8)
cv2.line(img, (250, 90), (350, 140), (255, 0, 0), 1, cv2.LINE_AA)

cv2.arrowedLine(img, (50, 200), (150, 200), (0, 0, 255), 1)
cv2.arrowedLine(img, (50, 250), (350, 250), (255, 0, 255), 1)
cv2.arrowedLine(img, (50, 300), (350, 300), (255, 0, 0), 1, tipLength=0.05)

cv2.drawMarker(img, (50, 350), (0, 0, 255), cv2.MARKER_CROSS)
cv2.drawMarker(img, (100, 350), (0, 0, 255), cv2.MARKER_TILTED_CROSS)
cv2.drawMarker(img, (150, 350), (0, 0, 255), cv2.MARKER_STAR)
cv2.drawMarker(img, (200, 350), (0, 0, 255), cv2.MARKER_DIAMOND)
cv2.drawMarker(img, (250, 350), (0, 0, 255), cv2.MARKER_SQUARE)
cv2.drawMarker(img, (300, 350), (0, 0, 255), cv2.MARKER_TRIANGLE_UP)
cv2.drawMarker(img, (350, 350), (0, 0, 255), cv2.MARKER_TRIANGLE_DOWN)

cv2.imshow("img", img)              
cv2.waitKey()
cv2.destroyAllWindows()
--> 

 

### 도형 그리기

img = np.full((400, 400, 3), 255, np.uint8)

cv2.rectangle(img, (50, 50), (150, 100), (0, 0, 255), 2)
cv2.rectangle(img, (50, 150), (150, 200), (0, 0, 128),-1)

cv2.circle(img, (300, 120), 30, (255, 255, 0), -1)
cv2.circle(img, (300, 120), 60, (255, 0, 0), 3)

cv2.ellipse(img, (120, 300), (60, 30), 20, 0, 270, (255, 255, 0), cv2.FILLED, cv2.LINE_AA)
cv2.ellipse(img, (120, 300), (100, 50), 20, 0, 360, (255, 0, 0), 2, cv2.LINE_AA)

pts = np.array([[250, 250], [300, 250], [300, 300], [350, 300], [350, 350], [250, 350]])
cv2.polylines(img, [pts], True, (255, 0, 255), 2)         
            
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()
--> 

 

### 문자열 출력하기

img = np.full((500, 800, 3), 255, np.uint8)
cv2.putText(img, "FONT_HERSHEY_SIMPLEX", (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255))
cv2.putText(img, "FONT_HERSHEY_PLAIN", (20, 100), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 255))
cv2.putText(img, "FONT_HERSHEY_DUPLEX", (20, 150), cv2.FONT_HERSHEY_DUPLEX, 1, (0, 0, 255))
cv2.putText(img, "FONT_HERSHEY_COMPLEX", (20, 200), cv2.FONT_HERSHEY_COMPLEX, 1, (255, 0, 0))
cv2.putText(img, "FONT_HERSHEY_TRIPLEX", (20, 250), cv2.FONT_HERSHEY_TRIPLEX, 1, (255, 0, 0))
cv2.putText(img, "FONT_HERSHEY_COMPLEX_SMALL", (20, 300), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (255, 0, 0))
cv2.putText(img, "FONT_HERSHEY_SCRIPT_SIMPLEX", (20, 350), cv2.FONT_HERSHEY_SCRIPT_SIMPLEX, 1, (255, 0, 255))
cv2.putText(img, "FONT_HERSHEY_SCRIPT_COMPLEX", (20, 400), cv2.FONT_HERSHEY_SCRIPT_COMPLEX, 1, (255, 0, 255))
cv2.putText(img, "FONT_HERSHEY_COMPLEX | FONT_ITALIC", (20, 450), cv2.FONT_HERSHEY_COMPLEX | cv2.FONT_ITALIC, 1, (255, 0, 0))
            
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()
--> 

 

img = np.full((200, 640, 3), 255, np.uint8)

text = "Hello, OpenCV"
fontFace = cv2.FONT_HERSHEY_TRIPLEX
fontScale = 2.0
thickness = 1

sizeText, _ = cv2.getTextSize(text, fontFace, fontScale, thickness)
# print(type(sizeText))
# sizeText[0], sizeText[1]

org = (img.shape[1] - sizeText[0])//2, (img.shape[0] + sizeText[1])//2
cv2.putText(img, text, org, fontFace, fontScale, (255, 0, 0), thickness)
cv2.rectangle(img, org, (org[0] + sizeText[0], org[1]-sizeText[1]), (0, 255, 0), 1)

#TODO : org 좌표에 동그라미 그리기


cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()
--> 

 

### Workshop : 카운트 다운 영상 만들기

 

img = np.full((500, 500, 3), 255, np.uint8)

list = [ '1', '2', '3', '4', '5']

# 일반적인 for 문
for num in list:
    text = num
    fontFace = cv2.FONT_HERSHEY_COMPLEX
    fontScale = 2.0
    thickness = 1
    
    sizeText, _ = cv2.getTextSize(text, fontFace, fontScale, thickness)
    org = (img.shape[1] - sizeText[0])// 2, (img.shape[0] + sizeText[1])//2
    cv2.putText(img, text, org, fontFace, fontScale, (255, 0, 0), thickness)
    
    cv2.circle(img, (0, 0), 200, (0, 0, 255), 3)
    cv2.circle(img, (500, 500), 200, (0, 0, 255), 3)
    cv2.circle(img, (0, 500), 200, (0, 0, 255), 3)
    cv2.circle(img, (500, 0), 200, (0, 0, 255), 3)
    cv2.circle(img, (250, 250), 200, (0, 0, 255), 3)
    cv2.imshow("img", img)
    cv2.waitKey(1000)
    img = np.full((500, 500, 3), 255, np.uint8)


cv2.destroyAllWindows()

--> 5 4 3 2 1 로 카운트 다운한다.


주요 함수와 클래스

다양한 그리기 함수

void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);
영상위에 직선을 그리는 함수
・img  - 입출력 영상
・pt1 - 시작점
・pt2 - 끝점
・color - 선 색상(또는 밝기)
・thickness - 선 두께
・lineType - 선 타입, LINE_4, LNNE_8, LINE_AA 중 하나를 지정합니다.
・shift - 그리기 좌표 값의 축소 비율(오른쪽 비트 시프트(>>)연산)
 LineTypes 열거형 상수
・FILLED(-1) - 내부를 채움(직선 그리기 함수에는 사용 불가)
・LINE_4(4) - 4방향 연결
・LINE_8(8) - 8방향 연결
・LINE_AA(18) - 안티에일리어싱(anti-aliasing)

void arrowedLine(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0, double tipLength=0.1);
영상위에 화살표 형태의 직선을 그리는 함수
・ img  - 입출력 영상
・ pt1 - 시작점
・ pt2 - 끝점
・ color - 선 색상(또는 밝기)
・ thickness - 선 두께
・ lineType - 선 타입, LINE_4, LNNE_8, LINE_AA 중 하나를 지정합니다.
・ shift - 그리기 좌표 값의 축소 비율(오른쪽 비트 시프트(>>)연산)
・ tipLength - 전체 직선 길이에 대한 화살표 길이의 비율

void drawMarker(InputOutputArray img, Point pisition, const Scalar& color, int markerType = MARKER_CROSS, int markerSize=20, int thickness = 1, int line_type = 8);
직선 그리기 함수를 이용하여 다양한 모양의 마커를 그립니다.
・ img  - 입출력 영상
・ pisition - 마커 출력 위치
・ color - 선 색상
・ markerType - 마커 종류. markerType 열거형 상수중 하나를 지정합니다.
・ markerSize - 마커 크기
・ thickness - 선 두께
・ lineType - 선 타입, LINE_4, LNNE_8, LINE_AA 중 하나를 지정합니다.
markerType 열거형 상수
MARKER_CROSS - 십자가 모양(+ 모양)
MARKER_TILTED_CROSS - 45도회전된 십자가 모양(ⅹ 모양)
MARKER_STAR - MARKER_CROSS 모양과 MARKER_TILTED_CROSS모양이 합쳐진 형태
MARKER_DIAMOND - 마름모 모양(◇ 모양)
MARKER_SQUARE - 정사각형 모양(□ 모양)
MARKER_TRIANGLE_UP - 위로 뾰족한 삼각형(△ 모양)
MARKER_TRIANGLE_DOWN - 아래로 뾰족한 삼각형(▽ 모양)

void rectangle(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);
void rectangle(InputOutputArray img, Rect rec, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);
영상에 사각형을 그리는 함수
・ img  - 입출력 영상
・ pt1 -  사각형 꼭지점 좌표, Point 객체
・ pt2 - pt1과 대각 방향에 있는 사각형 꼭지점 좌표, Point 객체
・ rec - 사각형 위치 정보, Rect객체
・ color - 사각형 색상(또는 밝기)
・ thickness - 사각형 외곽선 두께, 이 값이 음수(-1 또는 FILLED)이면 내부를 채웁니다.
・ lineType - 선 타입
・ shift - 그리기 좌표 값의 축소 비율(오른쪽 비트 시브트(>>) 연산)

void circle(InputOutputArray img, Point center, int radius, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);
영상에 원을 그리는 함수
・ img  - 입출력 영상
・ center -  원의 중심
・ radius - 원의 반지름
・ color - 원 색상
・ thickness - 원 외곽선 두께, 이 값이 음수(-1 또는 FILLED)이면 내부를 채웁니다.
・ lineType - 선 타입
・ shift - 그리기 좌표 값의 축소 비율(오른쪽 비트 시브트(>>) 연산)

vodi ellipse(InputOutputArray img, Point center, Size axes, double angle, double starAngle, double endAngle, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);
영상에 타원을 그리는 함수
・ img  - 입출력 영상
・ center -  타원의 중심
・ axes - 타원의 반지름, Size(x축_반지름, y축_반지름)
・ angle - 타원 회전 각도(x축 기준, 시계 방향)
・ starAngle - 타원 호의 시작 각도(x축 기준, 시계 방향)
・ endAngle - 타원 호의 끝 각도(x축 기준, 시계 방향)
・ color - 타원 색상
・ thickness - 타원 외곽선 두께, 이 값이 음수(-1 또는 FILLED)이면 내부를 채웁니다.
・ lineType - 선 타입
・ shift - 그리기 좌표 값의 축소 비율(오른쪽 비트 시브트(>>) 연산)

void polylines(InputOutputArray img, InputArrayOfArrays pts, bool isClosed, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);
영상에 다각형을 그리는 함수
・ img  - 입출력 영상
・ pts -  다각형 외곽 점들의 배열, 주로 vector<Point>타입
・ isClosed - 다각형이 닫혀 있는지를 나타내는 플래그, 이 값이 true이면 다각형의 마지막 꼭지점과 첫 번쨰 꼭지점을 잇는 직선을 추가로 그립니다.
・ color - 선 색상
・ thickness - 선 두께, 이 값이 음수(-1 또는 FILLED)이면 내부를 채웁니다.
・ lineType - 선 타입
・ shift - 그리기 좌표 값의 축소 비율(오른쪽 비트 시브트(>>) 연산)

 

문자열 출력하기

void putText(InputOutputArray img, const String& text, Point org,  int fontFace, double fontScale, Scalar color, int thickness = 1, int lineType = LINE_8, bool bottomLeftOrigin = false);
영상 위에 정해진 폰트로 문자열을 출력하는 함수
・ img  - 입출력 영상
・ text - 출력할 문자열
・ org - 영상에서 문자열을 출력할 위치의 좌측 하단 좌표
・ fontFace - 폰트 종류. cv::HersheyFonts에서 선택
・ fontScale - 폰트 크기 확대/ 축소 비율
・ color - 문자열 색상
・ thickness - 문자열을 그릴 때 사용할 선 두께
・ lineType - 선 타입, LINE_4, LNNE_8, LINE_AA 중 하나를 지정합니다.
・ bottomLeftOrigin - 이 값이 true이면 영상의 좌측 하단을 원점으로 간주합니다.false이면 좌측 상단이 원점입니다.
HersheyFonts 열거형 상수
 FONT_HERSHEY_SIMPLEX - 일반 크기의 산세리프 폰트
 FONT_HERSHEY_PLAIN - 작은 크기의 산세리프 폰트
 FONT_HERSHEY_DUPLEX - 일반 크기의 산세리프 폰트(FONT_HERSHEY_SIMPLEX보다 복잡한 형태)
 FONT_HERSHEY_COMPLEX - 일반 그기의 세리프 폰트
 FONT_HERSHEY_TRIPLEX - 일반 그기의 세리프 폰트(FONT_HERSHEY_COMPLEX보다 복잡한 형태)
 FONT_HERSHEY_COMPLEX_SMALL - FONT_HERSHEY_COMPLEX보다 작은 폰트
 FONT_HERSHEY_SCRIPT_SIMPLEX - 필기체 스타일의 폰트
 FONT_HERSHEY_SCRIPT_COMPLEX - 필기체 스타일의 폰트(FONT_HERSHEY_SCRIPT_SIMPLEX 보다 복잡한 형태)
 FONT_ITALIC - 이탤릭체를 위한플래그

Size getTextSize(const String& text, int fontFace, double fontScale, int thickness, int* baseLine);
문자열 출력을 위해 필요한 사각형 영역 크기를 가늠 할수 있는 함수
・ text - 출력할 문자열
・ fontFace - 폰트 종류
・ fontScale - 폰트 크기 확대/ 축소 비율
・ thickness - 문자열을 그릴 때 사용할 선 두께
・ baseLine - (출력)가장 하단의 텍스트 위치를 기준으로 하는 기준선(baseline)의 y 좌표, 필요 없으면 0 지정
・ 반환값 - 지정한 문자열 출력 시 차지하는 사각형 크기

# 이벤트 처리

### Keyboard Event

img = cv2.imread('./data/lenna.bmp')

if img is None:
    print('Image load failed!')
    sys.exit()

cv2.imshow('img', img)

while True:
    keycode = cv2.waitKey()
    if keycode == ord('i') or keycode == ord("I"): #'i',"I"를 입력했을 경우
        img = ~img
        cv2.imshow("img", img)
    elif keycode == ord('q') or keycode == ord("Q"): #'q',"Q"를 입력했을 경우
        break

cv2.destroyAllWindows()

### Workshop : 키보드 이벤트 처리

img = np.full((512, 512, 3), 255, np.uint8)

x, y = img.shape[0]//2, img.shape[1]//2
width , height = img.shape[1], img.shape[0]

R = 50
direction = 0

while True:
    keycode = cv2.waitKeyEx(50)# 키보드에서 입력키받음 
    if keycode == 0x1B: #ESC키 
        break;
        
    elif key==0x270000: # 방향키 방향 전환 0x270000==right 
        direction=0
    elif key==0x280000: # 방향키 방향 전환 0x280000==down 
        direction=1
    elif key==0x250000: # 방향키 방향 전환 0x250000==left 
        direction=2 
    elif key==0x260000: # 방향키 방향 전환 0x260000==up 
        direction = 3

    if direction == 0:
        x += 10
    elif direction == 1:
        y += 10
    elif direction == 2:
        x -= 10
    elif direction == 3:
        y -=10
        
        
    # 경계처리
    if x < R:
        x = R
        direction = 0
    if x > width - R:
        x = width -R
        direction = 2
    
    if y < R:
        y = R
        direction = 1
    if y > height - R:
        y = height - R
        direction = 3
    
    
    cv2.circle(img, (x, y), R, (0, 0, 255), -1)    
    cv2.imshow('img', img)
    
    img = np.full((512, 512, 3), 255, np.uint8)
    
cv2.destroyAllWindows()

### Mouse Event

def on_mouse(event, x, y, flags, param):
    global old_x, old_y
    if event == cv2.EVENT_LBUTTONDOWN:
        old_x, old_y = x, y
    elif event == cv2.EVENT_LBUTTONUP:
        pass
    elif event == cv2.EVENT_MOUSEMOVE:
        if flags & cv2.EVENT_FLAG_LBUTTON:
            cv2.line(img, (old_x, old_y), (x, y), (0, 255, 255), 2)
            cv2.imshow('img', img)
            old_x, old_y = x, y

img = cv2.imread('./data/lenna.bmp')

if img is None:
    print("Image load failed!")
    sys.exit()

cv2.namedWindow("img")    
cv2.setMouseCallback("img", on_mouse)
    
    
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()

### Workshop : 마우스 이벤트 처리

# 왼쪽 클릭 파란 동그라미 cv2.EVENT_LBUTTONDOWN
# 쉬프트 같이 왼쪽클릭 파란 사각형 cv2.EVENT_FLAGSHIFTKEY
# 오른쪽 클릭 빨간 동그라미 cv2.EVENT_RBUTTONDOWN
# 왼쪽 버튼 더블클릭 모두 삭제 cv2.EVENT_LBUTTONDBLCLK
def on_mouse(event, x, y, flags, param):
    global img
    if event == cv2.EVENT_LBUTTONDOWN:
        if flags & cv2.EVENT_FLAG_SHIFTKEY:
            cv2.rectangle(img,(x-5, y-5), (x+5, y+5),(255,0,0))
        else :
            cv2.circle(img,(x, y), 5,(255,0,0), 3)
    elif event == cv2.EVENT_RBUTTONDOWN:
        cv2.circle(img,(x, y), 5,(0,0,255), 2)
    elif event == cv2.EVENT_LBUTTONDBLCLK:
        param[0] = np.full((512, 512, 3), 255, np.uint8)
        
    cv2.imshow("img", param[0])

img = np.full((512, 512, 3), 255, np.uint8)
cv2.imshow("img", img)


cv2.setMouseCallback("img", on_mouse, [img])
cv2.waitKey()    
cv2.destroyAllWindows()

### Trackbar

def saturated(value):
    if value > 255:
        value = 255
    elif value < 0:
         value = 0
    return value

def on_level_change(pos):
    img[:] = saturated(pos*16)
    cv2.imshow("img", img)


img = np.full((512, 512, 3), 255, np.uint8)

cv2.imshow("img", img)
cv2.createTrackbar('level', 'img', 0, 16, on_level_change)
cv2.waitKey()    
cv2.destroyAllWindows()

### Workshop : 트랙바 이벤트 처리

def onChange(pos):
    global img
    R = cv2.getTrackbarPos('R', 'img')
    G = cv2.getTrackbarPos('G', 'img')
    B = cv2.getTrackbarPos('B', 'img')
    img[:] = (B, G, R)
    cv2.imshow('img', img)

img = np.full((512, 512, 3), 255, np.uint8)
cv2.imshow("img", img)

cv2.createTrackbar('R', 'img', 0, 255, onChange)
cv2.createTrackbar('G', 'img', 0, 255, onChange)
cv2.createTrackbar('B', 'img', 0, 255, onChange)

cv2.waitKey()    
cv2.destroyAllWindows()

주요 함수와 클래스

이벤트 처리

키보드 이벤트 처리

int waitKey(int delay = 0);
프로그램상에서 키 입력을 확인하기 위해 사용한 함수. delay에 해당하는 밀리초 시간 동안 키입력을 기다리다가키  입력이 있으면 아스키 코드값을 반환합니다.
・ delay - 키 입력을 기다릴 시간(밀리초 단위). delay ≤ 0 이면 무한히 기다립니다.
・ 반환값 - 눌러진 키 값. 지정한 시간 동안 키가 눌리지 않았으면 -1을 반환합니다.
특수키 waitKey()반환값 특수키 waitKey()반환값
Insert 0x2d0000 F1 0x700000
Delete 0x2e0000 F2 0x710000
Home 0x240000 F3 0x720000
End 0x230000 F4 0x730000
Page Up 0x210000 F5 0x740000
Page Down 0x220000 F6 0x750000
0x250000 F7 0x760000
0x260000 F8 0x770000
0x270000 F9 0x780000
0x280000 F10 0x790000
    F11 0x7a0000
    F12 0x7b0000
 

 

마우스 이벤트 처리

void setMouseCallback(const String& winname, MouseCallback onMouse, void* userdata = 0);
특정 창에 마우스 콜백 함수를 등록할 때에 사용하는 함수. 창에서 마우스 클릭에 반응하거나 마우스를 드래그 하여 영상에 그림을 그리는 등의 동작을 수행 할 수 있습니다.
・ winname - 마우스 이벤트 처리를 할 창의 이름
・ onMouse - 마우스 이벤트 처리를 위한 콜백 함수 이름
・ userdata - 콜백 함수에 전달할 사용자 데이터의 포인터
MouseEventTypes 열거형 상수
 EVENT_MOUSEMOVE(값 : 0) - 마우스가 창 위에서 움직이는 경우
 EVENT_LBUTTONDOWN(값 : 1) - 마우스 왼쪽 버튼을 누른 경우
 EVENT_RBUTTONDOWN(값 : 2) - 마우스 오른쪽 버튼을 누른 경우
 EVENT_MBUTTONDOWN(값 : 3) - 마우스 가운데 버튼을 누른 경우
 EVENT_LBUTTONUP(값 : 4) - 마우스 왼쪽 버튼을 떼는 경우
 EVENT_RBUTTONUP(값 : 5) - 마우스 오른쪽 버튼을 떼는 경우
 EVENT_MBUTTONUP(값 : 6) - 마우스 가운데 버튼을 떼는 경우
 EVENT_LBUTTONDBLCLK(값 : 7) - 마우스 왼쪽 버튼을 더블클릭하는 경우
 EVENT_RBUTTONDBLCLK(값 : 8) - 마우스 오른쪽 버튼을 더블클릭하는 경우
 EVENT_MBUTTONDBLCLK(값 : 9) - 마우스 가운데 버튼을 더블클릭하는 경우
 EVENT_MOUSEWHEEL(값 : 10) - 마우스 휠을 앞뒤로 돌리는 경우
 EVENT_MOUSEHWHEEL(값 : 11) - 마우스 휠을 좌우로 움직이는 경우
MouseEventFlags 열거형 상수
 EVENT_FLAG_LBUTTON(값 : 1)  - 마우스 왼쪽 버튼이 눌려 있음
 EVENT_FLAG_RBUTTON(값 : 2)  - 마우스 오른쪽버튼이 눌려 있음
 EVENT_FLAG_MBUTTON(값 : 4)  - 마우스 가운데버튼이 눌려 있음
 EVENT_FLAG_CTRLKEY(값 : 8)  - Ctrl키가 눌려 있음
 EVENT_FLAG_SHIFTKEY(값 : 16)  - Shift키가 눌려 있음
 EVENT_FLAG_ALTKEY(값 : 32)  - Alt 키가 눌려 있음

트랙바 이벤트 처리

int createTrackbar(const String& trackbarname, const String& winname, int* value, int count, TrackbarCallback onChange = 0, void* userdata = 0);
트랙바는 슬라이더 컨트롤이라고도 부르며, 영상 출력 창에 부착되어 프로그램 동작 중에 지정된 범위 안의 값을 선택할 수 있다. 트랙바를 생성하려면 createTrackbar()함수를 사용
・ trackbarname - 트랙바 이름
・ winname - 트랙바를 생성할 창 이름
・ value - 트랙바 위치를 받을 정수형 변수의 주소
・ count - 트랙바 최대 위치
・ onChange  - 트랙바 위치가 변경될 때마다 호출되게 만들 콜백 함수 이름(함수의 포인터)
・ userdata  - 트랙바 콜백 함수에 전달할 사용자 데이터의 표인터
・ 반환값 - 정상 동작하면 1을, 실패하면 0을 반환합니다.

int getTrackbarPos(const String & trackbarname, const String& winname);
트랙바를 생성한후 트랙바의 현재 위치를 알수있는 함수
・ trackbarname - 트랙바 이름
・ winname - 트랙바가 부착되어 있는 창 이름
・ 반환값 - 지정한 트랙바 현재 위치

void setTrackbarPos(const String & trackbarname, const String& winname, int pos);
프로그램 동작중 트랙바 위치를 강제로 특정 위치로 옮기고 싶을 경우 사용하는 함수
・ trackbarname - 트랙바 이름
・ winname - 트랙바가 부착되어 있는 창 이름
・ pos - 트랙바를 이동할 위치

데이터 파일 입출력

FileStorage 클래스

virtual bool FileStorage::open(const STring& filename, int flags, const String& encoding = String())
데이터 파일 입출력 기능을 캡슐화 하여 지원하는 클래스
・ filename -  파일 이름
・ flags - 파일 열기 모드
・ encoding - (XML)파일 인코딩 방식
・ 반환값 - 정상적으로 파일을 열면 true,  실패하면 false를 반환합니다.
FileStorage::mode 열거형 상수
FileStorage::READ - 읽기 모드
FileStorage::WRITE - 쓰기 모드(새로 생성)
FileStorage::APPEND - 추가로 쓰기 모드
FileStorage::MEMORY - 논리합 연사자(¦)를 이용하여 FileStorage::READ 또는 FileStorage::WRITE 상수와 함께 사용될 경우, 실제 파일 입출력 대신 메모리 버퍼를 이용한 입출력을 수행합니다.

virtual bool FileStorage::isOpened() const;
데이터 파일 열기를 시도한 후에는 해당 파일이 정상적으로 열렸는지 확인하는 함수
・ 반환값 - 파일이 정상적으로 열려있으면 true, 그렇지 않으면 false를 반환

virtual void FileStorage::release();
사용하고 있던 파일을 닫고 메모리 버퍼를 해제

데이터 파일 저장하기

template<typename _Tp>
static FileStorage& operator << (FileStorage& fs, const _Tp& value);
static FileStorage& operator << (FileStorage& fs, const String& str);
static FileStorage& operator << (FileStorage& fs, const char* str);
FileStorage 클래스 객체에 데이터를 저장할 때 사용하는 << 연산자 재정의 함수
・ fs - FileStorage객체
・ value - 저장할 데이터(백터, 클래스 등)
・ str - 문자열(이름 또는 값)
・ 반환값 - FileStorage 객체의 참조

데이터 파일 불러오기

FileNode FileStorage::operator[](const char* nodename) const;
특정이름으로 저장되어 있는 FileNode 객체에 접근하려면 연산자 재정의 함수 사용
・ fs - 노드 이름
・ 반환값 - FileNode 객체

template<typename _Tp>
static void operator >> (const FileNode& n, _Tp& value);
template<typename _Tp>
static void operator >> (const FileNode& n, std::vector<_Tp>& vec);
FileNode 객체를 얻어 온 후에는 FileNode 클래스의  >> 연산자 재정의 함수를 이용하여 노드엥 저장된 데이 값을 받아 올수 있다.
・ n - FileNode 객체
・ value 받아올 데이터 형식에 맞는 변수 이름
・ vec - STL vector 형식으로 지정된 데이터를 블러올 때 사용합니다.

 

반응형