2017-08-14 86 views
0

我想发送一个OpenCV Mat通过TCP使用C++从树莓到我的Windows PC。 我的代码正在工作,它正在发送和获取帧,但是这些图像的灰度和质量都很差。如何发送OpenCV垫通过插座

客户端(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; 
} 

服务器端(树莓派):

#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你可以看到我的客户端如何得到的帧。

我不知道是什么导致了这个问题。 捕获框架后我是否缺少任何东西?

+0

对cv :: Mat进行序列化可能具有挑战性。你有没有考虑用PNG进行编码,然后通过网线发送并解压缩PNG? – Xvolks

+0

我不会指望'recv'中的'MSG_WAITALL'。更多阅读:https://stackoverflow.com/questions/12214356/winsock2-how-to-open-a-tcp-socket-that-allows-recv-with-msg-waitall – user4581301

回答

3

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

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

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

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

+0

你的意思是我应该这样做? :获取帧>将帧保存在磁盘上作为png> compress png> send png> ... –

+0

我已经从服务器发送了缓冲区,但是如何将该缓冲区转换为Mat对象?我的客户端代码:'recv(newsockfd,(char *)iptr,imgSize,MSG_WAITALL)''cv :: Mat aux = cv :: Mat(480,640,CV_8UC3,iptr);''cv :: Mat mat = cv :: imdecode(aux,0);''cv :: imshow(“VIDEO CLIENT”,mat);'这显示了一个完整的黑色框架 –

+0

@ E.Williams - 您将数据ptr从套接字直接传递到imdecode 。它知道图像数据的大小和格式,你不需要首先制作一个cv :: mat。 –