カメラ画像をOpenCVで取得してJpegエンコードして、ZeroMQを通してネットワーク配信するプログラムサンプル
(メモ)
Windows10, Visual Studio2015環境で、openFrameworks9.3でofxZmq addonとOpenCV3.1を使用して高速に画像を配信するためのサンプルプログラムです。
ofxZmqにstd::vector
ofApp.h
#pragma once #include "ofMain.h" #include "opencv2/opencv.hpp" class ofxZmqSubscriber; class ofxZmqPublisher; class testApp : public ofBaseApp{ public: void setup(); void update(); void draw(); void keyPressed (int key); void keyReleased(int key); void mouseMoved(int x, int y ); void mouseDragged(int x, int y, int button); void mousePressed(int x, int y, int button); void mouseReleased(int x, int y, int button); void windowResized(int w, int h); void dragEvent(ofDragInfo dragInfo); void gotMessage(ofMessage msg); ofxZmqSubscriber* subscriber; ofxZmqPublisher* publisher; cv::VideoCapture cap; cv::Mat frame; std::vector<unsigned char> send_buf; std::vector<int> params; string type; cv::Mat image; std::vector<unsigned char> recv_buf; };
ofApp.cpp
#include "testApp.h" #include "ofxZmq.h" #include "opencv2/opencv.hpp" #pragma comment(lib, "opencv_calib3d310.lib") #pragma comment(lib, "opencv_core310.lib") #pragma comment(lib, "opencv_features2d310.lib") #pragma comment(lib, "opencv_flann310.lib") #pragma comment(lib, "opencv_highgui310.lib") #pragma comment(lib, "opencv_imgcodecs310.lib") #pragma comment(lib, "opencv_imgproc310.lib") #pragma comment(lib, "opencv_ml310.lib") #pragma comment(lib, "opencv_objdetect310.lib") #pragma comment(lib, "opencv_photo310.lib") #pragma comment(lib, "opencv_shape310.lib") #pragma comment(lib, "opencv_stitching310.lib") #pragma comment(lib, "opencv_superres310.lib") #pragma comment(lib, "opencv_ts310.lib") #pragma comment(lib, "opencv_video310.lib") #pragma comment(lib, "opencv_videoio310.lib") #pragma comment(lib, "opencv_videostab310.lib") //-------------------------------------------------------------- void testApp::setup() { ofSetFrameRate(30); cap.open(0); if (cap.isOpened()) { cout << "Camera is ready!" << endl; cap.set(cv::CAP_PROP_FRAME_WIDTH, 1280); cap.set(cv::CAP_PROP_FRAME_HEIGHT, 720); cap.set(cv::CAP_PROP_FPS, 30); type = ".jpg"; //type = ".webp"; if (type == ".jpg") { params.push_back(CV_IMWRITE_JPEG_QUALITY); params.push_back(100); params.push_back(CV_IMWRITE_JPEG_OPTIMIZE); params.push_back(0); params.push_back(CV_IMWRITE_JPEG_PROGRESSIVE); params.push_back(0); } else if (type == ".webp") { params.push_back(CV_IMWRITE_WEBP_QUALITY); params.push_back(100); } // start server publisher = new ofxZmqPublisher(); publisher->setHighWaterMark(1); publisher->bind("tcp://*:9999"); } // start client subscriber = new ofxZmqSubscriber(); subscriber->setHighWaterMark(1); subscriber->connect("tcp://localhost:9999"); } //-------------------------------------------------------------- void testApp::update() { while (subscriber->hasWaitingMessage()) { subscriber->getNextMessage(recv_buf); image = cv::imdecode(recv_buf, CV_LOAD_IMAGE_COLOR); cout << "received data: " << recv_buf.size() << endl; } if (!cap.isOpened()) return; if (cap.grab()) { cap >> frame; int msec_start = ofGetElapsedTimeMillis(); bool ret = cv::imencode(type, frame, send_buf, params); int msec_stop = ofGetElapsedTimeMillis(); if (ret) { publisher->send(send_buf); int lap = msec_stop - msec_start; int fps = (lap) ? 1000.0 / lap : ofGetFrameRate(); cout << "encoded size(" << type << ") : " << send_buf.size() << ", time : " << lap << ", fps : " << fps << endl; } } } //-------------------------------------------------------------- void testApp::draw() { if (!image.empty()) { cv::imshow("image", image); } } //-------------------------------------------------------------- void testApp::keyPressed(int key) { } //-------------------------------------------------------------- void testApp::keyReleased(int key) { } //-------------------------------------------------------------- void testApp::mouseMoved(int x, int y) { } //-------------------------------------------------------------- void testApp::mouseDragged(int x, int y, int button) { } //-------------------------------------------------------------- void testApp::mousePressed(int x, int y, int button) { } //-------------------------------------------------------------- void testApp::mouseReleased(int x, int y, int button) { } //-------------------------------------------------------------- void testApp::windowResized(int w, int h) { } //-------------------------------------------------------------- void testApp::gotMessage(ofMessage msg) { } //-------------------------------------------------------------- void testApp::dragEvent(ofDragInfo dragInfo) { }
Core i7-4770S環境でJpegエンコードがおよそ10msec,出力データサイズが220kBytesでした。
WebPエンコードは、およそ60msecで、150kBytesでした。
WebPでQualityを70賭したときにはおよそ40msecで40kBytesでした。ストリーミングでも十分実用が見込めるぐらいの速さになってきました。
それぞれ、libjpeg-turboとMethod2でthreadを有効化したlibwebp1.5をOpenCVに静的リンクさせて使っています。