pi92 2021. 9. 6. 16:18

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

 

OpenCV에서는 카메라 또는 동영상 파일로부터 정지 영상 프레임을 받아 올 때 VideoCapture 클래스를 이용합니다. VideoCapture 클래스의 정의와 다양한 멤버 함수 사용법에 대해 알아보고, 실제로 카메라와 동영상 파일을 재생하는 소스 코드 작성 방법에 대해 알아보겠습니다. 또한 여러 장의 정지 영상을 동영상 파일로 저장할 때 사용할 수 있는 VideoWriter 클래스에 대해서도 소개합니다.

 

4.1.1 VideoCapture 클래스

동영상이란 일련의 정지 영상을 압축하여 파일로 저장한 형태입니다. 이때 동영상에 저장되어 있는 일련의 정지 영상을 프레임(frame)이라고 합니다. OpenCV에서는 VideoCapture라는 하나의 클래스를 이용하여 카메라 또는 동영상 파일로부터 정지 영상 프레임을 받아 올 수 있습니다. 간략화한 VideoCapture 클래스 정의를 코드 4-1에 나타냈습니다. 참고로 VideoCapture 클래스의 멤버 변수는 모두 protected: 모드로 선언되어 있어서 사용자가 직접 접근할 수 없으며, 코드 4-1에는 표시를 생략했습니다.


먼저 VideoCapture 클래스를 사용하여 동영상 파일을 불러오는 기능에 대해 알아보겠습니다. VideoCapture 클래스에서 동영상 파일을 불러오려면 처음 VideoCapture 객체를 생성할 때 생성자에 동영상 파일 이름을 지정하거나 또는 기본 생성자로 VideoCapture 객체를 생성한 후 VideoCapture::open() 멤버 함수를 호출해야 합니다. 이때 사용하는 VideoCapture 생성자와 VideoCapture::open() 멤버 함수 원형은 다음과 같습니다.

카메라 장치를 열 때에도 VideoCapture 생성자 혹은 VideoCapture::open() 멤버 함수를 사용하는데, 이때는 함수의 인자에 문자열이 아니라 정수 값을 전달합니다. 다음에 나타낸 VideoCapture 생성자와 VideoCapture::open() 멤버 함수는 카메라 장치를 열 때 사용합니다.

 

 

카메라 장치를 사용하려고 할 때 VideoCapture 클래스의 생성자 혹은 VideoCapture::open() 함수에 전달하는 정수 값 index는 다음과 같은 형태로 구성됩니다.

 

index = camera_id + domain_offset_id 

 

만약 컴퓨터에 한 대의 카메라만 연결되어 있다면 이 카메라의 camera_id 값은 0입니다. 두 대 이상의 카메라가 연결되어 있다면 각각의 카메라는 0보다 같거나 큰 정수를 ID로 갖습니다.

 

카메라 또는 동영상 파일 열기를 수행한 후에는 VideoCapture::isOpened() 멤버 함수를 이용하여 열기 작업이 성공적으로 수행되었는지 확인하는 것이 좋습니다.

 

 

카메라 장치 또는 동영상 파일의 사용이 끝나면 VideoCapture::release() 함수를 호출하여 사용하던 자원을 해제해야 합니다. 참고로 VideoCapture 클래스의 소멸자에도 VideoCapture::release() 함수와 마찬가지로 사용하고 있던 자원을 모두 해제하는 코드가 들어가 있어서 VideoCapture 객체가 소멸할 때 자동으로 열려 있던 카메라 장치 또는 동영상 파일이 닫히게 됩니다. VideoCapture::release() 함수 원형은 다음과 같습니다.

 

이번에는 카메라 또는 동영상 파일로부터 한 프레임의 정지 영상을 받아 오는 방법에 대해 알아보겠습니다. VideoCapture 클래스를 이용하여 카메라 또는 동영상 파일을 정상적으로 열었다면, 그 후에는 공통의 멤버 함수를 사용하여 프레임을 받아 올 수 있습니다. VideoCapture 클래스에서 한 프레임을 받아 오기 위해서는 VideoCapture::operator >>() 연산자 재정의 함수 또는 VideoCapture::read() 함수를 사용합니다.

 

현재 열려 있는 카메라 장치 또는 동영상 파일로부터 여러 가지 정보를 받아 오기 위해서는 VideoCapture::get() 함수를 사용합니다.

 

 

예를 들어 시스템 기본 카메라를 열고, 카메라의 기본 프레임 크기를 확인하려면 다음과 같이 코드를 작성할 수 있습니다.

VideoCapture cap(0);
 
int w = cvRound(cap.get(CAP_PROP_FRAME_WIDTH));
int h = cvRound(cap.get(CAP_PROP_FRAME_HEIGHT));

 

 

VideoCapture::get() 함수와 반대로 현재 열려 있는 카메라 또는 비디오 파일 재생과 관련된 속성 값을 설정할 때에는 VideoCapture::set() 함수를 사용합니다.

 

 


4.2 다양한 그리기 함수

 

4.2.1 직선 그리기

영상 위에 직선을 그리는 line() 함수입니다. line() 함수도 cv 네임스페이스에서 선언되어 있지만 이 책에서는 간단히 line() 함수라고 표기하겠습니다. line() 함수 원형은 다음과 같습니다.

 

만약 화살표 형태의 직선을 그려야 하는 경우에는 arrowedLine() 함수를 이용하면 편리합니다. arrowedLine() 함수 원형은 다음과 같습니다.

OpenCV 함수 중에서 drawMarker() 함수는 직선 그리기 함수를 이용하여 다양한 모양의 마커(marker)를 그립니다. drawMarker() 함수 원형은 다음과 같습니다.

4.2.2 도형 그리기

사각형을 그리는 OpenCV 함수 이름은 rectangle()입니다. 그림을 그릴 사각형 정보는 사각형의 대각 위치에 있는 두 꼭지점 좌표를 이용하거나 또는 Rect 클래스 타입의 객체를 이용하여 전달할 수 있습니다. OpenCV는 다음과 같이 두 가지 형식의 rectangle() 함수를 제공합니다.

 

OpenCV에서 원을 그리는 함수는 circle()입니다. 원을 그리기 위해서는 원의 중심점 좌표와 반지름을 지정해야 합니다. circle() 함수 원형은 다음과 같습니다.

OpenCV에서 타원을 그리고 싶을 때에는 ellipse() 함수를 사용할 수 있습니다. 타원을 그리는 방식은 원보다는 좀 더 복잡합니다. ellipse() 함수 원형은 다음과 같습니다.

 

 polylines() 함수를 사용할 수 있습니다. polylines() 함수에는 다각형의 꼭지점 좌표를 전달해야 하며, 꼭지점 좌표는 보통 vector<Point> 자료형에 저장하여 전달합니다. polylines() 함수 원형은 다음과 같습니다.

 

 

4.2.3 문자열 출력하기

OpenCV는 영상 위에 정해진 폰트로 문자열을 출력하는 putText() 함수를 제공합니다. putText() 함수 원형은 다음과 같습니다.

 

 

 


4.3 이벤트 처리

 

OpenCV에서 유용하게 사용할 수 있는 키보드, 마우스, 트랙바 이벤트 처리 방법에 대해 알아보겠습니다.

4.3.1 키보드 이벤트 처리

HelloCV 프로그램에서 키 입력을 확인하기 위해 사용한 함수는 waitKey() 함수이고, 이 함수가 키보드 입력을 처리하는 기본적인 OpenCV 함수입니다. 다시 한 번 waitkey() 함수의 원형을 소개하면 다음과 같습니다.

4.3.2 마우스 이벤트 처리

OpenCV에서 특정 창에 마우스 콜백 함수를 등록할 때에는 setMouseCallback() 함수를 사용합니다. setMouseCallback() 함수의 원형과 사용법은 다음과 같습니다.

마우스 콜백 함수는 마우스 이벤트가 발생할 때 자동으로 호출되는 함수이며, 이 콜백 함수의 형식 MouseCallback은 다음과 같이 정의되어 있습니다.

typedef void (*MouseCallback)(int event, int x, int y, int flags, void* userdata);

 

 

4.3.3 트랙바 사용하기

OpenCV에서 트랙바를 생성하려면 createTrackbar() 함수를 사용하며, 이 함수의 원형은 다음과 같습니다.

 


4.4 OpenCV 데이터 파일 입출력

4.4.1 FileStorage 클래스
OpenCV에서 데이터 파일 입출력은 FileStorage 클래스가 담당합니다. FileStorage 클래스는 OpenCV에서 사용하는 데이터의 파일 입출력 기능을 캡슐화하여 지원하는 클래스입니다.

FileStorage 객체를 생성한 후에는 FileStorage::open() 함수를 이용하여 실제 사용할 파일을 열어야 합니다. FileStorage::open() 함수 원형은 다음과 같습니다.

 

4.4.2 데이터 파일 저장하기

FileStorage 클래스 객체에 데이터를 저장할 때 사용하는 << 연산자 재정의 함수 원형은 다음과 같습니다.

4.4.3 데이터 파일 불러오기

특정 이름으로 저장되어 있는 FileNode 객체에 접근하려면 FileStorage::operator[]() 연산자 재정의 함수를 사용합니다.

일단 노드 이름을 이용하여 FileNode 객체를 얻어 온 후에는 FileNode 클래스의 >> 연산자 재정의 함수를 이용하여 노드에 저장된 데이터 값을 받아 올 수 있습니다. FileNode 객체와 함께 사용하는 >> 연산자 재정의 함수 원형은 다음과 같습니다.


4.5 유용한 OpenCV 기능

 

4.5.1 마스크 연산

 Mat::setTo() 함수는 마스크 연산을 지원하는 함수이며, 이 함수의 원형을 다시 쓰면 다음과 같습니다.

마스크 연산을 지원하는 Mat::copyTo() 함수 원형은 다음과 같습니다.

4.5.2 연산 시간 측정

OpenCV에서는 getTickCount() 함수와 getTickFrequency() 함수를 사용하여 특정 연산의 수행 시간을 측정합니다.

4.5.3 유용한 OpenCV 함수 사용법

sum( ) 함수와 mean( ) 함수

주어진 행렬의 전체 원소 합 또는 평균을 구하는 일은 종종 필요합니다. OpenCV에서 Mat 행렬의 원소 합을 구하고 싶을 때에는 sum() 함수를 사용하고, 평균을 구하고 싶을 때에는 mean() 함수를 사용합니다. 이 두 함수는 4채널 이하의 행렬에 대해서만 동작하며, 합과 평균을 Scalar 타입으로 반환합니다. 두 함수의 원형은 다음과 같습니다.

 

minMaxLoc( ) 함수

다음으로 살펴볼 함수는 주어진 행렬의 최솟값, 최댓값을 찾는 minMaxLoc() 함수입니다. 이 함수는 최솟값, 최댓값이 있는 좌표 정보도 함께 알아낼 수 있습니다. minMaxLoc() 함수 원형은 다음과 같습니다.

normalize( ) 함수

다음으로는 행렬의 노름(norm) 값을 정규화하거나 또는 원소 값 범위를 특정 범위로 정규화할 때 사용할 수 있는 normalize() 함수에 대해 알아보겠습니다. normalize() 함수 원형은 다음과 같습니다.

cvRound( ) 함수

영상 처리를 수행하다 보면 내부 연산은 실수를 사용하고, 최종적인 결과는 정수로 변환하는 경우가 종종 있습니다. 실수 값을 정수로 변환할 때는 주로 반올림을 사용하며, OpenCV에서는 실수 값의 반올림 연산을 위해 cvRound() 함수를 제공합니다. cvRound() 함수 원형은 다음과 같습니다.