OpenCV에서 카메라 또는 동영상 파일로부터 프레임을 받아올 때 사용하는 클래스.
우선 기본 코드는 이렇게 된다.
영상 읽어서 재생하기
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main() {
//"path" 경로에 있는 영상을 읽어오기
VideoCapture cap("path");
// 에러 방지 코드 - 영상이 정상적으로 열렸는지 확인
if (!cap.isOpened()) {
cout << "video not found\n";
return -1;
}
// 영상의 fps를 바탕으로 delay 계산
double fps = cap.get(CAP_PROP_FPS);
int delay = cvRound(1000 / fps);
Mat frame; // 프레임을 받을 변수 선언
int cnt = 0; // 프레임 개수를 저장하는 변수
while (++cnt) {
cap.read(frame);
if (frame.empty()) { // 프레임을 받아오지 못함 (영상 종료)
break;
}
imshow("video", frame); // "video"이름으로 창을 띄움
if (waitKey(delay) > 0) { // delay만큼 입력을 기다림, 만약 키보드 입력이 있을 경우 break
break;
}
}
// 프레임 수 출력
cout << "# of frame: " << cnt;
return 0;
}
위에서 fps를 바탕으로 waitKey()
에 delay를 설정해주는데, 이 부분에 대해서는 좀 더 자세히 적어보려고 한다.
우선 영상을 띄워주기 위해서 imshow()
함수를 쓸 때 필수적으로 따라오는 함수이다. waitKey()
는 인자로 받는 시간만큼 키 입력을 받아 리턴 값으로 돌려주고, 단위는 ms이다. 따라서 1초동안 입력을 받고 싶다면 1000을 넘겨주면 된다. 만약 키 입력을 제대로 받지 못한다면 이미지가 띄워진 창을 한번 클릭하여 포커스를 맞춰준 후 다시 입력해보길 바란다.
여기까지 말하면 뭔가 선택사항 인 것 같지만, 만약 이 코드를 쓰지 않으면, imshow()
함수는 이미지 창을 바로 꺼버린다. 따라서 흔적이라도 보고 싶으면 1ms라도 waitKey()
를 꼭 걸어주어야 한다.
Frame per Second
, 말 그대로 초당 몇 프레임짜리인지 표기하는 영상의 정보이다. 우리가 보는 영상은 프레임의 연속이다. 즉, 연속적인 사진의 모음이라고 생각하면 된다. 이 정보가 중요한 이유는 영상의 속도에 영향을 미치기 때문이다. 어떤 영상이 100개의 프레임으로 이루어진 영상이라고 생각해보자. 만약 fps가 25라면, 이 영상은 100/25 = 4초짜리 영상이라는 것을 알 수 있다. 만약 30이라면, 100/20 = 5초짜리 영상이 된다. 따라서 이 fps는 영상의 속도를 알기 위해 필요한 정보가 된다. OpenCV로 영상을 열어서 재생하기 위해서 fps를 꼭 알아야 하는 것은 아니지만, fps를 모른다면 원본 재생 속도에 맞추어 영상을 띄워 줄 수 없다.
정리하자면,
전체 프레임 수 = 초당 프레임[frame/s] x 영상의 길이[s]
그렇다면 하나의 프레임과 다음 프레임 사이의 간격을 얼마나 될까? 간단하다, 프레임 당 시간이니 Second per Frame, fps의 역수이다.
하나의 프레임이 차지하는 시간[s] = 전체 시간 / 프레임의 수
= 영상 길이[s] / 프레임의 수[frame]
= 1 / fps
= 1000 / fps (ms)
따라서 하나의 프레임을 1000 / fps
ms 만큼 유지한 후, 다음 프레임을 보여주면 된다.