通过套接字发送 C++ OpenCV 图像

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20314524/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 23:03:00  来源:igfitidea点击:

C++ OpenCV image sending through socket

c++socketsopencvstreamingmat

提问by user2938976

I'm trying to implement a streaming service using OpenCV and sockets. The server side loads a given image and sends it to the client, which receives it through the socket and displays it. I'm having a lot of trouble, though, sending the data of the image and reconstructing it on the client side. This is the code I've made so far:

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

Image sender:

图片发件人:

#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;
}

Image receiver:

图像接收器:

#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; 
}

Al I receive on the client side is a black image, nothing else. Any help?

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

回答by Haris

Get Mat.dataand directly send to the socket, the data order is BGR BGR BGR.... On the receiving side assumes you know the size of image. After receiving just assign the received buffer(BGR BGR... array) to a Mat.

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

Client:-

客户:-

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))

Server:-

服务器:-

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;
    }
}

回答by user3165224

bytes = send(clientSock, frame.data, imgSize, 0));

This statement is giving error in Visual Studio 12.It say that.. ERROR: argument of type "uchar *" is incompatible with parameter of type "const char *" at ""frame.data"".

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

回答by Sida

Haris's answer is right and worked for me. However, instead of that server code (constructing image from uchar data), you can also use the shorter form:

哈里斯的回答是正确的,对我有用。但是,除了服务器代码(从 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);

回答by user5473110

In Microsoft Visual Studio 2012, I have a red line under imgSize in sockData[imgSize] saying expression must have a constant value. I then changed int imgSize to const int imgSize. It still shows me the same problem.

在 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];

回答by user5473110

Buffer overflow. And I am not sure that format and sizes of image are the same -> you should serialize your Mat honestly, something like here.

缓冲区溢出。而且我不确定图像的格式和大小是否相同-> 您应该诚实地序列化您的 Mat,例如此处的内容