지난 글에서 작성했던 로직을 클래스로 구현해봤다.
코드에 대한 설명은 주석으로 대체한다.
oneVideoWriter.hpp
#ifndef LANE_DETECTION_ONEVIDEOWRITER_HPP //include 꼬임 방지
#define LANE_DETECTION_ONEVIDEOWRITER_HPP
#include <iostream>
#include <opencv2/opencv.hpp>
/**
* 영상 합본 저장하는 클래스
*/
class OneVideoWriter {
public:
int width, height; // 영상 1개의 너비, 높이
int row, col; // 영상 배치 레이아웃 - 2X3으로 배치한다면 row=2, col=3
int proc_cnt; // 한 화면에 나올 영상 개수
std::string file_path; // 비디오 저장 경로
cv::Mat merged_frame; // 합본
cv::VideoWriter vw;
OneVideoWriter() {} // 선언용
// 생성자 + 초기화
OneVideoWriter(std::string file_path, int width, int height, int row, int col, int proc_cnt);
// 프레임 작성
void writeFrame(cv::Mat frame, int idx);
};
/**
* 생성자
* @param file_path 저장 파일 경로
* @param width 작은 영상 1개 너비
* @param height 작은 영상 1개 높이
* @param row 영상 레이아웃 - 몇개의 행으로 배치할건지
* @param col 영상 레이아웃 - 몇개의 열로 배치할건지
* @param proc_cnt 프로세수 수 - 영상의 수
*/
OneVideoWriter::OneVideoWriter(std::string file_path, int width, int height, int row, int col, int proc_cnt) {
this->width = width; // 영상 1개의 너비
this->height = height; // 영상 1개의 높이
this->row = row;
this->col = col;
this->proc_cnt = proc_cnt;
vw.open(file_path, cv::VideoWriter::fourcc('a', 'v', 'c', '1'), 30, cv::Size(col * width, row * height), true);
this->merged_frame = cv::Mat(row * height, col * width, CV_8UC3);
}
/**
* idx번째 프레임 저장하는 함수
* @param frame
* @param idx 0부터 시작하는 인덱스
*/
void OneVideoWriter::writeFrame(cv::Mat frame, int idx) {
cv::Mat frame_cp = frame.clone();
// 모든 프레임의 type을 BGR로 통일
if (frame.type() != CV_8UC3) {
cvtColor(frame, frame_cp, cv::COLOR_GRAY2BGR);
}
//위치 계산
int r = idx / this->col, c = idx % this->col;
// roi 영역 잡기
cv::Mat roi = this->merged_frame(cv::Rect(c * this->width, r * this->height, this->width, this->height));
// 합본 프레임에 복사
frame_cp.copyTo(roi);
// 프레임 합본 완성되면 비디오에 저장
if (idx + 1 == this->proc_cnt) {
this->vw << this->merged_frame;
}
}
#endif //LANE_DETECTION_ONEVIDEOWRITER_HPP
#include "opencv2/opencv.hpp"
#include "./oneVideoWriter.hpp"
using namespace cv;
OneVideoWriter vw;
const string src_path = "../video.avi";
const string dst_path = "../result.mp4";
int main(){
VideoCapture input_video(src_path);
if (!input_video.isOpened()) {
cout << "Can't open video\n";
return;
}
int width = input_video.get(CAP_PROP_FRAME_WIDTH);
int height = input_video.get(CAP_PROP_FRAME_HEIGHT);
vw = OneVideoWriter(dst_path, width, height, 2, 2, 4);
Mat frame;
while (true) {
video >> frame;
if (frame.empty()) {
break;
}
// 4단계 가공을 거친다고 가정했을 때...
vw.writeFrame(frame, 0); //원본 저장
frame = proc1(frame);
vw.writeFrame(frame, 1);
frame = proc2(frame);
vw.writeFrame(frame, 2);
frame = proc3(frame);
vw.writeFrame(frame, 3);
}
}