OpenCV에서는 카메라 혹은 동영상으로부터 프레임(Frame)을 받아오는 작업을 VideoCapture
클래스 하나로 처리한다. VideoCapture
의 객체는 영상 파일의 경로 혹은 장치 번호로 초기화 하며, fream = Read();
함수 혹은 cap >> frame;
오버로딩 된 연산자를 통해서 데이터를 가져온다. read()
함수는 grab()
과 retrieve()
두 함수를 합친 것이다. grab()
은 장치에서 프레임을 메모리에 올리는 작업을 수행하고 retrieve()
메모리에서 다음 프레임을 검색해서 반환하는 역할을 수행한다.
open()
의 인자는 정수와 문자열을 받을 수 있는데 정수의 경우 연결되 카메라 장치의 번호를 입력하고 문자열의 경우 동영상 파일의 경로를 입려한다. 인터넬 주소를 입력하는 경우 스트림 동영상 데이터도 읽을 수 있다.
또한 영상 뿐만 아니라 정지 영상인 이미지도 가능하다.
get()
, set()
은 카메라 혹은 동영상 데이터의 속성을 가져오거나 설정하는데 사용된다.
enum VideoCaptureProperties {
CAP_PROP_POS_MSEC =0, //!< Current position of the video file in milliseconds.
CAP_PROP_POS_FRAMES =1, //!< 0-based index of the frame to be decoded/captured next.
CAP_PROP_POS_AVI_RATIO =2, //!< Relative position of the video file: 0=start of the film, 1=end of the film.
CAP_PROP_FRAME_WIDTH =3, //!< Width of the frames in the video stream.
CAP_PROP_FRAME_HEIGHT =4, //!< Height of the frames in the video stream.
CAP_PROP_FPS =5, //!< Frame rate.
CAP_PROP_FOURCC =6, //!< 4-character code of codec. see VideoWriter::fourcc .
CAP_PROP_FRAME_COUNT =7, //!< Number of frames in the video file.
CAP_PROP_FORMAT =8, //!< Format of the %Mat objects (see Mat::type()) returned by VideoCapture::retrieve().
//!< Set value -1 to fetch undecoded RAW video streams (as Mat 8UC1).
CAP_PROP_MODE =9, //!< Backend-specific value indicating the current capture mode.
CAP_PROP_BRIGHTNESS =10, //!< Brightness of the image (only for those cameras that support).
CAP_PROP_CONTRAST =11, //!< Contrast of the image (only for cameras).
CAP_PROP_SATURATION =12, //!< Saturation of the image (only for cameras).
CAP_PROP_HUE =13, //!< Hue of the image (only for cameras).
CAP_PROP_GAIN =14, //!< Gain of the image (only for those cameras that support).
CAP_PROP_EXPOSURE =15, //!< Exposure (only for those cameras that support).
CAP_PROP_CONVERT_RGB =16, //!< Boolean flags indicating whether images should be converted to RGB. <br/>
//!< *GStreamer note*: The flag is ignored in case if custom pipeline is used. It's user responsibility to interpret pipeline output.
...
}
VideoCapture(const String& filename, int apiPreference = CAP_ANY);
bool open(const String& filename, int apiPreference = CAP_ANY);
VideoCapture(int index, int apiPreference, const std::vector<int>& params);
bool open(int index, int apiPreference, const std::vector<int>& params);
bool isOpened() const;
void release();
bool grab();
bool retrieve(OutputArray image, int flag = 0);
VideoCapture& operator >> (CV_OUT Mat& image);
virtual bool read(OutputArray image);
virtual bool set(int propId, double value);
virtual double get(int propId) const;
void ex_video(){
VideoCapture cap("../data//test_video.mp4");
// or
// VideoCapture cap;
// cap.open(0);
if(!cap.isOpened()){
cerr << "File open failed!" << endl;
return;
}
Mat frame;
while(true){
cap >> frame;
cout << cap.get(CAP_PROP_FRAME_HEIGHT) << endl;
cout << cap.get(CAP_PROP_FRAME_WIDTH) << endl;
cout << cap.get(CAP_PROP_FRAME_COUNT) << endl;
cout << cap.get(CAP_PROP_FPS) << endl;
cout << cap.get(CAP_PROP_POS_FRAMES) << endl;
imshow("video", frame);
if(waitKey(10) == 27){
break;
}
}
cap.release();
destroyAllWindows();
}
VideoCapture cap(0);
에서 인지로 들어간 숫자는 장치의 번호를 의미한다. 장치에 연결된 카메라가 여러개인 경우
void ex_cam(){
VideoCapture cap(0);
if(!cap.isOpened()){
cerr << "Camera open failed!" << endl;
return;
}
cap.set(CAP_PROP_FRAME_HEIGHT, 1280);
cap.set(CAP_PROP_FRAME_WIDTH, 720);
int w = cvRound(cap.get(CAP_PROP_FRAME_WIDTH));
int h = cvRound(cap.get(CAP_PROP_FRAME_HEIGHT));
cout << w << " x " << h << endl;
Mat frame;
while(true){
// cap >> frame;
cap.read(frame);
// 위 두 줄의 코드는 동일하게 cap으로 부터 한 프레임의 영상 데이터를 받아오는 코드이다.
// 일반적인 카메라의 FPS는 30으로 초당 30장의 이미지를 가져온다.
// 33ms의 1 frame을 받아오는 것이며, 해당 loop는 적어도 33ms의 한 번 순회 한다고 볼 수 있다.
if(frame.empty()){
cerr << "Fream empty" << endl;
break;
}
imshow("cam", frame);
cout << cap.get(CAP_PROP_FPS) << endl;
if(waitKey(1) == 27){
// waitKey()에 의해서 순회 주기가 33ms보다 길어질 수 있다.
break;
}
}
cap.release();
destroyAllWindows();
}
영상 데이터를 파일로 저장하는 클래스이다.
VideoWriter(const String& filename, int fourcc, double fps, Size frameSize, bool isColor = true);
bool open(const String& filename, int fourcc, double fps, Size frameSize, bool isColor = true);
bool isOpened() const;
void release();
VideoWriter& operator << (const Mat& image);
void write(InputArray image);
bool set(int propId, double value);
double get(int propId) const;
int fourcc(char c1, char c2, char c3, char c4);
// e.g.
// int fourcc = VideoWriter::fourcc('R','P','Z','A');
void ex_video_writer(){
VideoCapture cap(0);
// VideoCapture cap("../data/test_video.mp4");
if(!cap.isOpened()){
cerr << "File open failed!" << endl;
return;
}
// int fourcc = VideoWriter::fourcc('X', 'V', 'I', 'D');
int fourcc = VideoWriter::fourcc('R','P','Z','A');
Size size((int)cap.get(CAP_PROP_FRAME_WIDTH),
(int)cap.get(CAP_PROP_FRAME_HEIGHT));
double fps = cap.get(CAP_PROP_FPS);
cout << "FPS " << fps << endl;
cout << "Size " << size << endl;
cout << "Size " << size.width << endl;
cout << "foucc " << fourcc << endl;
VideoWriter output("../data/test_video2.mp4", fourcc, fps, size);
if(!output.isOpened()){
cout << "test_video_output.avi open failed" << endl;
return;
}
int delay = cvRound(1000/fps);
Mat frame;
while(true){
cap >> frame;
if(frame.empty()){
break;
}
output << frame;
imshow("frame", frame);
if(waitKey(delay) == 27){
// 한 fream 단위로 원본 영상과 시간을 맞추기 위해 delay를 사용한다.
break;
}
cout << "File save complete!" << endl;
output.release();
cap.release();
destroyAllWindows();
}
}