利用Opencv提供的imencode和imdecode进行图像视频传输(发送端支持Linux和Windows双系统)

关于网络图像传输,网上大多数都是基于像素访问进行传输,传输的大小是图像的分辨率以及他的通道数,一般普通摄像头拍摄到图像大小的分辨率是640480,也就是说单通道灰度图像,一次要传输的数据量大小是640480=307200个字节,如果是彩色3通道那就是604803 = 921600个字节。90万的字节对网络资源的消耗是非常大,采用这种方式进行网络图像传输,容易造成视频的卡顿,所以不建议采用像素的访问进行传输。
Openc提供了imencode和imdecode两个函数,将图像进行二进制编码。https://docs.opencv.org/3.0-beta/modules/imgcodecs/doc/reading_and_writing_images.html这个是opencv官网对于图像读写的API做出了相应的介绍。我们先看一下imencode。

关于imencode与imdecode

C++: bool imencode(const String& ext, InputArray img, vector<uchar>& buf, const vector<int>& params=vector<int>())

参数:
ext-定义输出文件格式的扩展名
img-需要被编码的图像
buf-输出的缓存区,类型是vector
parms-被编码的格式和压缩率,类型是vector
prams目前支持以下参数:
JPEG,它的压缩率范围(cv_imwrite_jpeg_quality)从0到100(越大越好)。默认值是95。100为没有压缩。
对于WEBP来说,它的压缩范围(cv_imwrite_webp_quality)从1到100(越大越好)。默认情况下(不含任何参数)和质量在100以上,则使用无损压缩。
png,可以压缩级别(cv_imwrite_png_compression)从0到9。更高的值意味着更小的尺寸和更长的压缩时间。默认值是3。
PPM、PGM、或PBM,它可以是一个二进制格式的标志(cv_imwrite_pxm_binary),0或1。默认值是1。

然后看一下imdecode

C++: Mat imdecode(InputArray buf, int flags)
C++: Mat imdecode(InputArray buf, int flags, Mat* dst)

buf-输入解压的buf
flags-和imread()的flags是一样的
CV_LOAD_IMOSE_COLOR-如果设置,始终将图像转换为彩色图像
CV_LOAD_IMAGE_GRAYSCALE如果设置,始终将图像转换为灰度图像
dst -解码矩阵的可选输出占位符。不填则是NULL。

关于图像传输
图像传输利用socket套接字进行传输,有两种协议,这个是TCP协议一个是UDP协议。对于两种协议的采用哪种,我个人觉得UDP会更好一些。UDP不需要建立握手环节,在某些工程下减少了一些资源的开销。相反TCP协议需呀建立握手后才可以通信,一旦因为网络不好或者网络断开,就需要重新连接,需要一些时间和精力去处理这些琐事,同时也会消耗系统的资源。在网络不好时UDP存在的现象,无非使视频卡顿,而TCP则需重新连接。所以选择UDP是一个非常好的选择。

以下是UDP协议下利用imencode和imdecode的网络视频传输

接收端:

#define  _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <iostream>
#include <opencv2/opencv.hpp>  
#include <opencv2/imgproc/imgproc.hpp> 
#include <WinSock2.h>
#pragma comment(lib,"WS2_32.lib")

using namespace cv;
using namespace std;

enum
{
	PORT = 0x1234
};
int main(int argc, char** argv)
{
	WSADATA wsaData;
	WSAStartup(0x01, &wsaData); //创建初始化句柄

	SOCKET m_sockClient;
	if ((m_sockClient = socket(AF_INET, SOCK_DGRAM, 0)) < 0)    //创建socket句柄,采用UDP协议
	{
		printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
		return -1;
	}
	sockaddr_in m_servaddr;
	memset(&m_servaddr, 0, sizeof(m_servaddr));  //初始化结构体
	m_servaddr.sin_family = AF_INET;           //设置通信方式
	m_servaddr.sin_port = htons(PORT);         //设置端口号

	bind(m_sockClient, (sockaddr*)&m_servaddr, sizeof(m_servaddr));//绑定套接字
	Mat image;
	char buf[65536];
	while (true)
	{
		std::vector<uchar> decode;

		int n = recv(m_sockClient, buf, sizeof(buf), 0);//接受缓存
		int pos = 0;
		while (pos < n)
		{
			decode.push_back(buf[pos++]);//存入vector
		}
		buf[n] = 0;
		image = imdecode(decode, CV_LOAD_IMAGE_COLOR);//图像解码
		imshow("image", image);
		waitKey(30);
	}
	return 0;
}

发送端:

#ifdef _WIN32	
#define  _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#pragma comment(lib,"WS2_32.lib")
#else
#include <unistd.h>//Linux系统下网络通讯的头文件集合
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <malloc.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdarg.h>
#include <fcntl.h>
#include <fcntl.h>
#endif
#include <iostream>
#include <opencv2/opencv.hpp>  
#include <opencv2/imgproc/imgproc.hpp> 
using namespace cv;
using namespace std;

enum
{
	PORT = 0X4321
};
int main(int argc, char** argv)
{
#ifdef _WIN32
	WSADATA wsaData;
	WSAStartup(0x01, &wsaData); //创建初始化句柄
#endif
	int m_sockClient;
	if ((m_sockClient = socket(AF_INET, SOCK_DGRAM, 0)) < 0)    //创建socket句柄,采用UDP协议
	{
		printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
		return -1;
	}
	sockaddr_in m_servaddr;
	memset(&m_servaddr, 0, sizeof(m_servaddr));  //初始化结构体
	m_servaddr.sin_family = AF_INET;           //设置通信方式
	m_servaddr.sin_port = htons(PORT);         //设置端口号

	bind(m_sockClient, (sockaddr*)&m_servaddr, sizeof(m_servaddr));//绑定端口号
	VideoCapture capture(0);//打开摄像头
	Mat image;
	while (true)
	{
		capture >> image;//读入图片
		if (image.empty())    //如果照片为空则退出
		{
			printf("empty image\n\n");
			return -1;
		}
		std::vector<uchar> data_encode;
		std::vector<int> quality;
		quality.push_back(CV_IMWRITE_JPEG_QUALITY);
		quality.push_back(50);//进行50%的压缩
		imencode(".jpg", image, data_encode,quality);//将图像编码
		char encodeImg[65535];

		int nSize = data_encode.size();
		for (int i = 0; i < nSize; i++)
		{
			encodeImg[i] = data_encode[i];
		}
		m_servaddr.sin_addr.s_addr = inet_addr("192.168.1.102");
		m_servaddr.sin_port = htons(0x1234);//设置需要发送的IP和端口号
		sendto(m_sockClient, encodeImg, nSize, 0, (const sockaddr*)& m_servaddr, sizeof(m_servaddr));
		memset(&encodeImg, 0, sizeof(encodeImg));  //初始化结构体
	}
	return 0;
}

相关源码可以在此处下载:http://download.csdn.net/download/qq_37406130/10161435

  • 13
    点赞
  • 107
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值