基於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的實時視訊傳輸的實現。
相關推薦
基於Socket和OpenCV的實時視訊傳輸(On Windows)
目前由於專案的需要,實現了基於Socket和OpenCV的實時視訊傳輸。 由一臺PC(Client客戶端)採集攝像頭影象後經Socket傳輸到另一臺PC(Server伺服器)再顯示出來。 這一篇介紹在Windows上的實現,在下一篇講解在Linux上的實現。 環境: S
【視訊傳輸】二、Opencv結合socket進行視訊傳輸(TCP協議)
博文由來:筆者突發奇想,做採集4個USB攝像頭畫面小實驗時,卻遇到了在電腦上最多隻能同時開啟3個這樣頭痛的問題(個人分析認為是電腦的問題),故出此下策,在客戶端掛1個,伺服器掛3個攝像頭,利用socket進行視訊傳輸,本篇文章是利用的是TCP協議。筆者拙見,
基於RTP和Android的視訊傳輸的研究實現方法
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.7和opencv的人臉識別(含資料收集,模型訓練)
前言 第一次寫部落格,有點緊張和興奮。廢話不多說,直接進入正題。如果你渴望使你的電腦能夠進行人臉識別;如果你不想了解什麼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-基於socket和select模塊實現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對視訊幀進行處理)
基於MFC和OpenCV的攝像機定標與立體匹配測試程式
最近整理了一下這兩年一直在用的攝像機定標與立體匹配測試程式,將程式碼進行了重構,介面也做了調整,分享出來方便有需要的朋友使用。當然我的程式設計能力有限,程式可能還有各種bug,請大家多多包涵。相關問題歡迎留言或email聯絡討論,謝謝! =========
VC++6.0下基於MFC框架利用CInternetSession和CHttpFile獲取網頁資料(附程式碼)
例:從網站http://qq.ip138.com/weather/guangdong/GuangZhou.htm獲取近三天的日期、天氣、溫度、風向,程式碼如下: //新增標頭檔案 #include <afxinet.h> //獲取網路資料 void CSensorSysDlg:
[原始碼和文件分享]基於Qt和OpenCV實現彩色圖和灰度圖的轉換
一、實驗目的與要求 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