通过套接字发送 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
C++ OpenCV image sending through socket
提问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.data
and 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];