如何通过套接字发送OpenCV Mat

时间:2017-08-14 21:41:32

标签: c++ sockets opencv serialization

我正在尝试使用来自覆盆子的c ++向我的Windows PC发送OpenCV Mat。 我的代码工作正在发送和获取帧,但是这些图像是灰度级的,质量非常差。

客户端(Windows):

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <string.h>
#include <sys/types.h>
#include <winsock2.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include "WS2tcpip.h"

#define bzero(b,len) (memset((b),'\0',(len)),(void)0)
#define bcopy(b1,b2,len) (memmove((b2),(b1),(len)),(void) 0)

using namespace std;

int main()
{
    int sockfd, newsockfd, portno;
    socklen_t clilen;
    struct sockaddr_in serv_addr, cli_addr;
    int n;

    // IMPORTANT
    WSADATA Data;
    WSAStartup(MAKEWORD(2, 2), &Data);
    ////////////

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        cout << "Error while opening socket"<<endl;
        return -1;
    }

    bzero((char*)&serv_addr,sizeof(serv_addr));
    portno = 5001;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);
    if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        cout << "Error while binding." << endl;
        return -1;
    }
    listen(sockfd, 5);
    clilen = sizeof(cli_addr);
    newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr,&clilen);

    if (newsockfd < 0) {
        cout << "Error while accepting socket" << endl;
        return -1;
    }

    cv::Mat img;
    img = cv::Mat::zeros(480, 640, CV_8UC1);
    int imgSize = img.total() * img.elemSize();
    uchar *iptr = img.data;
    int bytes = 0;

    if (!img.isContinuous()) {
        img = img.clone();
    }

    cout << "Img size: " << imgSize << endl;

    while (1) {
        if ((bytes = recv(newsockfd, (char *)iptr, imgSize, MSG_WAITALL)) == -1) {
            cout << "Error while recv frame" << endl;
            break;
        }
        cv::imshow("VIDEO CLIENT", img);
        cv::waitKey(30);
    }


    // IMPORTANT
    WSACleanup();
    //////////////

    return 0;
}

服务器端(Raspberry Pi):

#include <ctime>
#include <iostream>
#include <raspicam/raspicam_cv.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;

int main (int argc, char **argv){
 int sockfd,portno,n;
 struct sockaddr_in serv_addr;
 struct hostent *server;

 portno=5001;
 sockfd = socket(AF_INET,SOCK_STREAM,0);
 if(sockfd<0){
  cout << "Error while opening socket."<<endl;
  return -1;
 }else{
  cout << "Socket is now openned."<<endl;
 }
 server = gethostbyname("192.168.1.10");
 if(server ==NULL){
  cout << "Host does not exist."<<endl;
  return -1;
 }else{
  cout << "Valid host!"<<endl;
 }


 bzero((char *) &serv_addr,sizeof(serv_addr));
 serv_addr.sin_family = AF_INET;
 bcopy((char*)server->h_addr,
        (char *)&serv_addr.sin_addr.s_addr,
        server->h_length);
 serv_addr.sin_port = htons(portno);
 if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr))<0){
  cout << "Error while trying to connect."<<endl;
  return -1;
 }
 else{
  cout << "Connected!"<<endl;
 }
 raspicam::RaspiCam_Cv cam;
 cv::Mat image;
 image = cv::Mat::zeros(480,640,CV_8UC1);
 if (!image.isContinuous()){
  image = image.clone();
 }
 int imageSize = image.total()*image.elemSize();
 int bytes = 0;

 cout << "img size: " << imageSize << endl;

 cam.set(CV_CAP_PROP_FORMAT,CV_8UC1);

 cout << "Opening camera..."<<endl;
 if (!cam.open()){
  cout << "Error while opening camera." << endl;
  return -1;
 }
while(1){
 cout << "Capturing frame..." << endl;
 cam.grab();
 cam.retrieve(image);
 if(!image.empty()){
   if((bytes = send(sockfd,image.data,imageSize,0))<0){
     cout << "Error while sending..";
     break;
   }
   cout << "Frame sent sucessfuly" << endl;
   cout << bytes << " bytes sent." <<endl;
 }else{
  cout << "Frame was empty"<<endl;
  break;
 }
}
cout << "Stopping camera..."<<endl;
cam.release();
return 0;
}

Here您可以看到我的客户端如何获取帧。

我不知道造成这个问题的原因。 捕获框架后我遗漏了什么吗?

1 个答案:

答案 0 :(得分:5)

我不建议在计算机之间发送cv :: Mat - 特别是具有不同CPU架构,字节顺序,字长和内存填充的计算机。

将图像转换为非压缩(或无损压缩)格式,例如png并发送。

您可以使用cv::encode / cv:: decode在内存中创建图像格式,而无需读取/写入临时文件。

注意:imdecode根据图像格式(png,jpeg等)标题内的数据确定图像类型。接收者不需要知道大小或类型。