Github项目分析: socket_opencv(客户端)

项目来自: 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); 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值