OpenCVは言わずと知れたComputer Visionのライブラリ群ですが,画像・動画ファイルは作れてもストリーミング周りは弱いです(あるのかな).それを補うためにffmpegやGStreamerと組み合わせる仕様ができていますが,いまいち使い方の文献が多くないように思います.
そこで本稿では,Windows, vcpkg, C++の環境下での実施方法についてまとめてみます.元は卒論指導用です.とりえあず細かいことは省略して書きます.追々詳細化します.
環境構築
- Visual Studio 2022でC++によるアプリケーション開発をする環境を整えてください.
- vcpkgを導入してください
- vcpkgでOpenCVを入れます.つけるオプションは自由ですが,最低限,
が良さそうです
vcpkg install opencv4[gstreamer,ffmpeg]:x64-windows
- 上の方法でOpenCVを入れると,gstreamerの1.22.5が入るようです(2024年6月28日現在).この状態で入るGStreamerは各種プラグインなどが入っていないようなので,別にインストールし,環境変数(
GST_PLUGIN_PATH
)を設定する必要があります.このとき,別にインストールするGStreamerとvcpkgでOpenCVとともにインストールされるGStreamerのバージョンが一致していないと,どうやらうまく動かないようです.古いGStreamerは公式のアーカイブからダウンロードできます.MSVCの方が良いみたいです.無印とDevelの両方を入れます. - GStreamerのインストールが完了したら,
GST_PLUGIN_PATH
を環境変数に設定します.私の環境では,C:\gstreamer\1.0\msvc_x86_64\lib\gstreamer-1.0
でした.
動かしてみよう
こちらのStackOverflowの回答を参考にしました.
cv::VideoWriter
やcv::VideoCapture
を使うようです.サンプルのように,gst-launch-1.0
で記述するようなパイプラインを.open
メソッドの引数に指定します.このとき,appsrc
やappsink
がOpenCVとの窓口になるみたいです.下のサンプルの場合は,cv::VideoWriter
経由でフレームを書き込むと,appsrc
に流れるようです.こちらが正しく実行できれば,下図のようにautovideosink
のウィンドウでOpenCVで作成したフレームが表示されます.
パイプラインを所望のシステムになるように構築するだけですから,ストリーミングでもファイル蓄積でも,簡単にできます.
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
cv::VideoWriter out;
out.open("appsrc ! videoconvert ! autovideosink",
cv::CAP_GSTREAMER,
0,
16,
cv::Size(640, 480),
true);
cv::Mat frame(480, 640, CV_8UC3, cv::Scalar(0, 255, 0));
int count = 0;
while(1)
{
rectangle(frame, Rect(0, 0, 640, 480), Scalar(0, 255, 0), -1);
frame = Mat(480, 640, CV_8UC3, cv::Scalar(0, 255, 0));
cv::putText(frame, to_string(count++), Point(100,100), FONT_HERSHEY_SCRIPT_SIMPLEX, 3.0, Scalar::all(255), 3, 8);
out << frame;
//imshow("sent", frame);
int c = waitKey(100);
if (c == 'q')
break;
}
return 0;
}
RTPストリーミングのサンプル(H.264エンコード)
VideoWriter
の.open
メソッドで指定するパイプラインをRTPでストリーミングするように変えてみます.こちらも先ほどのStackOverflowの回答を参考にしています.
cv::VideoWriter out;
out.open("appsrc ! videoconvert ! x264enc tune=zerolatency bitrate=500 speed-preset=superfast ! rtph264pay ! udpsink host=127.0.0.1 port=5000",
cv::CAP_GSTREAMER,
0,
16,
cv::Size(640, 480),
true);
受信側はgst-launch-1.0
を使って
gst-launch-1.0 udpsrc port=5000 ! application/x-rtp ! rtph264depay ! h264parse ! decodebin ! autovideosink
にして見ます.受信側から起動して,RTPストリーミング開始すれば,ローカルホスト経由ですがautovideosink
のウィンドウで再生されました.
まとめ
これは便利・・・.時間を見つけてもうちょっとちゃんと記事を書きます.あしからず.