OpenCV结合socket进行实时视频传输(TCP协议)
来源:互联网 发布:约翰马尔科维奇 知乎 编辑:程序博客网 时间:2024/06/06 03:07
一、概述
内容:由Client客户端采集摄像头图像后经Socket传输到Server服务器端再显示出来。本实验在同一台电脑上实验,即运行服务器程序,又跑客户端程序,也就是说通过socket编程来实现数据的自发自收,这一步通过了接下来跑服务器和客户端分开的实验就简单了。
实验平台: VS2013 + opencv2.4.11(Windows 7)
说明:近期项目需要进行图像的采集传输任务,遂在网上寻找,并进行了些修改,记录在此。
二、实现
1、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、关闭监听;
2、Client 的实现(数据发送)
// Client.cpp 主函数// 基于OpenCV和Winsock的图像传输(发送)#include "WinsockMatTransmissionClient.h" int main(){ WinsockMatTransmissionClient socketMat; if (socketMat.socketConnect("192.168.191.1", 6666) < 0) //地址自行设置 { return 0; } cv::VideoCapture capture(0); cv::Mat frame; while (1) { if (!capture.isOpened()) return 0; capture >> frame; imshow("client", frame); cv::waitKey(30); if (frame.empty()) return 0; socketMat.transmit(frame); } socketMat.socketDisconnect(); return 0;}
数据的发送——WinsockMatTransmissionClient.h
// WinsockMatTransmissionClient.h// 基于OpenCV和Winsock的图像传输(发送)#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
// WinsockMatTransmissionClient.cpp// 基于OpenCV和Winsock的图像传输(发送)#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; } }}
3、Server 的实现(数据接收)
// Server.cpp 主函数// 基于OpenCV和Winsock的图像传输(接收)#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("server", image); cv::waitKey(30); } } socketMat.socketDisconnect(); return 0;}
数据的接收——WinsockMatTransmissionServer.h
// WinsockMatTransmissionServer.h// 基于OpenCV和Winsock的图像传输(接收)#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
// WinsockMatTransmissionServer.cpp// 基于OpenCV和Winsock的图像传输(接收)// 基于OpenCV和Winsock的图像传输(接收)#include <iostream>#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); //28804 int count = 0; extern int errno; 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; } } } }}
三、结果
Client端:
Server端:
- OpenCV结合socket进行实时视频传输(TCP协议)
- 【视频传输】二、Opencv结合socket进行视频传输(TCP协议)
- 【视频传输】一、Opencv结合socket进行视频传输(TCP协议)
- 基于socket(TCP)和opencv的实时视频传输
- 基于iOS的网络音视频实时传输系统(四)- 自定义socket协议(TCP、UDP)
- tcp+opencv 视频传输
- 基于Socket和OpenCV的实时视频传输(On Windows)
- 基于Socket和OpenCV的实时视频传输(On Linux)
- 实时视频传输协议RTP
- tcp+opencv 视频传输+raspberry
- 基于Socket和OpenCV的实时视频传输(On Windows ,Ubuntu,及Windows和Ubuntu之间) 总结
- 基于TCP协议的视频传输
- Android使用Socket(Tcp/Udp)协议进行数据传输(传输大文件)
- 基于Socket的Android手机视频实时传输
- 基于Socket的Android手机视频实时传输
- 基于Socket的Android手机视频实时传输
- 基于Socket的Android手机视频实时传输
- socket TCP协议 传输层中的滑动窗口协议
- 观察者模式
- java基础
- 生产者消费者模式
- 记忆化搜索之P1464 Function
- Spring入门介绍
- OpenCV结合socket进行实时视频传输(TCP协议)
- 线程基础/线程同步和互斥
- Atcoder Transit Tree Path
- istringstream用法
- 【 2017"百度之星"程序设计大赛
- 20170812
- uva 1572 Self-Assembly
- UIStepper
- 数字三角形--动态规划