基于Socket和OpenCV的实时视频传输(On Linux)「建议收藏」

上一篇介绍了在Windows上实现基于Socket和openCV的实时视频传输,这一篇将继续讲解在Linux上的实现。环境:Server:Ubuntu14.04LTS+OpenCV2.4.10 Client:: Ubuntu14.04LTS+OpenCV2.4.10 我采用的仍是TCP协议的通信,Linux上的实现和Wind

大家好,又见面了,我是你们的朋友全栈君。

上一篇介绍了在Windows上实现基于Socket和openCV的实时视频传输,这一篇将继续讲解在Linux上的实现。

环境:

Server: Ubuntu 14.04 LTS + OpenCV2.4.10 

Client:: Ubuntu 14.04 LTS + OpenCV2.4.10 

我采用的仍是TCP协议的通信,Linux上的实现和Windows大同小异

Linux中OpenCV的编译安装可以参考 http://blog.csdn.net/pengz0807/article/details/49915573

TCP协议通信的一般步骤我再重新说一下:

客户端:

       1、创建一个socket,用函数socket(); 
  2、设置socket属性,用函数setsockopt();* 可选 
  3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选 
  4、设置要连接的对方的IP地址和端口等属性; 
  5、连接服务器,用函数connect(); 
  6、收发数据,用函数send()和recv(),或者read()和write(); 
  7、关闭网络连接;

服务器端:

       1、创建一个socket,用函数socket(); 
  2、设置socket属性,用函数setsockopt(); * 可选 
  3、绑定IP地址、端口等信息到socket上,用函数bind(); 
  4、开启监听,用函数listen(); 
  5、接收客户端上来的连接,用函数accept(); 
  6、收发数据,用函数send()和recv(),或者read()和write(); 
  7、关闭网络连接; 
  8、关闭监听; 

我把图像的发送和接收分别封装在了两个类中:

采集与发送:

SocketMatTransmissionClient.h

/*M///////  基于OpenCV和Socket的图像传输(发送)//	//	By 彭曾 , at CUST, 2016.08.07////	website: www.pengz0807.com  email: pengz0807@163.com //	//M*/#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 2//默认格式为CV_8UC3#define BUFFER_SIZE IMG_WIDTH*IMG_HEIGHT*3/PACKAGE_NUMstruct sentbuf{	char buf[BUFFER_SIZE];	int flag;};class SocketMatTransmissionClient{public:	SocketMatTransmissionClient(void);	~SocketMatTransmissionClient(void);private:	int sockClient;	struct sentbuf data;public:	// 打开socket连接	// params :	IP		服务器的ip地址	//			PORT	传输端口	// return : -1		连接失败	//			1		连接成功	int socketConnect(const char* IP, int PORT);	// 传输图像	// params : image 待传输图像	// return : -1		传输失败	//			1		传输成功	int transmit(cv::Mat image);	// 断开socket连接	void socketDisconnect(void);};#endif

SocketMatTransmissionClient.cpp

/*M///
//
//  基于OpenCV和Socket的图像传输(发送)
//	
//	By 彭曾 , at CUST, 2016.08.07 
//
//	website: www.pengz0807.com  email: pengz0807@163.com 
//	
//M*/


#include "SocketMatTransmissionClient.h"

SocketMatTransmissionClient::SocketMatTransmissionClient(void)
{
}


SocketMatTransmissionClient::~SocketMatTransmissionClient(void)
{
}


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) 
	{
		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");
	}
}


void SocketMatTransmissionClient::socketDisconnect(void)
{
	close(sockClient);
}

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;
	}

	for(int k = 0; k < PACKAGE_NUM; k++) 
	{
		int num1 = IMG_HEIGHT / PACKAGE_NUM * k;
		for (int i = 0; i < IMG_HEIGHT / PACKAGE_NUM; i++)
		{
			int num2 = i * IMG_WIDTH * 3;
			uchar* ucdata = image.ptr<uchar>(i + num1);
			for (int j = 0; j < IMG_WIDTH * 3; j++)
			{
				data.buf[num2 + j] = ucdata[j];
			}
		}

		if(k == PACKAGE_NUM - 1)
			data.flag = 2;
		else
			data.flag = 1;

		if (send(sockClient, (char *)(&data), sizeof(data), 0) < 0)
		{
			printf("send image error: %s(errno: %d)\n", strerror(errno), errno);
			return -1;
		}
	}
}

接收与显示:

SocketMatTransmissionServer.h

/*M///
//
//  基于OpenCV和Socket的图像传输(接收)
//	
//	By 彭曾 , at CUST, 2016.08.07
//
//	website: www.pengz0807.com  email: pengz0807@163.com 
//	
//M*/

#ifndef __SOCKETMATTRANSMISSIONSEVER_H__
#define __SOCKETMATTRANSMISSIONSEVER_H__

#include "opencv2/opencv.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

using namespace cv;

#define PACKAGE_NUM 2

#define IMG_WIDTH 640
#define IMG_HEIGHT 480

#define BLOCKSIZE IMG_WIDTH*IMG_HEIGHT*3/PACKAGE_NUM

struct recvBuf
{
	char buf[BLOCKSIZE];
	int flag;
};


class SocketMatTransmissionServer
{
public:
	SocketMatTransmissionServer(void);
	~SocketMatTransmissionServer(void);
	int sockConn;
private:
	struct recvBuf data;

	int needRecv;
	int count;

public:

	// 打开socket连接
	// params :	PORT	传输端口
	// return : -1		连接失败
	//			1		连接成功
	int socketConnect(int PORT);


	// 传输图像
	// params : image	待接收图像
	//		image	待接收图像
	// return : -1		接收失败
	//			1		接收成功
	int receive(cv::Mat& image);


	// 断开socket连接
	void socketDisconnect(void);
};

#endif

SocketMatTransmissionServer.cpp

/*M///////  基于OpenCV和Socket的图像传输(接收)//	//	By 彭曾 , at CUST, 2016.08.07 ////	website: www.pengz0807.com  email: pengz0807@163.com //	//M*/#include "SocketMatTransmissionServer.h"SocketMatTransmissionServer::SocketMatTransmissionServer(void){}SocketMatTransmissionServer::~SocketMatTransmissionServer(void){}int SocketMatTransmissionServer::socketConnect(int PORT){	int server_sockfd = socket(AF_INET,SOCK_STREAM, 0);	struct sockaddr_in server_sockaddr;	server_sockaddr.sin_family = AF_INET;	server_sockaddr.sin_port = htons(PORT);	server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);	if(bind(server_sockfd,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))==-1)	{		perror("bind");		return -1;	}	if(listen(server_sockfd,5) == -1)	{		perror("listen");		return -1;	}	struct sockaddr_in client_addr;	socklen_t length = sizeof(client_addr);	sockConn = accept(server_sockfd, (struct sockaddr*)&client_addr, &length);	if(sockConn<0)	{		perror("connect");		return -1;	}	else	{		printf("connect successful!\n");		return 1;	}		close(server_sockfd);}void SocketMatTransmissionServer::socketDisconnect(void){	close(sockConn);}int SocketMatTransmissionServer::receive(cv::Mat& image){	int returnflag = 0;	cv::Mat img(IMG_HEIGHT, IMG_WIDTH, CV_8UC3, cv::Scalar(0));	needRecv = sizeof(recvBuf);	count = 0;	memset(&data,0,sizeof(data));	for (int i = 0; i < PACKAGE_NUM; i++)	{		int pos = 0;		int len0 = 0;		while (pos < needRecv)		{			len0 = recv(sockConn, (char*)(&data) + pos, needRecv - pos, 0);			if (len0 < 0)			{				printf("Server Recieve Data Failed!\n");				break;			}			pos += len0;		}		count = count + data.flag;		int num1 = IMG_HEIGHT / PACKAGE_NUM * i;		for (int j = 0; j < IMG_HEIGHT / PACKAGE_NUM; j++)		{			int num2 = j * IMG_WIDTH * 3;			uchar* ucdata = img.ptr<uchar>(j + num1);			for (int k = 0; k < IMG_WIDTH * 3; k++)			{				ucdata[k] = data.buf[num2 + k];			}		}		if (data.flag == 2)		{			if (count == PACKAGE_NUM + 1)			{				image = img;				returnflag = 1;				count = 0;			}			else			{				count = 0;				i = 0;			}		}	}	if(returnflag == 1)		return 1;	else		return -1;}

示例代码:

图像的采集与发送:

SocketClientMat.cpp

#include "SocketMatTransmissionClient.h"

int main()
{
	SocketMatTransmissionClient socketMat;
	if (socketMat.socketConnect("127.0.0.1", 6666) < 0)
	{
		return 0;
	}
	
	cv::VideoCapture capture(0);
	cv::Mat image;

	while (1)
	{
		if (!capture.isOpened())
			return 0;

		capture >> image;

		if (image.empty())
			return 0;

		socketMat.transmit(image);
	}

	socketMat.socketDisconnect();
	return 0;
}

接收与显示:

SocketServerMat.cpp

#include "SocketMatTransmissionServer.h"

int main()
{
	SocketMatTransmissionServer socketMat;
	if (socketMat.socketConnect(6666) < 0)
	{
		return 0;
	}

	cv::Mat image;
	while (1)
	{
		if(socketMat.receive(image) > 0)
		{
			cv::imshow("",image);
			cv::waitKey(30);
		}
	}

	socketMat.socketDisconnect();
	return 0;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/129239.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 开通阿里云短信服务

    开通阿里云短信服务阿里云短信服务1,阿里云用户权限操作1.1、找到后台放在个人头像上面选择AccessKey管理1.2、选择子用户1.3、创建用户组1.4、给用户组添加权限然后就可以看到你的权限里面多了一个sms的短信权限1.5、创建用户注意!注意!注意点击确认后只可以看到一次密码返回就看不到了注意!注意!注意点击确认后只可以看到一次密码返回就看不到了注意!注意!注意点击确认后只可以看到一次密码返回就看不到了1.6、把用户加入到用户组2、开通阿里云短信服务

    2022年10月28日
  • WPF随笔(十)–使用AvalonDock实现可停靠式布局「建议收藏」

    WPF随笔(十)–使用AvalonDock实现可停靠式布局「建议收藏」许多软件都使用了可停靠式布局,可以方便的打开、关闭、收起、展开、移动选项卡。今天就来说明如何使用AvalonDock实现这种可停靠式布局。…

  • 关于高德地图标注的那些坑

    关于高德地图标注的那些坑关于高德地图标注的那些坑。先说一下自己遇到的问题:在地图加载完成后自动弹出自定义的标注点和气泡框,然后当点击气泡框的时候,可以直接响应气泡框上的Button事件。

  • 10.20卸载tensorflow2.0,安装tensorflow1.14.0

    10.20卸载tensorflow2.0,安装tensorflow1.14.0这里写自定义目录标题卸载tensorflow2.0安装1.14.0卸载tensorflow2.0安装1.14.0已安装python版本3.8.5,最开始误按装了tensorflow2.0,发现2.0和1.0版本语句不兼容,解决办法:tensorflow版本问题(1版本和2版本语句不兼容)当我们在tensorflow2.0版本上写的语句是1.0的格式时,可能会报错。这时只修改两条语句,就可以覆盖全部语句,不需要再担心。下面展示一些内联代码片。//Acodeblockvarfoo=

  • redis 客户端连接及常用命令使用[通俗易懂]

    redis 客户端连接及常用命令使用[通俗易懂]一、本地客户端连接[root@localhostredis]#bin/redis-cli127.0.0.1:6379>authrootOK显示”ok”表示连接成功常用命令操作redis的数据结构:redis存储的是:key,value格式的数据,其中key都是字符串,value有5种不同的数据结构value的数据结构:字符串类型string哈希类型hash:map格式列表类型list:linkedlist格式。支持重复元素集合类型set:不允

  • 机器学习框架及评估指标详解

    机器学习框架及评估指标详解目录机器学习的步骤train_test_split函数的详解机器学习评估指标分类模型评估指标混淆矩阵ROC曲线利用ROC的其他评估标准Python绘制ROC曲线求解AUC模板代码错误率精度查准率、查全率P-R曲线Python绘制P-R曲线模板代码平衡点(BEP)F1度量Python求解F1_score代码回归模型评估指标均方误差MAE(平均绝对误差)MAPE(平均绝对百分比误差)RMSE(均方根误差)RSquare(

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号