Web Analytics

こつこつエンジニア

現役アプリ開発者によるIT系特化ブログ

【VS(C#)+OpenCV(C++)】動画ファイルを再生してみる

f:id:madai21:20211014185103j:plain

はじめに

OpenCVには動画ファイルを読み込んでそれを再生する機能はないので、VideoCaptureという動画ファイルを読み込んで1フレームずつ静止画を取得する機能を使用して、それを順次imshowで表示させるという内容で実現したいと思います。

環境

この記事で作成したVisualStudio2019+OpenCV4のプロジェクトがあることを前提に進めます。
madai21.hatenablog.com

手順

  1. C++/CLI(OpenCVラッパー)プロジェクトの編集
  2. C#コンソールアプリプロジェクトの編集
  3. 動画ファイルを再生

1. C++/CLI(OpenCVラッパー)プロジェクトの編集

OpenCVWrapper.hを開いて以下の内容に編集します。

#pragma once
#include <opencv2/opencv.hpp>
#include <msclr/marshal_cppstd.h>
#include <vector>
using namespace System;
using namespace msclr::interop;
namespace OpenCVWrapper {
	public ref class OpenCVWrapperCls
	{
	public:
		static void ShowMovieFile(System::String^ filePath)
		{
			auto vc = cv::VideoCapture(marshal_as<std::string>(filePath));
			while (vc.isOpened())
			{
				cv::Mat mat;
				vc >> mat;
				if (mat.empty()) {
					continue;
				}
 
				cv::imshow("Show Movie File Window", mat);
				auto key = cv::waitKey(1);
				if (key == 27) {
					break;
				}
			}
			cv::destroyAllWindows();
		}
	};
}

2. C#コンソールアプリプロジェクトの編集

Program.csを開いて以下の内容に編集します。
"target.mp4"のところには再生したい動画のファイルパスを設定します。

using System;
 
namespace OpenCVConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            OpenCVWrapper.OpenCVWrapperCls.ShowMovieFile("target.mp4");
        }
    }
}

3. 動画ファイルを再生

では実際に確認していきたいと思います。
今回はこの動画ファイルを使用します。

OpenCVで再生した結果は以下となります。
うーん、再生はしてくれましたがかなり早いですね^^;
これはFPSを全く無視して再生していることが原因です。
なのでFPS通りに再生しようとするとフレーム間に正確にウェイト入れたりしないといけないのでOpenCVのVideoCaptureでは厳しそうです。。
FPSの情報はCAP_PROP_FPSプロパティで取ってこれるので、簡易的にwaitKeyにFPSの1フレームmsecを与えてみましょう。
OpenCVWrapper.hを以下の内容に変更します。

#pragma once
#include <opencv2/opencv.hpp>
#include <msclr/marshal_cppstd.h>
#include <vector>
using namespace System;
using namespace msclr::interop;
namespace OpenCVWrapper {
	public ref class OpenCVWrapperCls
	{
	public:
		static void ShowMovieFile(System::String^ filePath)
		{
			auto vc = cv::VideoCapture(marshal_as<std::string>(filePath));
			double fps = vc.get(cv::CAP_PROP_FPS); // ★追加した個所
			double fps_ms = ((1.0 / fps) * 1000.0); // ★追加した個所
			while (vc.isOpened())
			{
				cv::Mat mat;
				vc >> mat;
				if (mat.empty()) {
					continue;
				}

				cv::imshow("Show Movie File Window", mat);
				auto key = cv::waitKey(fps_ms); //★修正した個所
				if (key == 27) {
					break;
				}
			}
			cv::destroyAllWindows();
		}
	};
}

こうなりました。
先ほどより元の動画ファイルのFPSに近づきましたが、今度はウェイト入れ過ぎで遅いですね^^;
私の使用している低性能PCではここらあたりが限界のようですww

おわりに

今回は動画ファイルを読み込んで1フレームずつ静止画を表示することに成功しました。
次回はWEBカメラからの映像をリアルタイムに取得して表示させてみたいと思います!