카메라와 동영상 처리

VideoCapture 클래스

  • OpenCV 에서는 카메라와 동영상으로부터 프레임을 받아오는 작업을 VideoCapture 클래스 하나로 처리함
  • 카메라와 동영상을 여는 작업이 수행되면 매 프레임을 받아오는 공통의 작업을 수행함

image

image

카메라 열기
VideoCapture::VideoCapture(int index, int apiPreference = CAP_ANY);
bool VideoCapture::open(int index, int apiPreference = CAP_ANY);
  • index : 사용할 캡쳐 장치의 ID. (camera_id + domain_offset_id)
    • 시스템 기본 카메라를 기본 방법으로 열려면 0을 지정
    • 컴퓨터에 여러 대의 카메라가 연결되어 있으면 테스트 후 0, 1, … 순서로 지정
  • apiPreference : 선호하는 카메라 처리 방법
    • default 값이 있으므로 대부분은 apiPreference를 입력하지 않고 카메라를 오픈함
    • CAP_DSHOW, CAP_MSMF, CAP_V4L 등 특정 방법을 지정할 수 있음
  • 반환값 : VideoCapture 생성자를 사용했을 경우에는 VideoCapture 객체가 반환되고, VideoCapture:Open() 함수를 사용했을 경우에는 성공하면 true, 실패하면 false를 반환
동영상 파일 열기
VideoCapture::VideoCapture(const String& filename, int apiPreference = CAP_ANY);
bool VideoCapture::open(const String& filename, int apiPreference = CAP_ANY);
  • filename : 동영상 파일 이름, 정지 영상 시퀀스, 비디오 스트림 URL 등
    • 비디오 파일 : “video.avi”, “./data/video.avi”
    • 정지 영상 시퀀스 : “img_%02d.jpg”
    • 비디오 스트림 URL : “rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4”
  • apiPreference : 선호하는 동영상 처리 방법
  • 반환값 : VideoCapture 생성자를 사용했을 경우에는 VideoCapture 객체가 반환되고, VideoCapture:Open() 함수를 사용했을 경우에는 성공하면 true, 실패하면 false를 반환
현재 프레임 받아오기
bool VideoCapture::read(OutputArray image);
VideoCapture& VideoCapture::operator >> (Mat& image);
  • image : 현재 프레임, 만약 현재 프레임을 받아오지 못하면 비어 있는 영상으로 설정됨
  • 반환값 : VideoCapture::read() 함수는 작업이 성공하면 true, 실패하면 false를 반환
  • 참고사항 : » 연산자 오버로딩은 내부에서 read() 함수를 재호출하는 래퍼(wrapper) 함수
VideoCapture& VideoCapture::operator >> (Mat& image)
{
	read(image);
	return *this;
}
카메라와 동영상 속성 참조와 설정
double VideoCapture:: get(int propId) const;
bool VideoCapture::set(int propId, double value);
#include <iostream>
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

int main()
{
	VideoCapture cap;
	cap.open(0); 
	// 위에 줄과 합쳐서 VideoCapture cap(0) 으로 작성할 수도 있음
	// cap.open("../../data/test_video.mp4"); 
	// 위에 줄과 합쳐서 VideoCapture cap("test_video.mp4"); 으로 작성할 수도 있음

	if (!cap.isOpened()) {
		cerr << "Camera open failed!" << endl;
		return -1;
	}

	cap.set(CAP_PROP_FRAME_WIDTH, 1280); 
    cap.set(CAP_PROP_FRAME_HEIGHT, 720); // 1280 X 720 을 지원하는 카메라를 다음과 같이 세팅해줄 수 있음. 동영상에서 작동 X
		
	int w = cvRound(cap.get(CAP_PROP_FRAME_WIDTH)); // cvRound을 통해 double값인 현재 프레임의 width을 반올림
	int h = cvRound(cap.get(CAP_PROP_FRAME_HEIGHT)); // cvRound을 통해 double값인 현재 프레임의 height을 반올림
	// double fps = cap.get(CAP_PROP_FPS); // FPS 값을 받아옴
    
	cout << "width: " << w << endl;
	cout << "height: " << h << endl;
    // cout << "fps: " << fps << endl;

	Mat frame, edge;
	while (true) {
		cap >> frame; // VideoCapture 객체로부터 한 프레임을 받아 frame 변수에 저장

		if (frame.empty()) {
			cerr << "Empty frame!" << endl;
			break;
		}

		Canny(frame, edge, 50, 150); // frame 영상을 Canny 한 후 edge 영상으로 만듬
		imshow("frame", frame);
		imshow("edge", edge);

		if (waitKey(1) == 27) 
		// waitKey에 아무 값을 안주면 키 입력때 까지 무한정 기다려서 동영상이 아닌 한 프레임씩 나옴 
		// 괄호안에 숫자를 넣어 일정시간만 기다리게 해야함
		// 27은 ESC를 의미하는 것으로 ESC를 입력시 종료
			break;
	}
	
	cap.release();
	destroyAllWindows();
}

VideoWriter 클래스

  • OpenCV는 일련의 정지 영상을 동영상 파일로 저장할 수 있는 VideoWriter 클래스를 제공함 (동영상 저장)

image

VideoWriter::VideoWriter(const 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);
  • filename : 저장할 동영상 파일의 이름

  • fourcc : four character code의 약자로 압축 방식을 나타내는 4개의 문자, VideoWirter::fourcc() 함수로 생성

image

  • fps : 초당 프레임 수
  • frameSize : 비디오 프레임 크기
  • isColor : 컬러 동영상 플래그로 false로 지정하면 그레이스케일 동영상
#include <iostream>
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

int main()
{
	VideoCapture cap(0);

	if (!cap.isOpened()) {
		cerr << "Camera open failed!" << endl;
		return -1;
	}

	int  fourcc = VideoWriter::fourcc('X', 'V', 'I', 'D');
	double fps = 30;
	Size sz = Size((int)cap.get(CAP_PROP_FRAME_WIDTH), (int)cap.get(CAP_PROP_FRAME_HEIGHT)); 
	// 현재 카메라의 설정에서 Width, Height를 가져와  값을 정수 값으로 변환하고 Size 객체 Sz를 생성함
	// Size sz((int)cap.get(CAP_PROP_FRAME_WIDTH), (int)cap.get(CAP_PROP_FRAME_HEIGHT));  바꿔   있음

	cout << "FPS = " << fps << endl;
	cout << "Size = " << sz << endl;

	VideoWriter output("output.avi", fourcc, fps, sz); // output.avi 파일로 저장

	if (!output.isOpened()) { // 동영상 파일 저장을 위해 파일 open을 실패했을 경우 에러문구와 함께 프로그램 종류 
		cerr << "output.avi open failed!" << endl;
		return -1;
	}

	int delay = cvRound(1000 / fps); 
	Mat frame, edge;
	
	while (true) {
		cap >> frame;
		if (frame.empty())
			break;

		Canny(frame, edge, 50, 150);
		cvtColor(edge, edge, COLOR_GRAY2BGR); 
		// 그레이스케일 영상인 edge 파일을 BGR 파일로 변경해야 정상적으로 저장이 
		// 안하면 저장이 안되는 이유 : 위에서 output을 color로 만들었으므로 output을 수정하든 이렇게 변환해주든   하나를 진행해야 저장이 가능

		output << frame; // output에 현재 frame을 저장
		output << edge; 

		imshow("frame", frame);
		imshow("edge", edge);

		if (waitKey(delay) == 27)
			break;
	}

	cout << "output.avi file is created!!!" << endl;
	
	output.release();
	cap.release();
	destroyAllWindows();
}