【问题标题】:C++ OpenCV image sending through socketC++ OpenCV 图像通过套接字发送
【发布时间】:2013-12-17 08:21:20
【问题描述】:

我正在尝试使用 OpenCV 和套接字实现流服务。服务器端加载给定的图像并将其发送给客户端,客户端通过套接字接收并显示它。但是,我在发送图像数据并在客户端重建它时遇到了很多麻烦。这是我到目前为止所做的代码:

图片发件人:

#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/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

using namespace cv;
using namespace std;

void error(const char *msg)
{
    perror(msg);
    exit(0);
}

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

    char buffer[256];
    if (argc < 3) {
       fprintf(stderr,"usage %s hostname port\n", argv[0]);
       exit(0);
    }
    portno = atoi(argv[2]);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
        error("ERROR opening socket");
    server = gethostbyname(argv[1]);
    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }
    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) 
        error("ERROR connecting");

    Mat image;
    image = imread(argv[3], CV_LOAD_IMAGE_COLOR);
    if(! image.data )                              // Check for invalid input
    {
        cout <<  "Could not open or find the image" << std::endl ;
        return -1;
    }

    n = write(sockfd,image.data,image.total()*image.channels());
    if (n < 0) 
         error("ERROR writing to socket");
    close(sockfd);

    namedWindow( "Client", CV_WINDOW_AUTOSIZE );// Create a window for display.
    imshow( "Client", image );  
    waitKey(0);
    return 0;
}

图像接收器:

#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/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

using namespace cv;
using namespace std;

void error(const char *msg)
{
    perror(msg);
    exit(1);
}

int main(int argc, char *argv[])
{
     int sockfd, newsockfd, portno;
     socklen_t clilen;
     char buffer[1024];
     struct sockaddr_in serv_addr, cli_addr;
     int n;
     if (argc < 2) {
         fprintf(stderr,"ERROR, no port provided\n");
         exit(1);
     }
     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     if (sockfd < 0) 
        error("ERROR opening socket");
     bzero((char *) &serv_addr, sizeof(serv_addr));
     portno = atoi(argv[1]);
     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) 
              error("ERROR on binding");
     listen(sockfd,5);
     clilen = sizeof(cli_addr);
     newsockfd = accept(sockfd, 
                 (struct sockaddr *) &cli_addr, 
                 &clilen);
     if (newsockfd < 0) 
          error("ERROR on accept");
     bzero(buffer,1024);

     n = read(newsockfd,buffer,1023);
     if (n < 0) error("ERROR reading from socket");

     Mat image(690,690,CV_8UC3,*buffer);
     imwrite("/home/securitas/images/prova.jpg",image);
     close(newsockfd);
     close(sockfd);

     namedWindow( "Server", CV_WINDOW_AUTOSIZE );// Create a window for display.
     imshow( "Server", image );  
     waitKey(0);
     return 0; 
}

我在客户端收到的是黑色图像,没有别的。有什么帮助吗?

【问题讨论】:

    标签: c++ sockets opencv streaming mat


    【解决方案1】:

    获取Mat.data,直接发送到socket,数据顺序为BGR BGR BGR....接收端假设你知道图片的大小。接收后只需将接收到的缓冲区(BGR BGR...数组)分配给Mat

    客户:-

    Mat frame;
    frame = (frame.reshape(0,1)); // to make it continuous
    
    int  imgSize = frame.total()*frame.elemSize();
    
    // Send data here
    bytes = send(clientSock, frame.data, imgSize, 0))
    

    服务器:-

    Mat  img = Mat::zeros( height,width, CV_8UC3);
    int  imgSize = img.total()*img.elemSize();
    uchar sockData[imgSize];
    
    //Receive data here
    
    for (int i = 0; i < imgSize; i += bytes) {
        if ((bytes = recv(connectSock, sockData +i, imgSize  - i, 0)) == -1)  {
            quit("recv failed", 1);
        }
    }
    
    // Assign pixel value to img
    int ptr=0;
    for (int i = 0;  i < img.rows; i++) {
        for (int j = 0; j < img.cols; j++) {                                     
           img.at<cv::Vec3b>(i,j) = cv::Vec3b(sockData[ptr+ 0],sockData[ptr+1],sockData[ptr+2]);
           ptr=ptr+3;
        }
    }
    

    【讨论】:

    • 这拯救了我的一天。非常感谢,现在完美运行。不过,最后一个问题。在服务器端,我必须将“字节”初始化为某个值。我刚刚添加了 int bytes = 0;就在接收数据for循环之前。那正确吗?我的意思是,它有效,但我真的不知道它是否正确。再次感谢:D
    • 是的,你可以用 0 初始化,这不是问题。实际上字节用于检查 recv() 调用是否成功。成功完成后,recv() 将返回读取的消息长度(以字节为单位)。如果没有消息可以接收并且对等方已经执行了有序关闭,recv() 应该返回 0。否则,应该返回 -1。
    • 我强烈建议在通过套接字发送之前将数据编码为JPEGPNG。它可以显着减小尺寸(JPEG 10%,PNG 25%)
    • 所以最好编码成PNG不是吗?如果编码,是否应该进行整形?
    【解决方案2】:

    在 Microsoft Visual Studio 2012 中,我在 sockData[imgSize] 中的 imgSize 下有一条红线,表示表达式必须具有常量值。然后我将 int imgSize 更改为 const int imgSize。它仍然向我显示同样的问题。

     Mat img = Mat::zeros(100,100, CV_8UC3);
     const int imgSize = img.total()*img.elemSize();
     uchar sockData[imgSize];
    

    【讨论】:

      【解决方案3】:

      哈里斯的回答是正确的,对我有用。但是,除了服务器代码(从 uchar 数据构建图像)之外,您还可以使用更短的形式:

      int  imgSize = img.total()*img.elemSize();
      uchar sockData[imgSize];
      
      for (int i = 0; i < imgSize; i += bytes) {
          if ((bytes = recv(connectSock, sockData +i, imgSize  - i, 0)) == -1)
              quit("recv failed", 1);
      }
      
      // change the last loop to below statement
      Mat img(Size(HEIGHT, WIDTH), CV_8UC3, socketData);
      

      【讨论】:

        【解决方案4】:
        bytes = send(clientSock, frame.data, imgSize, 0));
        

        此语句在 Visual Studio 12 中给出错误。它说.. 错误:“uchar *”类型的参数与“const char *”类型的参数不兼容 在 ""frame.data"" 处。

        【讨论】:

          【解决方案5】:

          缓冲区溢出。而且我不确定图像的格式和大小是否相同 -> 你应该诚实地序列化你的 Mat,like here

          【讨论】:

          • 1024 还不够?或者你的意思是在发件人处?那我应该放什么? 9999999?
          猜你喜欢
          • 1970-01-01
          • 2013-03-24
          • 2013-12-31
          • 2011-04-11
          • 2010-10-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多