2017-08-14 106 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。 –