Search
Duplicate

OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝/ OpenCV 주요 기능

(각 함수의 상세한 파라미터에 대해서는 이전의 <OpenCV로 배우는 영상처리 및 응용>에서 정리하였으므로 생략)

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

VideoCapture 클래스

동영상이란 일련의 정지 영상을 압축하여 파일로 저장한 형태
이때 동영상에 저장되어 있는 정지 영상을 프레임(frame)이라고 함.
동영상을 처리하는 작업은 동영상에서 프레임을 추출한 후, 각각의 프레임에 영상 처리 기법을 적용하는 형태로 이루어짐.
OpenCV에서는 VideoCapture라는 클래스를 이용하여 카메라 또는 동영상 파일로부터 정지 영상 프레임을 받아올 수 있음.
VideoCapture 클래스에서 동영상 파일을 불러오려면 처음 VideoCapture 객체를 생성할 때 동영상 파일 이름을 지정하거나 기본 생성자로 VideoCpature 객체를 생성한 후 VideoCapture::open() 멤버 함수를 호출해야 함.
하나의 동영상 파일 대신 일련의 숫자로 구분되는 이름의 정지 영상 파일을 가지고 있고, 이 파일을 불러오고 싶을 때에도 VideoCapture 클래스를 이용할 수 있음.
예컨대 img0001.jpg, img0002.jpg, img0003.jpg 라는 파일이 있을 때 filename 인자에 ‘img%04d.jpg”라고 입력하면 일련의 영상 파일을 차례로 불러올 수 있음.
또한 filename 인자에 ‘protocol://host:port/script_name?script_params|auth’ 형태의 비디오 스트림 URL을 지정하여 인터넷 동영상을 사용할 수도 있음.
apiPreference 인자에는 아래 표와 같은 VideoCaptureAPIs 열거형 상수 중 하나를 사용하여 동영상 파일을 불러오는 방법을 지정할 수 있음.
대부분의 경우 apiPreference 인자를 생략하거나 기본값인 CAP_ANY를 지정하는데, 이 경우 시스템이 알아서 적절한 방법을 선택하여 사용 함.
Search
열거형 상수
설명
CAP_V4L, CAP_V4L2
Open
V4L/V4L2(리눅스)
CAP_FIREWIRE, CAP_IEEE1394
Open
IEEE 1394 드라이버
CAP_DSHOW
Open
다이렉트쇼(DirectShow)
CAP_PVAPI
Open
PvAPI, Prosilica GigE SDK
CAP_OPENNI
Open
OpenNI
CAP_MSMF
Open
마이크로소프트 미디어 파운데이션
CAP_GSTREAMER
Open
GStreamer
CAP_FFMPEG
Open
FFMPEG 라이브러리
CAP_IMAGES
Open
OpenCV에서 지원하는 일련의 영상 파일
CAP_OPENCV_MJPEG
Open
OpenCV에 내장된 MotionJPEG 코덱
컴퓨터에 연결된 카메라 장치를 열 때에도 VideoCapture 생성자 혹은 VideoCapture::open() 함수를 이용하는데, 이때 함수의 인자에 문자열이 아닌 정수 값을 전달 함.
카메라 장치를 사용하려 할 때 VideoCapture 클래스의 생성자 혹은 VideoCapture::open() 함수에 전달하는 정수 값 index는 다음과 같은 형태로 구성됨
index = camera_id + domain_offset_id
C++
만일 컴퓨터에 한 대의 카메라만 연결되어 있다면 이 카메라의 camera_id는 0이 된다.
만일 두 대 이상의 카메라가 연결되어 있다면 각각의 카메라는 0보다 같거나 큰 정수를 ID로 갖는다.
domain_offset_id는 카메라 장치를 사용하는 방식을 표현하는 정수 값이며 VideoCaptureAPIs 열거형 상수 중 하나를 지정한다.
대부분의 경우 domain_offset_id는 자동 선택을 의미하는 0(CAP_ANY)을 사용하기 때문에 index 값은 결국 camera_id와 같은 값으로 설정한다.
카메라 또는 동영상 파일 열기를 수행한 후에는 VideoCapture::isOpened() 함수를 이용하여 열기 작업이 성공적으로 수행되었는지를 확인하는 것이 좋다.
카메라 장치 또는 동영상 파일의 사용이 끝나면 VideoCapture::release()를 호출하여 사용하던 자원을 해제해야 한다.
참고로 VideoCapture 클래스의 소멸자에도 VideoCapture::release() 함수와 마찬가지로 사용하고 있던 자원을 모두 해제하는 코드가 들어가 있어서 VideoCapture 객체가 소멸할 때 자동으로 열려 있던 카메라 장치 또는 동영상 파일이 닫히게 된다.
VideoCapture 클래스를 이용하여 카메라 또는 동영상 파일을 정상적으로 열었다면 그 후에 공통의 멤버 함수를 사용하여 프레임을 받아올 수 있다.
VideoCapture 클래스에서 한 프레임을 받아 오기 위해서는 VideoCapture::operator >>() 연산자 재정의 함수 또는 VideoCapture::read() 함수를 사용한다.
>> 연산자 재정의와 VideoCapture::read() 함수는 모두 카메라 또는 동영상 파일로부터 다음 프레임을 받아 와서 Mat 클래스 형식의 변수 image에 저장한다.
사실 >> 연산자 재정의는 함수 내부에 명시적으로 VideoCapture::read() 함수를 호출하는 형태로 구성되어 있기 때문에 그 둘은 완전히 같다.
VideoCapture cap(0); Mat frame1, frame2; cap >> frame1; // 1st frame cap.read(frame2); // 2nd frame
C++
현재 열려 있는 카메라 장치 또는 동영상 파일로부터 여러 정보를 받아 오기 위해서는 VideoCapture::get() 함수를 사용한다.
VideoCapture::get() 함수는 인자로 지정한 속성 ID(propID)에 해당하는 속성 값을 반환한다.
VideoCapture::get() 함수의 인자로 지정할 수 있는 속성 ID는 VideoCaptureProperties 열거형 상수 중 하나를 지정할 수 있으며, 자주 사용되는 상수를 아래 표에 정리.
VideoCapture::get() 함수는 속성을 double 타입으로 반환한다.
Search
VideoCaptureProperties 열거형 상수
설명
CAP_PROP_POS_MSEC
Open
비디오 파일에서 현재 위치(밀리초 단위)
CAP_PROP_POS_FRAMES
Open
현재 프레임 위치 (0-기반)
CAP_PROP_POS_AVI_RATIO
Open
[0, 1] 구간으로 표현한 동영상 프레임의 상대적 위치(0: 시작, 1: 끝)
CAP_PROP_FRAME_WIDTH
Open
비디오 프레임의 가로 크기
CAP_PROP_FRAME_HEIGHT
Open
비디오 프레임의 세로 크기
CAP_PROP_FPS
Open
초당 프레임 수
CAP_PROP_FOURCC
Open
fourcc 코드(코덱을 표현하는 정수 값)
CAP_PROP_FRAME_COUNT
Open
비디오 파일의 전체 프레임 수
CAP_PROP_BRIGHTNESS
Open
(카메라에서 지원하는 경우) 밝기 조절
CAP_PROP_CONTRAST
Open
(카메라에서 지원하는 경우)  명암비 조절
CAP_PROP_SATURATION
Open
(카메라에서 지원하는 경우) 채도 조절
CAP_PROP_HUE
Open
(카메라에서 지원하는 경우) 색상 조절
CAP_PROP_GAIN
Open
(카메라에서 지원하는 경우) 감도 조절
CAP_PROP_EXPOSURE
Open
(카메라에서 지원하는 경우) 노출 조절
CAP_PROP_ZOOM
Open
(카메라에서 지원하는 경우) 줌 조절
CAP_PROP_FOCUS
Open
(카메라에서 지원하는 경우) 초점 조절
VideoCapture cap(0); int w = cvRound(cap.get(CAP_PROP_FRAME_WIDTH)); int h = cvRound(cap.get(CAP_PROP_FRAME_HEIGHT));
C++
VideoCapture::get() 함수와 반대로 현재 열려 있는 카메라 또는 비디오 파일 재생과 관련된 속성 값을 설정할 때는 VideoCapture::set() 함수를 사용한다.
VideoCapture::set() 함수의 속성 ID도 위의 표에 정리한 VideoCaptureProperties 열거형 상수를 지정한다.
만일 video.mp4 파일을 열어서 100번째 프레임으로 이동하려면 다음과 같은 코드를 작성하면 된다.
VideoCapture cap("video.mp4"); cap.set(CAP_PROP_POS_FRAMES, 100);
C++

카메라 입력 처리하기

(앞서 나온 내용을 이용한 예제 코드와 설명이라 생략)

동영상 파일 처리하기

(앞서 나온 내용을 이용한 예제 코드와 설명이라 생략)

동영상 파일 저장하기

(앞서 나온 내용을 이용한 예제 코드와 설명이라 생략)

다양한 그리기 함수

직선 그리기

line()은 영상 위에 직선을 그리는 함수
영상 위에 pt1 좌표부터 pt2 좌표까지 직선을 그린다.
이때 선의 색상, 밝기는 color로 지정할 수 있고, thickness를 이용하여 두께를 지정할 수 있다.
lineType인자는 그리는 방식을 지정할 수 있는데, LineTypes 열거형 상수 중 하나를 지정할 수 있다.
Search
LineTypes
설명
FILLED
Open
-1
내부를 채움(직선 그리기 함수에는 사용 불가)
LINE_4
Open
4
4방향 연결
LINE_8
Open
8
8방향 연결
LINE_AA
Open
18
안티에일리어싱
화살표 형태의 직선을 그려야 하는 경우에는 arrowedLine()을 이용하면 된다.
arrowedLine() 함수는 영상 위에 pt1 좌표부터 pt2 좌표까지 직선을 그리고 끝점인 pt2에 화살표 모양의 직선 두 개를 추가로 그린다.
이때 화살표 모양의 직선 길이는 arrowedLine() 함수의 마지막 인자인 tipLength를 이용하여 조절할 수 있다.
drawMarker()는 직선 그리기 함수를 이용하여 다양한 모양의 마커를 그린다.
drawMarker() 함수는 img 영상의 position 좌표에 color 색상을 이용하여 마커를 그리는데, 마커의 종류는 markerType 인자로 지정할 수 있다. 기본값으로는 십자가 모양의 MARKER_CROSS 가 지정되어 있다.
Search
MarkerTypes
설명
MARKER_CROSS
Open
십자가 모양 (+)
MARKER_TILTED_CROSS
Open
45도 회전된 십자가 모양 (x)
MARKER_STAR
Open
별 모양 (*)
MARKER_DIAMOND
Open
마름모 모양
MARKER_SQUARE
Open
정사각형 모양
MARKER_TRIANGLE_UP
Open
위로 뾰족한 삼각형
MARKER_TRIANGLE_DOWN
Open
아래로 뾰족한 삼각형

도형 그리기

rectangle()은 사각형을 그리는 함수
rectangle(0 함수 인자 중 thickness는 도형 외곽선의 두께를 지정하는데, 만일 thickness에 -1 을 지정하거나 FILLED 열거형 상수를 지정하면 내부를 채운 사각형을 그린다.
circle()은 원을 그리는 함수
원을 그리기 위해서는 원의 중심점 좌표와 반지름을 지정해야 한다.
ellipse()는 타원을 그리는 함수. 타원을 그리는 방식은 원을 그리는 방식보다 복잡하다.
ellipse() 함수는 다양한 형태의 타원 또는 타원의 일부인 호를 그릴 수 있다.
타원의 크기는 axes 인자를 통해 지정하는데, axes 인자는 size 자료형을 사용하며, x축 방향 타원과 반지름과 y축 방향 반지름을 지정한다.
angle에 0이 아닌 값을 전달하면 회전된 타원을 그릴 수 있다.
startAngle과 endAngle 인자를 적절하게 이용하면 호를 그리는 용도로도 사용할 수 있다.
예컨대 startAngle에 0을 지정하고 endAngle에 360을 지정하면 완전한 타원을 그리지만 startAngle에 0을 지정하고 endAngle에 180을 지정하면 타원에 반에 해당하는 호를 그린다.
thickness는 타원 외곽선 두께를 나타내는데, -1 또는 FILLED를 지정하면 내부를 채운 타원이나 호를 그린다.
polylines() 함수는 임의의 다각형을 그리는 함수
polylines()에는 다각형의 꼭지점 좌표를 전달해야 하며, 꼭지점 좌표는 vector<Point> 자료형에 저장하여 전달한다.

문자열 출력하기

영상 위에 정해진 폰트로 문자열을 출력하려면 putText() 함수를 이용하면 된다.
putText() 함수는 img 영상의 org 위치에 text로 지정된 문자열을 출력한다.
이때 사용할 폰트는 fontFace 인자로 지정할 수 있고, faceScale 인자를 이용하여 폰트 크기를 조절할 수 있다.
fontFace 인자에는 HersheyFonts 열거형 상수 값을 지정할 수 있다. HersheyFonts 열거형 중 FONT_ITALIC 상수는 논리합 연산자(|)를 이용하여 다른 상수와 함께 사용한다.
Search
HersheyFonts
설명
FONT_HERSHEY_SIMPLEX
Open
일반 크기의 산세리프 폰트
FONT_HERSHEY_PLAIN
Open
작은 크기의 산세리프 폰트
FONT_HERSHEY_DUPLEX
Open
일반 크기의 산세리프 폰트 (FONT_HERSHEY_SIMPLEX 보다 복잡)
FONT_HERSHEY_COMPLEX
Open
일반 크기의 세리프 폰트
FONT_HERSHEY_TRIPLEX
Open
일반 크기의 세리프 폰트 (FONT_HERSHEY_COMPLEX보다 복잡)
FONT_HERSHEY_COMPLEX_SMALL
Open
FONT_HERSHEY_COMPLEX 보다 작은 폰트
FONT_HERSHEY_SCRIPT_SIMPLEX
Open
필기체 스타일의 폰트
FONT_HERSHEY_SCRIPT_COMPLEX
Open
필기체 스타일의 폰트(FONT_HERSHEY_SCRIPT_SIMPLEX 보다 복잡한 형태)
FONT_ITALIC
Open
이탤릭체를 위한 플래그
OpenCV는 문자열 출력을 위해 필요한 사각형 영역 크기를 가늠할 수 있는 getTextSize() 함수를 제공하는데, 이 함수를 잘 이용하면 문자열이 한쪼긍로 치우치지 않고 적당한 위치에 출력되도록 설정할 수 있다.
putText(0 함수를 이용하여 특정 위치 좌표에 문자열을 출력하면, 보통 문자열 길이와 크기에 따라 문자열이 차지하는 영역 크기가 달라지기 때문에 문자열이 한쪽에 치우쳐서 나타날 수 있다. 그러나 getTextSize() 함수가 반환하는 문자열 영역 크기 정보를 이용하면 문자열 출력 위치를 적절하게 조절할 수 있다.
Mat img(200, 640, CV_8UC3, Scalar(255, 255, 255)); const String text = "Hello, OpenCV"; int fontFace = FONT_HERSHEY_TRIPLEX; double fontScale = 2.0; int thickness = 1; Size sizeText = getTextSize(text, fontFace, fontScale, thickness, 0); Size sizeImg = img.size(); // 텍스트의 크기를 이용해서 적절한 위치를 계산 Point org((sizeImg.width - sizeText.width) / 2, (sizeImg.Height + sizeText.height) / 2); putText(img, text, org, fontFace, fontScale, Scalar(255, 0, 0), thickness);
C++

이벤트 처리

키보드 이벤트 처리

waitKey() 함수는 키보드 입력을 처리하는 OpenCV의 기본 함수
waitKey() 함수는 delay에 해당하는 밀리초 시간 동안 키 입력을 기다리다가 키 입력이 있으면 해당 키의 아스키 코드(ASCII code) 값을 반환한다. 만일 지정 시간 동안 키 입력이 없었으면 -1을 반환한다.
Window 운영체제에서 waitKey()는 일반적인 키보드 입력은 처리할 수 있지만, 함수키(F1, F2 등) 또는 화살표키 등 특수키 입력은 처리하지 못한다. 만일 키보드의 특수 키에 대한 처리를 하고 싶다면 waitKey() 대신 waitKeyEx()를 사용하면 된다.

마우스 이벤트 처리

OpenCV 에서 마우스 이벤트를 처리하려면 먼저 마우스 콜백 함수를 등록하고, 이후 마우스 콜백 함수에 마우스 이벤트를 처리하는 코드를 추가해야 한다.
OpenCv에서 특정 창에 마우스 콜백 함수를 등록할 때는 setMouseCallback() 함수를 사용한다.
setMouseCallback() 함수는 winname 창에서 마우스 이벤트가 발생하면 onMouse로 등록된 콜백 함수가 자동으로 호출되도록 설정한다.
userdata 인자에는 사용자가 마우스 콜백 함수에 전달하고 싶은 데이터를 void* 형식으로 전달할 수 있다.
마우스 콜백 함수는 다음과 같이 정의되어 있다.
typedef void (*MouseCallback)(int event, int x, int y, int flags, void* userdata);
C++
마우스 콜백함수의 event 인자에는 MouseEventTypes로 정의된 열거형 상수가 전달된다.
Search
MouseEventTypes
설명
EVENT_MOUSEMOVE
Open
0
마우스가 창 위에서 움직임
EVENT_LBUTTONDOWN
Open
1
마우스 왼쪽 버튼 누름
EVENT_RBUTTONDOWN
Open
2
마우스 오른쪽 버튼 누름
EVENT_MBUTTONDOWN
Open
3
마우스 가운데 버튼 누름
EVENT_LBUTTONUP
Open
4
마우스 왼쪽 버튼 뗌
EVENT_RBUTTONUP
Open
5
마우스 오른쪽 버튼 뗌
EVENT_MBUTTONUP
Open
6
마우스 가운데 버튼 뗌
EVENT_LBUTTONDCLICK
Open
7
마우스 왼쪽 버튼 더블 클릭
EVENT_RBUTTONDCLICK
Open
8
마우스 오른쪽 버튼 더블 클릭
EVENT_MBUTTONDCLICK
Open
9
마우스 가운데 버튼 더블 클릭
EVENT_MOUSEWHEEL
Open
10
마우스 휠을 앞으로 돌림
EVENT_MOUSEHWHEEL
Open
11
마우스 휠을 좌우로 돌림
마우스 콜백함수의 flags 인자에는 MouseEventFlags 열거형 상수의 논리합이 전달된다.
Search
MouseEventFlags
설명
EVENT_FLAG_LBUTTON
Open
1
마우스 왼쪽 버튼이 눌려 있음
EVENT_FLAG_RBUTTON
Open
2
마우스 오른쪽 버튼이 눌려 있음
EVENT_FLAG_MBUTTON
Open
4
마우스 가운데 버튼이 눌려 있음
EVENT_FLAG_CTRLKEY
Open
8
ctrl 키가 눌려있음
EVENT_FLAG_SHIFTKEY
Open
16
shift 키가 눌려있음
EVENT_FLAG_ALTKEY
Open
32
alt 키가 눌려있음

트랙바 사용하기

OpenCV에는 Window, Linux, Mac OS에서 공통으로 사용할 수 있는 트랙바(trackbar)라는 인터페이스를 제공함.
트랙바는 슬라이더 컨트롤(slider control)이라고도 부르며, 영상 출력 창에 부착되어 프로그램 동작 중에 사용자가 지정된 범위 안의 값을 선택할 수 있음.
트랙바는 사용자가 지정한 영상 출력 창의 상단에 부착되며, 필요한 경우 창 하나에 여러 개의 트랙바를 생성할 수 있음. 각각의 트랙바에는 고유한 이름을 지정해야 하며, 이 이름은 트랙바 왼쪽에 나타남.
트랙바 위치는 사용자가 마우스를 이용하여 이동시킬 수 있고, 트랙바의 현재 위치는 트랙바 이름 옆에 함께 표시 됨.
OpenCV에서 트랙바를 생성하려면 createTrackbar() 함수를 이용하면 된다.
createTrackbar(0 함수는 winname 이름의 창에 trackbarname 이름의 트랙바를 부착하고, 트랙바가 움직일 때마다 onChange에 해당하는 트랙바 콜백 함수가 호출되도록 설정함.
사용자가 트랙바 콜백 함수에 전다랗고 싶은 데이터가 있다면 userdata 인자를 통해 void* 형식으로 전달할 수 있음.
onChange에 지정하는 트랙바 콜백 함수는 트랙바 위치가 변경될 때 자동으로 호출되는 함수로 다음과 같이 정의되어 있음.
typedef void (*TrackbarCallback)(int pos, void* userdata);
C++
트랙바 콜백 함수의 첫 번째 인자에는 현재 트랙바의 위치 정보가 전달되고, 두 번째 인자에는 createTrackbar() 함수에서 지정한 사용자 데이터 포인터 값이 전달 됨.
트랙바를 생성한 후 트랙바의 현재 위치를 알고 싶다면 getTrackbarPos() 함수를 사용하면 된다.
프로그램 동작 중에 트랙바 위치를 강제로 옮기고 싶다면 setTrackbarPos()를 사용하면 된다.

OpenCV 데이터 파일 입출력

OpenCV에서 제공하는 FileStorage 클래스는 Mat 클래스 객체 뿐만 아니라 일반적인 C/C++ 자료형 데이터를 XML, YAML, JSON 등 파일 형식으로 저장하는 기능을 제공한다.

FileStorage 클래스

OpenCV에서 데이터 파일 입출력은 FileStorage가 담당하는데, FileStorage 클래스는 데이터의 파일 입출력 기능을 캡슐화하여 지원하는 클래스이다.
FileStorage 클래스를 이용하여 OpenCV 데이터를 저장하거나 읽어오려면 먼저 FileStorage 클래스를 생성한 후 FileStorage::open() 함수를 이용하여 실제 사용할 파일을 열어야 한다.
FileStorage::open() 함수의 첫 번째 인자 filename에는 데이터 파일 이름을 지정하는데, FileStorage 클래스는 XML, YAML, JSON 형식의 파일 입출력을 지원하며, 사용할 파일 형식은 filename의 확장자에 의해 자동으로 결정된다.
만약 파일 이름 뒤에 .gz를 추가하면 데이터 파일을 압축하여 저장한다. 예컨대 filename을 “mydata.xml.gz”로 설정하면 XML 파일 형식으로 데이터를 저장한 후 gzip 형식으로 압축한다.
두 번째 인자 flags는 파일 열기 모드를 결정하는데, FileStorage::mode 열거형 상수를 지정할 수 있다.
Search
FileStorage::mode 열거형 상수
설명
FileStorage::READ
Open
읽기 모드
FileStorage::WRITE
Open
쓰기 모드 (새로 생성)
FileStorage::APPEND
Open
추가로 쓰기 모드
FileStorage::MEMORY
Open
논리합 연산자(|)를 이용하여 FileStorage::READ 또는 FileStorage::WRITE 상수와 함께 사용될 경우, 실제 파일 입출력 대신 메모리 버퍼를 이용한 입출력을 수행함
FileStorage::open() 이후 파일이 정상적으로 열렸는지 확인하는 함수는 FileStorage::isOpened()이다.
일반적으로 FileStorage 클래스를 이용하여 파일에 데이터를 저장할 때는 << 연산자 재정의 함수를 사용하고, 파일로부터 데이터를 읽어올 때는 >> 연산자 재정의 함수를 사용한다.
FileStorage 객체를 이용하여 파일 입출력 작업이 완료되면 FileStorage::release() 함수를 호출해서 객체를 해제해야 한다.

데이터 파일 저장하기

예제 코드
String name = "Jane"; int age = 10; Point pt1(100, 200); vector<int> scores = { 80, 90, 50 }; Mat mat1 = (Mat_<float>(2, 2) << 1.0f, 1.5f, 2.0f, 3.2f); FileStorage fs("mydata.json", FileStorage::WRITE); if (!fs.isOpened()) { cerr << "File open failed!" << endl; return; } fs << "name" << name; fs << "age" << age; fs << "point" << pt1; fs << "scores" << scores; fs << "data" << mat1; fs.release();
C++

데이터 파일 불러오기

예제 코드
String name; int age; Point pt1; vector<int> scores; Mat mat1; FileStorage fs("mydata.json", FileStorage::READ); if (!fs.isOpened()) { cerr << "File open failed!" << endl; return; } fs["name"] >> name; fs["age"] >> age; fs["point"] >> pt1; fs["scores"] >> scores; fs["data"] >> mat1; fs.release();
C++

유용한 OpenCV 기능

마스크 연산

OpenCV에서는 임의의 모양을 갖는 ROI를 설정하기 위하여 일부 행렬 연산 함수에 대하여 마스크 연산을 지원한다.
마스크 연산을 지원하는 OpenCV 함수는 보통 입력 영상과 크기가 같고 깊이가 CV_8U인 마스크 영상을 함께 인자로 전달 받는다.
마스크 영상이 주어질 경우, 마스크 영상의 픽셀값이 0이 아닌 좌표에 대해서만 연산이 수행된다.
일반적으로 마스크 영상은 사람의 눈으로도 구분이 쉽도록 픽셀 값이 0 또는 255로 구성된 흑백 영상이 사용된다.
Mat::setTo() 함수는 마스크 연산을 지원하는 함수로 함수의 두 번째 인자 mask에 마스크 영상을 지정할 수 있다.
기본값으로 설정되어 있는 noArray()를 mask 인자로 지정하면 입력 행렬의 모든 원소 값을 value 값으로 설정하고 적절한 마스크 영상을 mask 인자로 지정하면 특정 영역에 대해서만 픽셀 값을 설정할 수 있다. 이때 마스크 영상은 Mat::setTo()를 호출하는 대상 행렬과 크기가 같아야 한다.
Mat src = imread("lenna.bmp", IMREAD_COLOR); Mat mask = imread("mask_smile.bmp", IMREAD_GRAYSCALE); if (src.empty() || mask.empty()) { cerr << "Image load failed!" << endl; return; } src.setTo(Scalar(0, 255, 255), mask);
C++
마스크 연산을 지원하는 또 다른 함수로 Mat::copyTo() 라는 함수가 있다.
마스크 연산을 지원하는 Mat::copyTo() 함수는 mask 영상의 픽셀 값이 0이 아닌 위치에서만 *this 행렬 원소 값을 행렬 m으로 복사한다.
만약 Mat::copyTo() 함수를 호출하는 *this 행렬과 인자로 전달된 m 행렬이 서로 크기 또는 타입이 같지 않을 경우, Mat::copyTo() 함수 내부에서 m.create() 함수를 호출하여 대상 영상 m을 새롭게 생성한 후 마스크 영상을 고려하여 픽셀 값을 복사한다.
만약 *this 행렬과 m 행렬이 서로 크기와 타입이 같다면 m 행렬 원소 값을 그대로 유지한 상태에서 *this 행렬의 픽셀 값을 복사한다.
Mat src = imread("airplane.bmp", IMREAD_COLOR); Mat mask = imread("mask_plane.bmp", IMREAD_GRAYSCALE); Mat dst = imread("field.bmp", IMREAD_COLOR); if (src.empty() || mask.empty()) { cerr << "Image load failed!" << endl; return; } src.copyTo(dst, mask);
C++

연산 시간 측정

OpenCV 라이브러리는 정밀한 시간 측정 방법을 제공한다. 본래 특정 프로그램의 동작 시간을 측정하는 C/C++ 소스 코드 작성 방법은 운ㄷ영 체제마다 각기 다르지만 OpenCV 라이브러리를 이용하면 운영 체제에 상관 없이 통일된 인터페이스 함수를 사용하여 연산 시간을 측정할 수 있다.
OpenCV에서는 getTickCount() 함수와 getTickFrequency() 함수를 사용하여 특정 연산의 수행 시간을 측정한다.
getTickCount() 함수는 컴퓨터 시스템의 특정 시점부터 현재까지 발생한 틱(tick) 횟수를 반환한다. 여기서 틱 횟수는 컴퓨터 시스템에서 발생하는 클럭처럼 매우 빠르게 증가하는 성능 측정 계수를 의미하며, 컴퓨터의 성능에 따라 빠르게 증가할 수도 있고, 느리게 증가할 수도 있다.
틱 횟수 차이 값은 사용하고 있는 컴퓨터의 시스템 성능에 따라 다르게 측정되므로 실제 연산 시간을 알아내기 위해서는 틱 횟수 차이를 시스템의 틱 주파수(tick frequency)로 나누는 작업이 동반되어야 한다.
틱 주파수란 1초 동안 발생하는 틱 횟수를 의미하며 getTickFrequency()를 이용하여 시스템의 틱 주파수를 구할 수 있다.
int64 t1 = getTickCount(); my_func(); // do something int64 t2 = getTickCount(); double ms = (t2 - t1) * 1000 / getTickFrequency();
C++
getTickCount()와 getTickFrequency() 를 조합하는 것이 번거롭기 때문에 OpenCV 3.2.0 버전부터 연산 시간 측정을 위한 TickMeter 라는 이름의 클래스를 새롭게 제공한다.
사용법은 아래와 같다.
TickMeter tm; tm.start(); my_func(); // do something tm.stop(); double ms = tm.getTimeMilli();
C++

유용한 OpenCV 함수 사용법

sum() 함수와 mean() 함수

OpenCV에서 Mat 행렬의 원소 합을 구하고 싶을 때는 sum() 함수를 사용하고, 평균을 구하고 싶을 때는 mean() 함수를 사용한다.
이 두 함수는 4채널 이하의 행렬에 대해서만 동작하며, 합과 평균을 Scalar 타입으로 반환한다.
mean() 함수는 마스크 연산을 지원하므로 필요한 경우 mask 영상을 지정하여 특정 영역의 원소 평균을 구할 수도 있다.
Mat img = imread("lenna.bmp", IMREAD_GRAYSCALE); int sumVal = (int)sum(img)[0]; int meanVal = (int)mean(img)[0];
C++

minMaxLoc() 함수

minMaxLoc() 함수는 행렬 또는 영상에서 최솟값, 최댓값, 그리고 최솟값과 최댓값의 위치를 찾을 때 사용한다.
minMaxLoc() 함수는 마스크 연산을 지원하므로 행렬 일부 영역에서의 최솟값, 최댓값과 그 위치를 구할 수 있다.
double minVal, maxVal; Point minPos, maxPos; minMaxLoc(img, &minVal, &maxVal, &minPos, &maxPos);
C++

normalize() 함수

행렬의 노름(norm) 값을 정규화하거나 원소 값 범위를 특정 범위로 정규화할 때 normalize() 함수를 사용한다.
normalize() 함수는 norm_type 인자에 따라 동작이 결정된다.
norm_type이 NORM_INF, NORM_L1, NORM_L2인 경우에는 dstLp=alpha(p=Inf,1,2)\|dst\|_{L_{p}} = alpha(p = Inf, 1, 2) 수식을 만족하도록 입력 행렬 원소 값의 크기를 조정한다.
dstL=maxidsti=alpha\|dst\|_{L_{\infty}} = max_{i} |dst_{i}| = alpha
dstL1=idsti=alpha\|dst\|_{L_{1}} = \sum_{i} |dst_{i}| = alpha
dstL2=idsti2=alpha\|dst\|_{L_{2}} = \sqrt{\sum_{i} dst_{i}^{2}} = alpha
만약 norm_type 인자가 NORM_MINMAX인 경우에는 src 행렬의 최솟값이 alpha, 최댓값이 beta가 되도록 모든 원소 값 크기를 조절한다.
많은 OpenCV 예제 코드에서 NORM_MINMAX 타입으로 normalize() 함수를 사용하고 있으며, 특히 실수로 구성된 행렬을 그레이스케일 영상 형태로 변환하고자 할 때 normalize() 함수를 사용하면 유용하다.
Mat src = Mat_<float>({1, 5}, {-1.f, -0.5f, 0.f, 0.5f, 1.f}); Mat dst; normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
C++

cvRound() 함수

OpenCV에서 실수 갑의 반올림 연산을 위해 cvRound() 함수를 제공한다.
이와 더불어 실수의 올림을 수행할 때는 cvCeil() 함수를 사용하고, 내림을 수행할 때는 cvFloor() 함수를 사용한다.