読者です 読者をやめる 読者になる 読者になる

kivantium活動日記

プログラムを使っていろいろやります

OpenCVでWebカメラのストリーミング

OpenCVWebカメラの映像をネットワーク越しに送受信するプログラムを書いてみました。
環境は送受信ともUbuntuです。

送信側プログラム

キャプチャ画像をjpg圧縮してUDPで送っています

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

#include <iostream>
#include <vector>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>

using namespace std;
using namespace cv;

int main(int argc, char *argv[]){
    //ソケットの設定
    int sock;
    struct sockaddr_in addr;

    sock = socket(AF_INET, SOCK_DGRAM, 0);

    addr.sin_family = AF_INET;
    addr.sin_port = htons(12345);  //ポート番号
    addr.sin_addr.s_addr = inet_addr("192.168.1.8"); //送信先IPアドレス

    //カメラの設定
    VideoCapture cap(0);
    cap.set(CV_CAP_PROP_FRAME_WIDTH, 640);
    cap.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
    if(!cap.isOpened()){
        cout << "Camera not Found!" << endl;
        return -1;
    }

    Mat frame;
    Mat jpgimg;
    static const int sendSize = 65500;
    char buff[sendSize];
    vector<unsigned char> ibuff;
    vector<int> param = vector<int>(2);
    param[0] = CV_IMWRITE_JPEG_QUALITY;
    param[1] = 85;

    while(cvWaitKey(1) == -1){
        cap >> frame;
        imencode(".jpg", frame, ibuff, param);
        if(ibuff.size() < sendSize ){
            for(int i=0; i<ibuff.size(); i++) buff[i] = ibuff[i];
            sendto(sock, buff, sendSize, 0, (struct sockaddr *)&addr, sizeof(addr));
            jpgimg = imdecode(Mat(ibuff), CV_LOAD_IMAGE_COLOR);
        }
        ibuff.clear();
    }
    close(sock);
}

受信側プログラム

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

#include <iostream>
#include <vector>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>

using namespace std;
using namespace cv;
int main() {
    int sock, numrcv;
    struct sockaddr_in addr;    
    sock = socket(AF_INET, SOCK_DGRAM, 0);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(12345);
    addr.sin_addr.s_addr = INADDR_ANY;
    bind(sock, (struct sockaddr *)&addr, sizeof(addr));

    cvNamedWindow("Receive", CV_WINDOW_AUTOSIZE);

    cv::Mat image = cv::Mat(480,640,CV_8UC3);
    static const int receiveSize = 65500;
    static char buff[receiveSize];

    vector<uchar> ibuff;
    while(cvWaitKey(1) == -1){
        while(cvWaitKey( 10 ) == -1){
            numrcv = recv(sock, buff, receiveSize, 0);
            for(int i=0; i<sizeof(buff) ; i++){
                ibuff.push_back((uchar)buff[i]);
            }
            if(numrcv == -1) break;
            image = imdecode(Mat(ibuff), CV_LOAD_IMAGE_COLOR);
            cv::imshow("Receive", image);
            ibuff.clear();
        }
    }
    close(sock);

    return 0;
}

結果

LAN内ではうまく送受信できたが、LAN外のコンピューターに送信すると遅延がひどくて使い物にならずそのうち固まってしまった。UDPで順番がバラバラになっているのが原因かもしれないが、LAN外で使う予定はないのでとりあえず放置しておく。