[OpenCV 5] 동영상 입출력 (파일 / 카메라)

Sinaenjuni·2023년 7월 8일
0

OpenCV

목록 보기
5/25

VideoCapture

OpenCV에서는 카메라 혹은 동영상으로부터 프레임(Frame)을 받아오는 작업을 VideoCapture 클래스 하나로 처리한다. VideoCapture의 객체는 영상 파일의 경로 혹은 장치 번호로 초기화 하며, fream = Read(); 함수 혹은 cap >> frame; 오버로딩 된 연산자를 통해서 데이터를 가져온다. read() 함수는 grab()retrieve() 두 함수를 합친 것이다. grab()은 장치에서 프레임을 메모리에 올리는 작업을 수행하고 retrieve() 메모리에서 다음 프레임을 검색해서 반환하는 역할을 수행한다.
open()의 인자는 정수와 문자열을 받을 수 있는데 정수의 경우 연결되 카메라 장치의 번호를 입력하고 문자열의 경우 동영상 파일의 경로를 입려한다. 인터넬 주소를 입력하는 경우 스트림 동영상 데이터도 읽을 수 있다.
또한 영상 뿐만 아니라 정지 영상인 이미지도 가능하다.

VideoCapture 클래스 속성

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 클래스와 멤버 함수

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();

}

카메라로 부터 영상 데이터를 Mat 객체로 가져오는 방법

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

영상 데이터를 파일로 저장하는 클래스이다.

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');

Mat 객체를 동영상 파일로 저장하는 방법

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(); 

    }

}

0개의 댓글