[2023-04-19] 1. OpenCV 카메라와 동영상 처리
카메라와 동영상 처리
VideoCapture 클래스
- OpenCV 에서는 카메라와 동영상으로부터 프레임을 받아오는 작업을 VideoCapture 클래스 하나로 처리함
- 카메라와 동영상을 여는 작업이 수행되면 매 프레임을 받아오는 공통의 작업을 수행함
카메라 열기
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);
- propId : 속성 플래그로 cv::VideoCaptureProperties 또는 Additional flags for Video I/O API backends 상수 중 선택
- 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 클래스를 제공함 (동영상 저장)
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() 함수로 생성
- 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();
}