Search on the blog

2014年4月20日日曜日

OpenCV日記(4)PCカメラに写った映像を画像ファイルに出力

 PC内臓カメラに写った画像を取得して、適当な処理をして、画像ファイルに出力するということをやってみました。
 適当な処理は、VideoCaptureクラスの説明[2]を参考にして、
  1. グレースケールに変換
  2. ガウスフィルターでぼかしを入れる
  3. Cannyでエッジ検出
を行いました。

出来たもの


ソースコード
#include <iostream>
#include <sys/time.h>

#include "opencv2/opencv.hpp"

using namespace cv;

/**
 * return time elapsed in millisecond
 */
inline double getElapsedTime(const timeval &s, const timeval &t) {
    double ts = s.tv_sec * 1e6 + s.tv_usec;
    double tt = t.tv_sec * 1e6 + t.tv_usec;
    return (tt - ts) / 1000;
}

/**
 * PCのカメラに写った映像を編集して、ビデオファイルに出力する。
 */
int main() {

    VideoCapture cap(0);   // open the default camera
    if (!cap.isOpened()) {
        std::cout << "Could not access the default camera" << std::endl;
        return -1;
    }

    Size size = Size((int) cap.get(CV_CAP_PROP_FRAME_WIDTH),
                     (int) cap.get(CV_CAP_PROP_FRAME_HEIGHT));
    int codec = CV_FOURCC('X', 'V', 'I', 'D');
    double fps = 30.0;   // frames per second

    VideoWriter writer("sample.avi", codec, fps, size, true);
    if (!writer.isOpened()) {
        std::cout  << "Could not open the output video." << std::endl;
        return -1;
    }

    Mat frame, edges;
    struct timeval startTime, endTime;
    for (;;) {
        gettimeofday(&startTime, NULL);

        cap >> frame;
        cvtColor(frame, edges, CV_BGR2GRAY);
        GaussianBlur(edges, edges, Size(9, 9), 3.0, 3.0);
        Canny(edges, edges, 0, 30, 3);
        cvtColor(edges, frame, CV_GRAY2BGR);   // before write a frame to VideoWriter, conver it to BGR img.
        imshow("live", frame);
        writer << frame;

        gettimeofday(&endTime, NULL);

        int waitTime = max(1.0, 1000 / fps - getElapsedTime(startTime, endTime));
        // std::cout << (int)(1000 / fps) << " - > " << waitTime << std::endl;
        if (waitKey(waitTime) >= 0)            // consider fps and the time elapsed
            break;
    }

    std::cout << "finished" << std::endl;

    return 0;
}
メモ
  • 出力ビデオのコーデックはintでエンコードして渡さないといけない。ビット演算を使って自分でエンコードすることも出来るが、CV_FOURCCというマクロがあるのでそれを使うとよい。
  • 1チャネルのフレームをVideoWriterに出力すると、動画ファイルが再生できなかった。グレースケールのフレームの場合は、3チャネルに変換して出力しないといけない。
  • 定義したFPS(Frame Per Second)と処理に要した時間を考慮して、適切なタイミングでVideoWriterに出力しなければならない。

参考URL
[1] Creating a video with OpenCV 
[2] Reading and Writing Images and Video

0 件のコメント:

コメントを投稿