项目来自: socket_opencv
利用OpenCV和TCP传输视频数据
1.客户端:
(1) 头文件SocketMatTransmissionClient.h:
#ifndef __SOCKETMATTRANSMISSIONCLIENT_H__
#define __SOCKETMATTRANSMISSIONCLIENT_H__
#include "opencv2/opencv.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace cv;
//待传输图像默认大小为 640*480,可修改
#define IMG_WIDTH 640 // 需传输图像的宽
#define IMG_HEIGHT 480 // 需传输图像的高
#define PACKAGE_NUM 1
//默认格式为CV_8UC3
#define BUFFER_SIZE IMG_WIDTH*IMG_HEIGHT*3/PACKAGE_NUM
struct sentBuf
{
char head[2];
char buf[BUFFER_SIZE];
//int flag;
};
struct recvBuf
{
char head[2];
char buf[BUFFER_SIZE];
//int flag;
};
class SocketMatTransmissionClient
{
public:
SocketMatTransmissionClient(void);
~SocketMatTransmissionClient(void);
private:
int sockClient;
struct sentBuf data;
struct recvBuf data_r;
int needRecv;
int count;
public:
int socketConnect(const char* IP, int PORT);
int transmit(cv::Mat image);
int transmit_stop(void);
int receive(cv::Mat& image);
void socketDisconnect(void);
};
#endif
头文件中定义了一个类:
class SocketMatTransmissionClient
{
public:
SocketMatTransmissionClient(void);
~SocketMatTransmissionClient(void);
private:
int sockClient;
struct sentBuf data;
struct recvBuf data_r;
int needRecv;
int count;
public:
int socketConnect(const char* IP, int PORT);
int transmit(cv::Mat image);
int transmit_stop(void);
int receive(cv::Mat& image);
void socketDisconnect(void);
};
构造函数和析构函数都是私有数据成员:
SocketMatTransmissionClient::SocketMatTransmissionClient(void)
{
}
SocketMatTransmissionClient::~SocketMatTransmissionClient(void)
{
}
公共成员函数socketConnect(const char* IP, int PORT):
int SocketMatTransmissionClient::socketConnect(const char* IP, int PORT)
{
struct sockaddr_in servaddr;
if ((sockClient = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{ // 建立套接字, 套接字的描述符是类的私有数据成员
printf("create socket error: %s(errno: %d)\n",strerror(errno), errno);
return -1;
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
if(inet_pton(AF_INET, IP, &servaddr.sin_addr) <= 0)
{ // 将IP地址从文本形式转换为二进制形式
printf("inet_pton error for %s\n", IP);
return -1;
}
if (connect(sockClient, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
{ // 建立连接
printf("connect error: %s(errno: %d)\n", strerror(errno), errno);
return -1;
}
else
{
printf("connect successful!\n");
}
}
公共成员函数SocketMatTransmissionClient::socketDisconnect(void)
void SocketMatTransmissionClient::socketDisconnect(void)
{
close(sockClient);
}
公共成员函数SocketMatTransmissionClient::transmit(cv::Mat image)
int SocketMatTransmissionClient::transmit(cv::Mat image)
{
if(image.empty())
{
printf("empty image\n\n");
return -1;
}
if(image.cols != IMG_WIDTH || image.rows != IMG_HEIGHT || image.type() != CV_8UC3)
{
printf("the image must satisfy : cols == IMG_WIDTH(%d) rows == IMG_HEIGHT(%d) type == CV_8UC3\n\n", IMG_WIDTH, IMG_HEIGHT);
return -1;
}
data.head[0] = 'a';
data.head[1] = 'b';
for (int i = 0; i < IMG_HEIGHT; i++)
{
int num2 = i * IMG_WIDTH * 3;
uchar* ucdata = image.ptr<uchar>(i);
for (int j = 0; j < IMG_WIDTH * 3; j++)
{
data.buf[num2 + j] = ucdata[j];
}
}
if (send(sockClient, (char *)(&data), sizeof(data), 0) < 0)
{
printf("send image error: %s(errno: %d)\n", strerror(errno), errno);
return -1;
}
}
这里有必要注意CV_8UC3,位深8bit,3通道
注意这部分的代码:
data.head[0] = 'a';
data.head[1] = 'b';
for (int i = 0; i < IMG_HEIGHT; i++)
{
int num2 = i * IMG_WIDTH * 3;
uchar* ucdata = image.ptr<uchar>(i);
for (int j = 0; j < IMG_WIDTH * 3; j++)
{
data.buf[num2 + j] = ucdata[j];
}
}
接着就是发送数据了:
if (send(sockClient, (char *)(&data), sizeof(data), 0) < 0)
{
printf("send image error: %s(errno: %d)\n", strerror(errno), errno);
return -1;
}
看来之前还是小看了send()函数,这图像的数据量得有921600个字节了
公共成员函数SocketMatTransmissionClient::transmit_stop(void):
int SocketMatTransmissionClient::transmit_stop(void)
{
memset(&data,0,sizeof(data));
data.head[0] = 'c';
data.head[1] = 'd';
if (send(sockClient, (char *)(&data), sizeof(data), 0) < 0)
{
printf("send error: %s(errno: %d)\n", strerror(errno), errno);
return -1;
}
}
(2) Client.cpp:
#include "SocketMatTransmissionClient.h"
int main()
{
SocketMatTransmissionClient socketMat; // 定义类对象
if (socketMat.socketConnect("192.168.8.112", 6666) < 0)
{ // 建立连接,返回值小于0表示建立失败
return 0;
}
cv::VideoCapture capture(0);
capture.set(CV_CAP_PROP_FRAME_WIDTH, 640);
capture.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
cv::Mat image;
cv::Mat img_s;
cv::Mat img_r;
int key = -1;
while (1)
{
if (!capture.isOpened()) // 确认摄像头是否打开
return 0;
capture >> image; // 读取图像
cv::resize(image,img_s,cv::Size(640,480),(0, 0),(0, 0),cv::INTER_LINEAR);
if (img_s.empty())
return 0;
socketMat.transmit(img_s);
//printf("Client send!\n");
if(socketMat.receive(img_r) > 0)
{
cv::imshow("Client",img_r);
key = cv::waitKey(10);
if (key == 'q')
break;
}
else
{
printf("Client recv error!\n");
}
}
cv::destroyAllWindows();
socketMat.transmit_stop();
socketMat.socketDisconnect();
return 0;
}
注意这里要调整图像:
cv::resize(image,img_s,cv::Size(640,480),(0, 0),(0, 0),cv::INTER_LINEAR);