本ページは i-PRO株式会社 の有志メンバーにより記載されたものです。
本ページの情報は ライセンス に記載の条件で提供されます。
本ページでは、i-PRO カメラとLinux OS の PCを MJPEG(Motion JPEG) で接続して映像表示するプログラムを c++ で作成します。
Python の記事は こちら を参照ください。
i-PRO カメラと接続するための MJPEG 表記仕様は こちら を参照ください。
Linux の c++ と OpenCV を使って、PC と i-PRO カメラを MJPEG(Motion JPEG) で接続して映像表示してみます。
今回の手法ではMPEGの取得をOpenCVに任せます。
| 開発環境 : |
GNU build-essensial CMake |
9.4.0 12.8 3.16.3 |
| ライブラリ : | OpenCV | 4.6.0 |
| OS : | ubuntu |
20.04 LTS |
以下のコマンドを実施して環境を準備します。
sudo apt update -y && sudo apt upgrade -y sudo apt install build-essential libopencv-dev cmake -y sudo apt update -y && sudo apt upgrade -y
サンプルプログラムのソースコードを以下に示します。
[プログラムソース "opencv_mjpeg.cpp"]
/*
======================================================================================
[Abstract]
Try connecting to an i-PRO camera with MJPEG.
MJPEG で i-PRO カメラと接続してみる
[Details]
Let's try first.
まずはやってみる
[Library install]
sudo apt update -y && sudo apt upgrade -y
sudo apt install build-essential libopencv-dev cmake -y
sudo apt update -y && sudo apt upgrade -y
======================================================================================
*/
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/utility.hpp>
const std::string user_id = "user_id"; // Change to match your camera setting
const std::string user_pw = "user_pw"; // Change to match your camera setting
const std::string host = "192.168.0.10"; // Change to match your camera setting
const std::string winname = "VIDEO"; // Window title
const std::string framerate = "15"
const std::string url = "http://" + user_id + ":" + user_pw + "@" + host + "/cgi-bin/nphMotionJpeg?Framerate=" + framerate ;
int main(int argc, const char* argv[])
{
cv::VideoCapture cap(url);
cv::Mat frame;
char ret;
while (true) {
cap >> frame;
if (frame.empty()) {
break;
}
// Please modify the value to fit your PC screen size.
resize(frame, frame, cv::Size(), 0.5, 0.5); // Setting by magnification.
// Display video.
cv::imshow(winname, frame);
ret = (char)cv::waitKey(1); // necessary to display the video by cv::imshow().
// Press the "q" key to finish.
if (ret == 'q') {
break;
}
}
cap.release();
cv::destroyAllWindows();
return EXIT_SUCCESS;
}
このソースコードはRTSPのソースコードとほぼ同じとなります。
ビルドにおいて環境依存を極力するなくするため、以下の手順でビルドします。
ソースコード(opencv_mjpeg.cpp)と同じディレクトリに以下のように中身が書かれたCMakeLists.txtを配置してください。
CMake の知識がある方は、内容をカスタマイズしてお使いください。
["CMakeLists.txt"]
# 変数SOURCE_CORDEを宣言し、ソースコードのファイル名の拡張子無くした値を入れる。
# cmake -D SOURCE_CODE=(ソース名)で上書き可
set(SOURCE_CODE opencv_mjpeg CACHE NAME "Target object name")
# CMakeの最低バージョンを記述
cmake_minimum_required(VERSION 2.8)
# ソリューション名を指定
project( ${SOURCE_CODE} )
# OpenCVのパッケージを探す
find_package( OpenCV REQUIRED )
#ヘッダファイルのパスを指定
include_directories( ${OpenCV_INCLUDE_DIRS} )
# 実行ファイル名とソース指定(ここではソースと同じ名前の実行ファイルを作ります)
add_executable( ${SOURCE_CODE} ${SOURCE_CODE}.cpp )
#リンク先のライブラリを指定
target_link_libraries( ${SOURCE_CODE} ${OpenCV_LIBS})
ビルド環境を作成してアプリケーションを構築するため、以下のコマンドを実施します。
mkdir build && cd build cmake .. make
これにより、buildディレクトリに[opencv_jpeg]という実行ファイルができましたので、以下のようにコマンドを実施すればアプリケーションが実施されます
./opencv_mjpeg
ソースコードの変更をする場合は、すでにビルド環境ができていますので、buildディレクトリで以下のようにすれば更新が可能です。
ライブラリを追加する場合は CMakeLists.txtの追記を行い、build ディレクトリを削除してcmakeをやり直してください。
make clean make
Linux の c++ と OpenCV を使って、PC と i-PRO カメラを MJPEG(Motion JPEG) で接続して映像表示してみます。
MJPEGのヘッダーの情報が欲しい時はこちらのソースコードを参考にしてみてください。
| 開発環境 : |
GNU build-essensial CMake |
9.4.0 12.8 3.16.3 |
| ライブラリ : | OpenCV libcurl4 |
4.6.0 7.68.0-1ubuntu2.14 amd64 |
| OS : | ubuntu | 20.04 LTS |
※注意:このソースでは"gcc extensions" を利用しています。標準仕様ではないので gcc/g++ 以外ではエラーになります。
以下のコマンドを実施して環境を準備します。
sudo apt update -y && sudo apt upgrade -y sudo apt install build-essential libopencv-dev cmake -y sudo apt install libcurl4-openssl-dev -y sudo apt update -y && sudo apt upgrade -y
サンプルプログラムのソースコードを以下に示します。
[プログラムソース "opencv_mjpeg_curl.cpp"]
/*
======================================================================================
[Abstract]
Try connecting to an i-PRO camera with MJPEG by curl.
RTSP で i-PRO カメラと接続してみる
[Details]
Let's try first.
まずはやってみる
[Library install]
sudo apt update -y && sudo apt upgrade -y
sudo apt install build-essential libopencv-dev cmake -y
sudo apt install libcurl4-openssl-dev -y
sudo apt update -y && sudo apt upgrade -y
======================================================================================
*/
#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>
#include <opencv2/core/utility.hpp>
#include <curl/curl.h>
const std::string user_id = "user-id"; // Change to match your camera setting
const std::string user_pw = "password"; // Change to match your camera setting
const std::string host = "192.168.0.10"; // Change to match your camera setting
const std::string winname = "VIDEO"; // Window title
const std::string framerate = "15"; // Frame rate (indispensable param)
const std::string cameraURL = "http://" + host + "/cgi-bin/nphMotionJpeg?Framerate=" + framerate;
// data receive callback function
size_t onReceive(void *ptr, size_t size, size_t nmemb, void *userdata)
{
//important static flag
static bool isSOI = false;
//receivebuffer handover
std::vector<char>* receiveBuffer = (std::vector<char>*)userdata;
const size_t segsize = size * nmemb;
//Find SOI/EOI and get position and raise a flag
int PosS=0; //start positon
int PosE=0; // end positon
int status=0; //0:Non,1:EOI,2:SOI,3:EOI->SOI
bool isJPEG=false;
//Finding SOI and EOI
for(int i=0;i<segsize-1;i++){
//find EOI
if(*((char*)ptr+i)==(char)0xFF && *((char*)ptr+i+1)==(char)0xD9 && isSOI==true){
isSOI=false;
PosE=i+1;//eoi position
status=1;
}
//find SOI
if(*((char*)ptr+i)==(char)0xFF && *((char*)ptr+i+1)==(char)0xD8 && isSOI==false){
isSOI=true;
PosS=i; //soi positon
if(status==1){ //EOI -> neer -> SOI
status=3;
}else{
status=2;
}
break; //start JPEG Image
}
}
//Fill jpeg data into receiveBuffer
if(isSOI==true && status==0){
receiveBuffer->insert(receiveBuffer->end(), (char*)ptr, (char*)ptr+segsize);
}else if(status==2){
receiveBuffer->insert(receiveBuffer->end(), (char*)ptr+PosS, (char*)ptr+segsize);
}else if(status==1 || status==3){
receiveBuffer->insert(receiveBuffer->end(), (char*)ptr, (char*)ptr+PosE);
isJPEG=true; //complete JPEG
}
//display JPEG
if(isJPEG==true){
try{
// JPEG decore
cv::Mat frame = cv::imdecode(*receiveBuffer, cv::IMREAD_UNCHANGED);
//clear recv_buffer
receiveBuffer->clear();
// Please modify the value to fit your PC screen size.
resize(frame, frame, cv::Size(), 0.5, 0.5);
cv::imshow(winname, frame); //Display video.
if((char)cv::waitKey(1) >= 0) { // wait for any key
return 0;
}
}catch(...){
//clear recv_buffer
receiveBuffer->clear();
}
}
//Fill jpeg data into receiveBuffer
if(status==3){ //EOI -> neer -> SOI : recv_buf need to add data
receiveBuffer->insert(receiveBuffer->end(), (char*)ptr+PosS, (char*)ptr+segsize);
}
return segsize;
}
int main(int argc, char* argv[])
{
std::vector<char> receiveBuffer;
CURL* curl = NULL;
CURLcode res;
//init curl processing
curl = curl_easy_init();
if (!curl) {
printf("curl_easy_init() failed...\n");
return 0;
}
//for digest
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
std::string user_id_pw =user_id + ":" + user_pw;
curl_easy_setopt(curl, CURLOPT_USERPWD, user_id_pw.c_str());
//curl option
curl_easy_setopt(curl, CURLOPT_URL, cameraURL.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &receiveBuffer);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, onReceive);
//In the mjpeg case, curl_easy_perform continues
res = curl_easy_perform(curl);
//curl processing finished
curl_easy_cleanup(curl);
receiveBuffer.clear();
cv::destroyAllWindows();
return 0;
}
MJPEGはストリームになるため、一度curl_easy_performが実行されると、ネットワーク切断が発生するまでcurl_easy_performが実行され続けます。
そこで、curl_easy_setoptでコールバック関数を呼び出すようにして、コールバック関数で受信バッファにJPEGデータを貯めこむようにしています。
MJPEGのストリームの区切りは、EOI SOIでわかるため、コールバック関数単位に受け取ったデータの中身を確認してSOIを見つけ出し、
EOIを受信するまで、受信バッファを貯めこむ動きをします。JPEGのデコードが終わったら、受信バッファをクリアしています。
ビルドにおいて環境依存を極力するなくするため、以下の手順でビルドします。
ソースコード(opencv_mjpeg_curl.cpp)と同じディレクトリに以下のように中身が書かれたCMakeLists.txtを配置してください。
CMake の知識がある方は、内容をカスタマイズしてお使いください。
["CMakeLists.txt"]
# 変数SOURCE_CORDEを宣言し、ソースコードのファイル名の拡張子無くした値を入れる。
# cmake -D SOURCE_CODE=(ソース名)で上書き可
set(SOURCE_CODE opencv_mjpeg_crel CACHE NAME "Target object name")
# CMakeの最低バージョンを記述
cmake_minimum_required(VERSION 2.8)
# ソリューション名を指定
project( ${SOURCE_CODE} )
# OpenCVのパッケージを探す
find_package( OpenCV REQUIRED )
#ヘッダファイルのパスを指定
include_directories( ${OpenCV_INCLUDE_DIRS} )
# CURLのパッケージを探す
find_package( CURL REQUIRED )
#ヘッダファイルのパスを指定
include_directories( ${CURL_INCLUDE_DIR} )
# 実行ファイル名とソース指定(ここではソースと同じ名前の実行ファイルを作ります)
add_executable( ${SOURCE_CODE} ${SOURCE_CODE}.cpp )
#リンク先のライブラリを指定
target_link_libraries( ${SOURCE_CODE} ${OpenCV_LIBS} ${CURL_LIBRARIES})
ビルド環境を作成してアプリケーションを構築するため、以下のコマンドを実施します。
mkdir build && cd build cmake .. make
これにより、buildディレクトリに[opencv_jpeg]という実行ファイルができましたので、以下のようにコマンドを実施すればアプリケーションが実施されます
./opencv_mjpeg_curl
ソースコードの変更をする場合は、すでにビルド環境ができていますので、buildディレクトリで以下のようにすれば更新が可能です。
ライブラリを追加する場合は CMakeLists.txtの追記を行い、build ディレクトリを削除してcmakeをやり直してください。
make clean make
本ページで紹介のソースコードは、下記 github より取得できます。
下記 github のソースコードと本ページの内容は差異がある場合があります。
i-pro-corp/cpp-examples: c++ sample programs for i-PRO camera. (github.com)
本ページの情報は、特記無い限り下記ライセンスで提供されます。
| 2023/3/22 | - | 新規作成, | 蓬田 康雄 |
i-PRO - Programming Items トップページ