摄像头监控视频传输实现(C++)
配置
这里采用的是 VS2017
之前写过一个Python的版本
https://blog.csdn.net/a19990412/article/details/80930725
- 首先得先下载一下opencv,然后简单配置一下。别担心,这个步骤操作就点击下三下鼠标就好了(但是如果是想换一个安装路径什么的,可能会多一点点的 不过基本上非常简单。)
- 根据https://blog.csdn.net/a19990412/article/details/79768775 就可以完成配置了。
- 如果遇到问题了,请务必在评论取留言,或者是私信我。是看不出对方是什么qq头像之类的,没必要担心,我也认不出是谁。
文章目录
- 配置
- 实现
- 代码解释
- 解释下服务端的代码
- 解释下客户端的代码
- 图片和网络数据的转换工作
- 从Mat到数据包
- 运行方法
- IP地址获取
实现
服务器代码(就是那个用有摄像头的那个电脑要运行的代码)
- 要把下面这个代码中的
sockAddr.sin_addr.S_un.S_addr = inet_addr("192.168.199.222");
192.168.199.222
换成有摄像头的电脑自己的ip地址(不用担心 怎么获得ip地址,在最后,我会说了,其实非常简单的。)- 关闭这个文件的话,我这里只是设置了强制更新的。没有设置自己关掉的方法。
#include "opencv2/opencv.hpp"
#include <WinSock2.h>
#include <Windows.h>
#pragma comment (lib, "ws2_32.lib") //加载 ws2_32.dll
#pragma warning(disable : 4996)//待传输图像默认大小为 640*480,可修改
#define IMG_WIDTH 640 // 需传输图像的宽
#define IMG_HEIGHT 480 // 需传输图像的高
//默认格式为CV_8UC3
#define BUFFER_SIZE IMG_WIDTH*IMG_HEIGHT*3/32
using namespace cv;struct sentbuf{char buf[BUFFER_SIZE];int flag;
};
sentbuf data;
void sendMat(SOCKET sockClient, Mat image);int main(int, char**)
{VideoCapture cap(0); // open the default cameraif (!cap.isOpened()) // check if we succeededreturn -1;Mat frame;//初始化 DLLWSADATA wsaData;::WSAStartup(MAKEWORD(2, 0), &wsaData);//创建套接字SOCKET servSock = ::socket(AF_INET, SOCK_STREAM, 0);//绑定套接字sockaddr_in sockAddr;sockAddr.sin_family = AF_INET;sockAddr.sin_addr.S_un.S_addr = inet_addr("192.168.199.222");sockAddr.sin_port = htons(1234);::bind(servSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));//进入监听状态listen(servSock, 5);//接收客户端请求SOCKADDR clntAddr;int nSize = sizeof(SOCKADDR);SOCKET clntSock = accept(servSock, (SOCKADDR*)&clntAddr, &nSize);std::cout << "linked\n";for (;;){cap >> frame; // get a new frame from camerasendMat(clntSock, frame);}// the camera will be deinitialized automatically in VideoCapture destructor//关闭套接字closesocket(clntSock);closesocket(servSock);//终止 DLL 的使用WSACleanup();return 0;
}
void sendMat(SOCKET sockClient, Mat image) {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;elsedata.flag = 1;send(sockClient, (char *)(&data), sizeof(data), 0);}
}
客户端代码(就是那个要看摄像头内容的电脑要运行的代码)
- 注意: 要把下面的代码中ip地址换成上面的那个有摄像头的电脑的ip地址。
- 就是修改下面的这个代码
addr.sin_addr.S_un.S_addr = inet_addr("192.168.199.222");
- 把这个
192.168.199.222
换一下就好了~ - 关闭这个文件的话,我这里只是设置了强制更新的。没有设置自己关掉的方法(毕竟为了代码短,其实可以在任务管理器上,强制关闭)。
#include <opencv2/opencv.hpp>
#include <WinSock2.h>
#include <Windows.h>
#pragma comment (lib, "ws2_32.lib")
#pragma warning(disable : 4996)
using namespace cv;//待传输图像默认大小为 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;
};
recvbuf data_recv;
Mat recieveMat(SOCKET sockServer);
int main() {//初始化 DLLWSADATA data;WORD w = MAKEWORD(2, 0);::WSAStartup(w, &data);// 创建套接字SOCKET s;s = ::socket(AF_INET, SOCK_STREAM, 0);// 构造ip地址sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_addr.S_un.S_addr = inet_addr("192.168.199.222");addr.sin_port = htons(1234);std::cout << "connecting\n";::connect(s, (sockaddr*)&addr, sizeof(addr));std::cout << "linked\n";while (true) {Mat frame = recieveMat(s);if (frame.data) imshow("Camera", frame);if (waitKey(1) >= 0)break;}::closesocket(s);::WSACleanup();}Mat recieveMat(SOCKET sockServer) {Mat img(IMG_HEIGHT, IMG_WIDTH, CV_8UC3, cv::Scalar(0));int needRecv = sizeof(recvbuf);int count = 0;for (int i = 0; i < 32; i++) {int pos = 0;int len0 = 0;while (pos < needRecv) {len0 = recv(sockServer, (char*)(&data_recv) + pos, needRecv - pos, 0);pos += len0;}count = count + data_recv.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_recv.buf[num2 + k];}}if (data_recv.flag == 2) {if (count == 33) {return img;}else {count = 0;i = 0;}}}
}
代码解释
解释下服务端的代码
- 服务端的代码,就是指运行在有摄像头的那个电脑的代码。
- 一开始的三行都是导入头文件。(如果你之前配置好了opencv这里就是没有问题的)
- 第四行,导入了一个
winsock
的包,这个包,是为了使用网络通信技术 - 之后,就是定义了几个常量(IMG_WIDTH,IMG_HEIGHT,BUFFER_SIZE)就是定义了几个数而已。
using namespace cv;
是使用opencv
的名空间(这个意思就是说,使用什么作为关键字符,比如,之前cout,这是个关键字,但是,这个的名空间是std
)- 之后创建一个结构体,这个你可以参照Python中的类的概念。(如果你也没学过类的话,就把这个理解为一个盒子(然后,我们在这个盒子里面放东西),以后定义新的元素的时候(像以前定义int,double之类的东西的时候,这里就直接定义一个))
- 所以说,在定义完的下面就有一行,写着
sentbuf data;
。 - 之后的话,就是写了一个函数的声明(定义放在了下面)。原因这里要跟Python区别一下。 Python的话,函数放在一个文件里,那就是可以找到的,但是c++不一样,就是必须要在函数调用之前就有了才能调用的。
- 但是这样写就会很丑,所以我这里才会先写一个函数声明,最后再写函数定义。
- 进入到main函数(注意到,有些时候我是写了参数的
int, char**
。但是实际上,没区别的。。) VideoCapture
是一个摄像头类- 然后,来确定一下,是否是打开的,如果是打开的,就是继续。
- Mat(其实是一个矩阵)在这里是为了存一个图(这个矩阵不是二维的,其实是三维的,还多加了一堆东西的)
- 之后的,什么初始化DLL之类的。没关系,反正我也记不住。
- 但是这个,都很简单的,大致流程copy一下就好了。
- 重点在那个换ip地址的(是的,我现在还没告诉你怎么看ip地址)
accept(servSock, (SOCKADDR*)&clntAddr, &nSize);
函数,必须在,有其他ip地址来连接到这个上面之后,才会继续,否则,整个代码就会一直定在这。(所以,后面输出了那个linked 的时候,才表示连接成功了)- 一直到
for(;;)
就是创建一个无限循环,一直在读取摄像头的图片,然后用那个函数给发出去。 - 最后的关闭什么的 都是套路,顺着来就好了。
解释下客户端的代码
- 就是那个看另外一个电脑摄像头信息的电脑运行的代码。
- 讲道理,前面都是基本一模一样的。
- 区别在于
std::cout << "connecting\n";
之后,使用的是connect
函数,表示创立连接,并且,整个连接,就是通过s
这个SOCKET
来完成通信。 - 同样是,如果没连上就会一直停在这个,所以,后面输出的话,就会表示已经连上了。
- 然后
while (true)
同样是一种无限循环的表示方法一样。 - 还是通过,先读取一个图片,然后再展示出来。
图片和网络数据的转换工作
- 之前一直没讲这个,其实这个才是难点。
- 之前的结构体中,我们除了放了一个
char*
之外,我们还放了一个int
作为标签。(作用为:记录当前这个包是不是这个图片的最后一个包) - 做上面这样的处理的原因是,电脑发数据的时候,一次性不能发太大大数据,所以,就只能这样了。
从Mat到数据包
- 每个图片分32个包来发出去。
img.ptr<uchar>(j + num1);
这个()
内的数字,表示的是第多少行。(这里不妨假设为二维的,三维只是因为有彩色的)uchar
其实跟char
也没太的区别,就是变成了没有符号的char
而已。- 本质上,就是通过Mat函数本身的
ptr
(这是个指针(可以这么理解)来定位到一个串,直接丢给字符串数组就好了。) *3
表示的是有三通道。
反过来的操作是类似的。这里就做多描述了。
运行方法
- 一个电脑运行服务端代码(要求有摄像头)
- 一个电脑运行客户端代码(没有要求)
- 两台电脑在同一个局域网下(可以是连着同一个wifi的两台机器。(也可以是连着同一个路由器的两台电脑))
- 我测试过了。测试环境是
- 服务端:
Win10 + VS2017+ 摄像头
- 客户端:
Win10 + VS2017
IP地址获取
win键+R
- 出来运行框。把那个输入框(只有一个)的内容换成cmd,敲回车
- 出现一个黑框框
- 输入
ipconfig
敲回车
如果这台电脑是通过台式链接的
如果这台电脑是wifi链接的
就找这个带有
WLAN
字样的IPv4地址
- 这样的运行出来的东西就是可以用的啦~
- 希望能帮到你
摄像头监控视频传输实现(C++)相关推荐
- 使用flask获取树莓派摄像头监控视频
目录 1.安装flask库 2.使用flask打开网页传输视频 2.1 在树莓派终端桌面上,新建一个flask文件夹 2.2 在flask文件夹里面,新建一个template文件夹和app.py文件 ...
- 海康摄像头监控视频播放详解
2019.12.09 更新(重要!!!) 一,此博文及对应代码写于2018年初,基于海康SDK V5.3.3.2版本(当时最新版本),只适用于2019年前海康监控设备:(海康监控产品更新换代,旧版SD ...
- [转]GStreamer资料(摄像头采集,视频保存,远程监控)DVR
http://blog.csdn.net/wzwxiaozheng/archive/2010/12/26/6099397.aspx GStreamer资料整理(包括摄像头采集,视频保存,远程监控,流媒 ...
- GStreamer资料(摄像头采集,视频保存,远程监控)DVR
转载自:http://blog.chinaunix.net/uid-10747583-id-282761.html http://blog.csdn.net/wzwxiaozheng/archive/ ...
- 从零搭建树莓派远程监控小车,udp视频传输,qt上位机
目录 前言 一.材料准备 二.连线方式 三.软件编程 软件编程主要有一下几个方面 (1)树莓派视频传输 (2)esp8266代码 (3)上位机编程 四.总结 前言 最近刚准备完期末机器人驱动的课设,本 ...
- 使用手机摄像头实现视频监控实时播放
使用手机摄像头实现视频监控实时播放 一.概述 视频监控实时播放的原理与目前较为流行的直播是一致的,所以采用直播的架构实现视频监控实时播放,流程图如下: #mermaid-svg-mUiqq5ywjTx ...
- 如何实现摄像头监控数据实时存储及传输?
我们今天接到一个需求电话,是用户打电话向我们咨询方案,具体场景是这样的:需要用户对某个场景的监控数据进行访问,也就是监控摄像头拍摄到的,外网用户在我们的网站上都能看到,难点是怎么把摄像头监控的数据进行 ...
- 视频监控远程传输方案
一.市场需求和产品瓶颈的尴尬局面 远程视频传输 早期对于集成厂商来说需要解决太多的技术问题,还要购买昂贵的网络产品,高难度的技术调试门槛.国内的一线大厂开发了云平台,这样就造成了集成厂商的可选择性很小 ...
- Android 手机采集摄像头视频 socket 视频传输实时传播
这里搜集了两种实现Android 手机采集摄像头视频 socket 视频传输实时传播的方法,两种都可以使用. 第一种如下: 1.通过客户端socket请求,服务端接受到请求后,获取socket的输出流 ...
最新文章
- Windbg学习 (0x0013) 扩展命令-SOS
- stl中各种容器的自定义比较函数
- 简单工厂模式(Simple Factory)
- UML 中各种图形重要性的排行
- S3c2440A平台HIVE注册表+binfs的实现
- ZOJ3944People Counting暴力/枚举
- 设计世界上最小的 Arduino!
- ios之JavaScript
- 蓝桥杯代码测评使用指南
- “kuangbin带你飞”专题计划——专题一:简单搜索
- SQL注入语句(详细)
- MongoDB下载、安装和配置教程
- 深入理解二进制 算法必备底层知识
- Java扫码点餐小程序源码 SaaS系统源码 微信、支付宝扫码点餐小程序源代码
- linux下解压文件丢失文件,Linux下解压文件
- 百度离线地图开发,node实现地图瓦片下载
- 关于trunk的几个端口模式
- 0x000000f怎么修复 win10_0xc000000f修复引导win10步骤
- Javascript获取元素的xpath
- ACM:nbsp;polya定理+hashnbsp;数论题nbsp;pojnbsp;3…