1. 程式人生 > >基於Socket和OpenCV的實時視訊傳輸(On Windows)

基於Socket和OpenCV的實時視訊傳輸(On Windows)

目前由於專案的需要,實現了基於Socket和OpenCV的實時視訊傳輸。

由一臺PC(Client客戶端)採集攝像頭影象後經Socket傳輸到另一臺PC(Server伺服器)再顯示出來。

這一篇介紹在Windows上的實現,在下一篇講解在Linux上的實現。

環境:

Server: Windows 10 + OpenCV2.4.10 

Client:: Windows 10 + OpenCV2.4.10 

我採用的是TCP協議的通訊。

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、關閉監聽; 

我把影象的傳送和接收分別封裝在了兩個類中:

採集與傳送:

WinsockMatTransmissionClient.h

/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  基於OpenCV和Winsock的影象傳輸(傳送)
//	
//	By 彭曾 , at CUST, 2016.08.06 
//
//	website: www.pengz0807.com  email: 
[email protected]
// //M*/ #ifndef __WINSOCKMATTRANSMISSIONCLIENT_H__ #define __WINSOCKMATTRANSMISSIONCLIENT_H__ #include "opencv2/opencv.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/core/core.hpp" #include <stdio.h> #include <Winsock2.h> #pragma comment(lib,"WS2_32.lib") //待傳輸影象預設大小為 640*480,可修改 #define IMG_WIDTH 640 // 需傳輸影象的寬 #define IMG_HEIGHT 480 // 需傳輸影象的高 //預設格式為CV_8UC3 #define BUFFER_SIZE IMG_WIDTH*IMG_HEIGHT*3/32 struct sentbuf { char buf[BUFFER_SIZE]; int flag; }; class WinsockMatTransmissionClient { public: WinsockMatTransmissionClient(void); ~WinsockMatTransmissionClient(void); private: SOCKET 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

WinsockMatTransmissionClient.cpp

/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  基於OpenCV和Winsock的影象傳輸(傳送)
//	
//	By 彭曾 , at CUST, 2016.08.06 
//
//	website: www.pengz0807.com  email: [email protected] 
//	
//M*/


#include "WinsockMatTransmissionClient.h"


WinsockMatTransmissionClient::WinsockMatTransmissionClient(void)
{
}


WinsockMatTransmissionClient::~WinsockMatTransmissionClient(void)
{
}


int WinsockMatTransmissionClient::socketConnect(const char* IP, int PORT)
{
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;

	wVersionRequested = MAKEWORD( 1, 1 );

	err = WSAStartup( wVersionRequested, &wsaData );
	if ( err != 0 ) {
		return -1;
	}

	if ( LOBYTE( wsaData.wVersion ) != 1 ||
		HIBYTE( wsaData.wVersion ) != 1 ) {
			WSACleanup( );
			return -1;
	}

	err = (sockClient = socket(AF_INET,SOCK_STREAM,0));
	if (err < 0) {
		printf("create socket error: %s(errno: %d)\n\n", strerror(errno), errno);
		return -1;
	}
	else
	{
		printf("create socket successful!\nnow connect ...\n\n");
	}

	SOCKADDR_IN addrSrv;
	addrSrv.sin_addr.S_un.S_addr=inet_addr(IP);
	addrSrv.sin_family=AF_INET;
	addrSrv.sin_port=htons(PORT);

	err = connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
	if (err < 0) 
	{
		printf("connect error: %s(errno: %d)\n\n", strerror(errno), errno);
		return -1;
	}
	else 
	{
		printf("connect successful!\n\n");
		return 1;
	}
}


void WinsockMatTransmissionClient::socketDisconnect(void)
{
	closesocket(sockClient);
	WSACleanup();
}

int WinsockMatTransmissionClient::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 < 32; k++) 
	{
		int num1 = IMG_HEIGHT / 32 * k;
		for (int i = 0; i < IMG_HEIGHT / 32; 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 == 31)
			data.flag = 2;
		else
			data.flag = 1;

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

影象的接收與顯示:

WinsockMatTransmissionServer.h

/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  基於OpenCV和Winsock的影象傳輸(接收)
//	
//	By 彭曾 , at CUST, 2016.08.06 
//
//	website: www.pengz0807.com  email: [email protected] 
//	
//M*/

#ifndef __WINSOCKMATTRANSMISSIONSEVER_H__
#define __WINSOCKMATTRANSMISSIONSEVER_H__

#include "opencv2/opencv.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/core/core.hpp"
#include <stdio.h>
#include <Winsock2.h>

#pragma comment(lib,"WS2_32.lib")

//待傳輸影象預設大小為 640*480,可修改
#define IMG_WIDTH 640	// 需傳輸影象的寬
#define IMG_HEIGHT 480	// 需傳輸影象的高
//預設格式為CV_8UC3
#define BUFFER_SIZE IMG_WIDTH*IMG_HEIGHT*3/32

struct recvbuf
{
	char buf[BUFFER_SIZE];
	int flag;
};

class WinsockMatTransmissionServer
{
public:
	WinsockMatTransmissionServer(void);
	~WinsockMatTransmissionServer(void);

private:
	SOCKET sockConn;
	struct recvbuf data;

public:

	// 開啟socket連線
	// params :	PORT	傳輸埠
	// return : -1		連線失敗
	//			1		連線成功
	int socketConnect(int PORT);


	// 傳輸影象
	// params : image	待接收影象
	// return : -1		接收失敗
	//			1		接收成功
	int receive(cv::Mat& image);


	// 斷開socket連線
	void socketDisconnect(void);
};

#endif
WinsockMatTransmissionServer.cpp
/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  基於OpenCV和Winsock的影象傳輸(接收)
//	
//	By 彭曾 , at CUST, 2016.08.06 
//
//	website: www.pengz0807.com  email: [email protected] 
//	
//M*/


#include "WinsockMatTransmissionServer.h"


WinsockMatTransmissionServer::WinsockMatTransmissionServer(void)
{
}


WinsockMatTransmissionServer::~WinsockMatTransmissionServer(void)
{
}


int WinsockMatTransmissionServer::socketConnect(int PORT)
{
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;

	wVersionRequested = MAKEWORD(1, 1);

	err = WSAStartup(wVersionRequested, &wsaData);

	if (err != 0)
	{
		return -1;
	}

	if (LOBYTE(wsaData.wVersion) != 1 ||
		HIBYTE(wsaData.wVersion) != 1)
	{
		WSACleanup();
		return -1;
	}

	SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);

	SOCKADDR_IN addrSrv;
	addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_port = htons(PORT);
	bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
	listen(sockSrv, 5);

	SOCKADDR_IN addrClient;
	int len = sizeof(SOCKADDR);
	sockConn = accept(sockSrv, (SOCKADDR*)&addrClient, &len);

	int nRecvBuf = 1024 * 1024 * 10;
	setsockopt(sockConn, SOL_SOCKET, SO_RCVBUF, (const char*)&nRecvBuf, sizeof(int));
}


void WinsockMatTransmissionServer::socketDisconnect(void)
{
	closesocket(sockConn);
}

int WinsockMatTransmissionServer::receive(cv::Mat& image)
{
	cv::Mat img(IMG_HEIGHT,IMG_WIDTH,CV_8UC3,cv::Scalar(0));

	int needRecv = sizeof(recvbuf);
	int count = 0;

	while (1)
	{
		for (int i = 0; i < 32; 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");
					return -1;
				}
				pos += len0;
			}

			count = count + data.flag;

			int num1 = IMG_HEIGHT / 32 * i;
			for (int j = 0; j < IMG_HEIGHT / 32; 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 == 33)
				{
					image = img;
					return 1;
					count = 0;
				}
				else
				{
					count = 0;
					i = 0;
				}
			}
		}
	}
}


示例程式碼:

採集與傳送:

SocketClientMat.cpp

/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  基於OpenCV和Winsock的影象傳輸(傳送)
//	
//	By 彭曾 , at CUST, 2016.08.06 
//
//	website: www.pengz0807.com  email: [email protected] 
//	
//M*/



#include "WinsockMatTransmissionClient.h"

int main()
{
	WinsockMatTransmissionClient socketMat;
	if (socketMat.socketConnect("192.168.1.101", 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;
}

接收與顯示:

WinsockServerMat.cpp

/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  基於OpenCV和Winsock的影象傳輸(接收)
//	
//	By 彭曾 , at CUST, 2016.08.06 
//
//	website: www.pengz0807.com  email: [email protected] 
//	
//M*/




#include "WinsockMatTransmissionServer.h"

int main()
{
	WinsockMatTransmissionServer 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;
}

將在下一篇文章中講解Linux中基於Socket和OpenCV的實時視訊傳輸的實現。

相關推薦

基於SocketOpenCV實時視訊傳輸On Windows

目前由於專案的需要,實現了基於Socket和OpenCV的實時視訊傳輸。 由一臺PC(Client客戶端)採集攝像頭影象後經Socket傳輸到另一臺PC(Server伺服器)再顯示出來。 這一篇介紹在Windows上的實現,在下一篇講解在Linux上的實現。 環境: S

視訊傳輸】二、Opencv結合socket進行視訊傳輸TCP協議

        博文由來:筆者突發奇想,做採集4個USB攝像頭畫面小實驗時,卻遇到了在電腦上最多隻能同時開啟3個這樣頭痛的問題(個人分析認為是電腦的問題),故出此下策,在客戶端掛1個,伺服器掛3個攝像頭,利用socket進行視訊傳輸,本篇文章是利用的是TCP協議。筆者拙見,

基於RTPAndroid的視訊傳輸的研究實現方法

1.安徽大學電腦科學與技術學院,安徽合肥230039;2.安徽大學計算智慧與訊號處理教育部重點實驗室,安徽合肥230039;3.安徽大學軟體學院,安徽合肥230039) 中國論文網 http://www.xzbu.com/8/view-2388338.htm   摘要:該

opencv視訊疊加控制檯版

//#include "stdafx.h" #include <iostream> #include <cv.h> //#include <cxcore.h> #include <cxcore.h> #in

Windows基於TCP協議的大檔案傳輸流形式

在TCP下進行大檔案傳輸,不像小檔案那樣直接打包個BUFFER傳送出去,因為檔案比較大可能是1G,2G或更大,第一效率問題,第二TCP粘包問題。針對服務端的設計來說就更需要嚴緊些。下面介紹簡單地實現大檔案在TCP的傳輸應用。 粘包出現原因:在流傳輸中出現,UDP不會出現粘包,因為它有訊息邊界(參考Wi

在IntelliJ IDEA中同步程式碼到華為雲git倉庫 on windows 續 -- 配置好正確的SSH key

不管是以華為雲還是以github作為託管平臺,都有會用到SSH或是Https。最近在用華為雲,遇到了些問題,比較low的問題,特此記錄下。 華為雲上在新建SSH金鑰頁面有一段關於SSH的介紹,我覺得寫的挺好的: SSH金鑰幫助文件 公鑰是程式碼託管服務(

在IntelliJ IDEA中同步程式碼到華為雲git倉庫 on windows

在IntelliJ IDEA中同步程式碼到華為雲程式碼倉庫和同步到github中差不多,只是兩個不同的程式碼託管平臺,公司現在讓把原始碼放到華為雲上,捯飭了一會,捋一下步驟。 假如你在IDEA中建立了一個maven專案,叫ideaToHuaWeiCloud,並

基於Python3.7opencv的人臉識別含資料收集,模型訓練

前言 第一次寫部落格,有點緊張和興奮。廢話不多說,直接進入正題。如果你渴望使你的電腦能夠進行人臉識別;如果你不想了解什麼c++、底層演算法;如果你也不想買什麼樹莓派,安裝什麼幾個G的opencv;如果你和我一樣是個還沒入門的小白,但是想體驗一下人臉識別的魅力。那麼恭喜你,這篇文章就是為你準備的。讓我們開始吧

基於opencv視訊傳輸

#include "StdAfx.h" #include "WinsockMatTransmissionClient.h" WinsockMatTransmissionClient::WinsockMatTransmissionClient(void) { } WinsockMatTransmissi

mysql5.7:mysql安裝基於SSL加密的主從復制詳細剖析

mysql ssl db 數據 加密傳輸 小生博客:http://xsboke.blog.51cto.com 小生 Q Q:1770058260 -------謝謝您的參考,如有疑問,歡迎交流目錄:--------my

Python-基於socketselect模塊實現IO多路復用

con style 不同 使用 encoding 但是 通過 append 出現 ‘‘‘IO指的是輸入輸出,一部分指的是文件操作,還有一部分網絡傳輸操作,例如soekct就是其中之一;多路復用指的是利用一種機制,同時使用多個IO,例如同時監聽多個文件句柄(socket對象一

基於FFmpeg OpenGL 的視訊播放 【C++】

環境: GLFW版本為 2.7.9 GLM版本為 0.9.4.6(需自己編譯生成 dll 和 lib) OpenGL 3.+ 以下程式碼僅僅通過ffmpeg解碼視訊(沒有處理音訊流),然後通過OpenGL進行顯示(或通過Shader對視訊幀進行處理)

基於MFCOpenCV的攝像機定標與立體匹配測試程式

最近整理了一下這兩年一直在用的攝像機定標與立體匹配測試程式,將程式碼進行了重構,介面也做了調整,分享出來方便有需要的朋友使用。當然我的程式設計能力有限,程式可能還有各種bug,請大家多多包涵。相關問題歡迎留言或email聯絡討論,謝謝!  =========

VC++6.0下基於MFC框架利用CInternetSessionCHttpFile獲取網頁資料附程式碼

例:從網站http://qq.ip138.com/weather/guangdong/GuangZhou.htm獲取近三天的日期、天氣、溫度、風向,程式碼如下: //新增標頭檔案 #include <afxinet.h> //獲取網路資料 void CSensorSysDlg:

[原始碼和文件分享]基於QtOpenCV實現彩色圖灰度圖的轉換

一、實驗目的與要求 1.1 目的 熟悉Qt視覺化開發,理解C++的面向物件思想 熟悉Qt和Opencv開發環境搭建 瞭解Qt訊息機制 初步理解Opencv的用法 學會使用c++異常處理 1.2 要求 使用Qt編寫一程式,點

LFTP Project Report——基於UDP實現TCP大檔案傳輸Python

LFTP Project Report 中山大學 資料科學與計算機學院 軟體工程(計算機應用方向) 16340132 樑穎霖 一.專案要求 Please choose one of following programing languages: C, C++,

基於socket多執行緒的聊天程式設計與實現

【要求】 1. 設計一款多人聊天程式,包括伺服器端和客戶端; 2. 伺服器先執行,自動獲取IP,建立socket並繫結在2017埠; 3. 客戶端通過IP地址連線伺服器端,由argv[1]提供IP地址,回車後提示輸入暱稱,然後登入伺服器; 4. 

基於C++OpenCv的SIFT_影象區域性特徵檢測演算法程式碼的實現

SIFT:尺度不變特徵變換匹配演算法詳解 本章將要講解的內容如下所示:    1)SIFT演算法的簡介    2)SIFT演算法的實現細節    3)SIFT演算法的應用領域    4)SIFT演算法的改進與擴充套件 一 SIFT演算法的簡介   1)傳統的特徵提取方法 成

基於Faster RCNN的實時視訊檢測

搞了三個星期,花了將近50G手機流量,終於把這個弄出來了。用faster實時檢測行人,17年初的時候,當時自己正在學習DL,發現有人就做出了這個,可以實時監測到人和車輛等各種物體,一直很好奇是如何做到的,前期已經完成了基於faster的相關圖片檢測任務,最近又要要求搞實時的視

C# 利用 OpenCV 進行視訊捕獲 筆記

簡介 這個專案是關於如何從網路攝像頭或者視訊檔案(*.AVI)中捕獲視訊的,這個專案是用C#和OPENCV編寫的。 這將有助於那些喜歡C#和OpenCV環境的人。這個程式完全基於Visual Studio 2010 version C#.NET環境。這個程式展示了怎樣用C#.NET環境的Visual Stu