|
|
|
模块划分:
|
|
客户端:C --Qt开发界面--跨平台使用
|
|
统一的要求:
|
功能结构体:
|
请求结构体:
|
数据头--固定
|
数据体--不同模块,不一样
|
|
响应结构体:
|
数据头
|
数据体
|
|
举例:
|
enum TypeInfo
|
{
|
REGISTER_REQ, // 注册请求
|
REGISTER_RES, // 注册响应
|
};
|
|
struct Head // 通用
|
{
|
int type;
|
int len;
|
};
|
以注册为例:
|
|
|
struct RegisterReq
|
{
|
Head head;
|
|
char username[32];
|
char password[32];
|
char email[32];
|
char tel[32];
|
char department[32];
|
|
RegisterReq()
|
{
|
head.type = REGISTER_REQ;
|
head.len = sizeof(RegisterReq);
|
}
|
};
|
|
struct RegisterRes
|
{
|
Head head;
|
|
char username[32];
|
int status;
|
|
RegisterRes()
|
{
|
head.type = REGISTER_RES;
|
head.len = sizeof(RegisterRes);
|
}
|
};
|
|
3星 1、注册登录
|
注册:
|
输入信息:用户名、密码、确认密码、邮箱、手机号、部门
|
自动补充的信息:状态、注册时间、默认的权限--在服务端补充
|
|
校验:客户端本地校验:用户名、密码、合法字符的判断
|
邮箱、手机号格式的判断、两次密码比较是否一样
|
|
服务端二次校验:用户名、密码、合法字符的判断
|
服务端判断:用户名是否存在,不存在则写入[用户名唯一]
|
|
安全:密码加密的处理,防止明文传输和明文显示
|
加密算法:双向非对称加密 RSA 公钥--私钥:公钥加密,私钥解密
|
客户端:拿到公钥,加密,放到结构体里面传输密文
|
服务端:用私钥解密,得到密码明文
|
|
公钥、私钥的产生,是在服务端每次随机生成固定长度的一组密钥
|
将公钥发给对应的客户端,私钥在服务端留着用来解密密文
|
|
原始内容:123456
|
密钥:公钥 xxww99
|
加密算法:(2个参数:原始内容,密钥-公钥) --> 返回计算结果:密文:x8sdsdsaxxxxadsadsadsadsda889e21ess
|
|
密钥:私钥 uuyy84
|
将密文发给另一端之后,解密算法(2个参数:密文,密钥-私钥)--> 明文:123456
|
|
登录:
|
输入信息:用户名、密码、验证码[可选]
|
校验:客户端本地校验:用户名、密码、合法字符的判断
|
服务端二次校验:用户名、密码、合法字符的判断
|
安全:密码加密的处理,防止明文传输和明文显示
|
|
状态:成功--显示主界面--根据用户拥有的权限,来显示不同的子界面
|
失败--再次登录
|
|
UI美化:QSS样式美化
|
--------------------------------------------
|
数据库表:用户信息表、角色权限表
|
---------------------------------------------
|
|
|
|
5星 2、考勤识别、管理、异常处理
|
考勤识别:
|
AI识别,需要传入图片,将图片放到AI算法里面调用模型进行识别,返回所属的分类,通过分类ID获取数据库里面用户信息表中的用户信息,并且将信息展示到界面上。
|
|
获取图片:打开摄像头--获取一张有人脸的照片
|
OpenCV库来打开摄像头并获取人脸照片
|
|
服务端识别:客户端上传图片到服务端,调用服务端AI算法,返回识别结果
|
本地识别:需要在客户端机器上部署AI模型,将图片传入调用AI算法识别,拿到分类ID,再把ID发送给服务端,进行数据库查询,拿到查询结果,在客户端UI展示
|
|
识别:成功--要记录人脸打开信息:考勤信息表--用户名[id]、考勤时间、考勤设备id
|
失败--提示失败
|
|
管理:
|
查询--展示一个特定时间段的考勤统计结果
|
考勤判断:上班时间段--下班时间段
|
忘打卡--补打卡次数: 5次/月
|
|
异常处理:
|
考勤异常:迟到、早退、缺勤、请假-[细分....]
|
|
|
|
|
|
4星 3、权限管理
|
前提条件:管理员才能管理这个模块
|
管理: 先查询到特定用户,再点开特定用户的权限信息,对权限勾选/去勾选,最后提交修改,保存到服务端是数据库
|
|
界面:查询条件----用户名、工号、注册时间段、部门、邮箱、手机号等
|
查询结果展示----用二维表视图展示[MVD]
|
右击菜单--选择特定用户--修改权限、禁用用户[修改状态]
|
修改权限----显示当前选定用户拥有的权限[勾选√],没有的权限不勾
|
修改的话,对选项勾选或去勾选之后,提交修改
|
|
权限:有就是1,无就是0
|
admin 管理员
|
export 报表导出
|
log_search 日志查询
|
img_in 图像录入
|
map_mark_change 地图标注修改
|
history 历史回放、历史查询
|
warning_man 警报管理
|
device_man 设备管理
|
version_man 客户端版本管理
|
|
数据库表:
|
id 角色名 具体的权限...【9个】
|
|
|
5星 4、客户端版本更新
|
更新方式:增量更新、全量更新
|
增量更新:逐版本更新
|
全量更新:某个版本的完整更新,就是整个安装包
|
|
更新逻辑:比较版本--最新[不更新]
|
--不是最新--更新--比较要要更新文件的大小--选择更新方式
|
|
增量更新: 循环操作: 当前版本--找到下一个版本要更新的文件--下载--覆盖到客户端本地目录--完成更新--再接着比较版本...
|
|
全量更新:下载最新版的完整安装包,安装到本地即可
|
|
核心:
|
文件传输--大文件--要支持 断点续传--记录一些传输的信息--确认断点位置--续传
|
|
数据库表: 版本信息表--读取
|
id 当前版本号 依赖版本号[前置版本] 文件名 文件大小 文件MD5 文件S端路径 文件C端路径[相对路径] 状态 产生时间
|
|
传输记录表[可选]
|
|
界面: 更新进度展示:进度条、详细信息罗列...
|
|
更新程序:和主程序要相互独立
|
update.exe client.exe
|
|
版本如何记录?
|
配置文件来记录,可以是 version.ini 或 version.xml
|
|
|
3星 5、报表导出
|
逻辑:提前数据[日志、历史...]--导出到文件: 文档、表格[csv,xlsx]、pdf
|
、html--保存到本次磁盘
|
|
一、提供接口,让别的模块传参调用
|
二、用列表展示已经导出的记录,可预览相应的文件
|
|
|
|
5星 6、实时播放
|
逻辑:客户端先获取所有可查看的摄像头信息,形成一个菜单配置[1-4-9-16-25]
|
然后在根据播放视图选择,组合菜单配置形成播放的实时画面
|
|
播放:要给选好的画面连接,进行多线程的拉流处理--RTSP协议--FFmpeg
|
--拉流过来之后:解码形成图片--在标签上显示
|
|
数据库表:
|
摄像头信息--设备信息表--会包含每个摄像头的url[网址]
|
|
数据流:H.265压缩内容,200倍的压缩比,要解压--解码
|
在三方库中已经完成了:FFmpeg库
|
|
有2部分的东西:
|
1、常规业务
|
查询请求--拿到所有可用摄像头的信息
|
请求:只需要指定结构体头里面的功能类型值就行
|
struct RealtimeShowReq
|
{
|
Head head;
|
RealtimeShowReq()
|
{
|
head.type = xx; // xx为提前定好的枚举变量
|
head.len = sizeof(RealtimeShowReq);
|
}
|
};
|
|
响应:回一个摄像头信息[柔性数组]的响应
|
struct VideoInfo
|
{
|
int id;
|
char url[256]; // 拼接好的摄像头网址 协议://ip:port/1/last.ts
|
// ...
|
};
|
|
struct RealtimeShowRes
|
{
|
Head head;
|
VideoInfo vi[0]; // 柔性数组
|
};
|
|
2、视频业务
|
用FFmpeg去拉rtsp url的地址流数据过来,用FFmpeg来解压缩、解码就行
|
|
|
|
|
3星 7、系统设置
|
客户端的设置:
|
样式控制:字体、颜色、外观调整
|
国际化的显示:中文、英文、法文...
|
快捷键:
|
自启动的服务:开机启动
|
自动登录:要记录用户名、密码[加密记录]
|
......
|
|
如何生效:将配置信息保存到xml文件中,启动时加载设置
|
|
|
3星 8、日志查询
|
查询条件:级别、时间段等
|
|
显示结果:用表格显示[MVD的视图]、分页显示--分页算法-将结果分成更小的块来显示,提升性能
|
1 2 3 ... 98 99 100 跳转__页[下拉框/编辑框]
|
|
导出:调用报表导出接口
|
|
|
4星 9、图像录入
|
用于训练模型,每个新员工都需要采集一些特定数量的图片来训练,训练完了之后,用于识别--考勤等
|
|
逻辑:客户端--先把要录入的员工工号输入--确认工号信息正确--再点开摄像头--获取该员工特定数量、视角的照片--上传到服务端特定目录下保存--用于模型训练
|
|
界面:
|
通过输入工号--获取员工信息--显示--通过操作员判断正确否
|
点一下录入按钮:就会提示分别路哪些视角:正脸、侧脸、眨眼、张嘴等
|
每个录完之后,用标签显示一下录到的照片--预览
|
确认无误--提交--上传到服务器特定工号目录保存--同时记录到数据库表
|
|
数据库表:图片信息表:id、图片名字、路径、所属工号、上传时间、是否已训练...
|
|
|
5星 10、地图标注-摄像头、设备
|
特殊的地方:编译器得使用MSVC的编译器,才能支持浏览器的绘制
|
通过绘制的浏览器,加载百度在线地图
|
标注:设备的坐标[经度、纬度],设备名称、编号、状态等显示出来
|
|
核心:
|
QT 和 网页的JS要交互,使用信号槽来交互
|
用到的技术 webchannal.js
|
需要额外掌握:HTML、JS代码的编写 [会C/C++,必然能秒懂]
|
|
逻辑:
|
显示地图的标注点--去查询设备的经纬度--拿到所有可用设备经纬度--标记到网页地图里
|
|
修改标注点:改状态、改名字、调整经纬度等
|
|
数据库表:
|
设备信息表 要经度、维度 名字 id 状态 等
|
|
|
|
5星 11、历史回放、历史数据查询分析
|
历史回放 -- 回放的是视频内容
|
查询特定时间段、特定设备类型、编号---拿到了特定时间段内的视频文件url
|
----使用FFmpeg对【RTSP】url 进行拉流--解码显示
|
|
操作:
|
截图--保存某一帧图片
|
快进、后退、暂停、播放等控制视频的操作
|
|
历史数据查询分析 -- 查看的是环境信息的历史数据
|
需要指定查询条件--时间段、设备等--拿到历史数据--展示到二维表
|
--分析[日、周、月、年]:最小值、最大值、平均值、中位数--形成图形、曲线
|
--用到QChart库,或者三分库 QCustomPlot来显示更多数据量的图形
|
|
结构体里面如何表示内容每次查询都不一样,但是都能拿到:用不定长结构体[柔性数组]
|
|
数据库表: 视频信息表、环境信息表......
|
|
5星 12、实时环境信息展示
|
逻辑: 得用一个大屏来实时显示环境信息
|
分不同区域来显示,还可以显示别的数据到大屏里面来
|
主要是环境信息[温度、湿度、粉尘浓度、施工进度等]
|
其他信息:看一下小地图、看一下考勤情况、动态切换一下监控摄像头情况
|
跟具体模块负责人对接,要接口就行
|
|
实时环境信息:现场的各种传感器采集而来
|
测试环境--可以模拟数据发送过来
|
|
实时信息:通过硬件上传数据之后,到服务端了,给所有在线的客户端转发的
|
|
数据库表: 环境信息表:id 设备id 温度 适度 粉尘浓度
|
施工进度表:id 施工类型 预计工作量 当前完成量 时间 ...
|
|
真假实时:转发为真,轮询为假
|
|
|
4星 13、警报管理
|
针对哪些做出警报的判断?
|
温度、湿度、粉尘浓度、施工进度等
|
|
要对特定指标进行阈值的管理:可以动态调整阈值--最大、最小值
|
|
发生了警报,怎么处理?
|
1、预警--硬件端先触发声、光警报,接着软件部分会给所有在线客户端提示预警信息
|
2、解决--控制现场设备,自动调节--失败了--给值班室派单--解决问题
|
|
数据库表:
|
阈值信息表、警报信息表
|
|
界面:
|
管理阈值的界面--先查询-再修改
|
显示警报的界面--要在主窗口中,所有子模块都能同时看见的位置显示
|
|
如何触发:
|
数据到了服务端之后,除了实时转发的操作,还要一个预警判断的操作
|
发生异常了,同时记录到警报信息表,且给所有在线客户端转发警报提示
|
|
|
3星 14、设备管理
|
设备:摄像头、硬盘录像机、各种工地的设备[资产管理的]
|
对设备进行增删改查
|
添加:新设备--录入信息--对于外露固定位置的设备,要有安装位置的经纬度
|
|
删除:修改设备状态--废弃、不可用、维修、正常
|
改:修改已经录入的信息
|
查询:查看都有哪些设备
|
|
数据库表:设备信息表
|
id 设备类型 名字 序列号 状态 安装时间 经度 维度 负责人
|
|
|
|
服务端:S
|
|
5星 1、网络搭建、TCP、UDP实现
|
确定并发量:1000--5000的并发量来设置
|
select + 线程池
|
最终的服务端:在linux平台下运行--Ubuntu 20.3--也可以使用epoll来处理高并发
|
|
解耦操作:
|
把业务当任务处理,要写一个通用的任务类来表示不同的业务
|
|
线程池的实现:先考虑使用C++实现--鸿蒙系统的线程池
|
|
还需要确定的:
|
1、每个用到网络的模块,要提交:请求结构体、响应结构体
|
2、要给每一个请求、响应结构体,分配枚举类型内容--type--用来区分不同的业务功能
|
3、任务类可以使用模板来处理,结合业务抽象类[纯虚函数],定好统一当接口
|
4、考虑使用高级的操作--设计模式的选择:工厂模式、观察者模式等
|
|
协议相关:
|
TCP--心跳检测、粘包处理
|
RTSP[udp]--使用Live555框架来支撑rtsp服务即可--开源框架
|
|
|
|
4星 2、数据库搭建
|
MySQL数据库--建库--建表
|
建库:统一建一个库名: znwl_db
|
建表:需要和每一个用到数据库的负责人--对接--要他们的数据库表--整合重复的内容--建表
|
SQL脚本导出:完成建库、建表之后,要导出sql语句,形成一个脚本,其他人使用脚本,本地即可生成一个新的库、表
|
|
封装:提供接口,给其他人使用--作为子服务来使用的
|
类--公有的接口--给他人调用
|
接口:增删改查的操作--先以sql语句为参数--拿结果集或拿条数
|
升级v2:写一个类来组装sql语句,每一条语句,就是一个对象,较安全
|
|
安全校验:防注入校验--正则匹配
|
|
私有API:自动初始化使用的--实例化对象时,自动把数据库连上
|
|
升级:数据库连接池--解决连接复用的问题
|
|
备份导出:shell脚本--定时导出--打包--上传到指定的ftp服务器保存
|
|
|
3星 3、日志封装
|
日志作用:用于问题定位的
|
级别:常规、调试、警告、错误、致命等
|
写到哪里? 文件、数据库表
|
文件:所有级别的记录 -- 超过指定大小之后-- 文件翻滚 -- 换一个文件继续记录 -- 实现文件翻滚算法
|
|
数据库表: 警告、错误、致命等重要的级别的日志内容
|
|
写日志:同步、异步的选择?---- 异步高效 -- 用队列来缓冲--记录任务
|
|
封装:类--提供对应的接口--函数宏[跟级别挂钩]:只需要选择宏,给一个日志描述,其他的自动生成
|
|
内容:
|
id 级别 时间 日志描述 文件名 函数名 行号 等
|
|
内容一式两份,一个写到文件,一个写到数据库表
|
|
参考框架:
|
log4c log4cPlus等框架,仅作参考,还是要自己实现封装的功能
|
|
|
5星 4、CNN模型搭建
|
作用:提供识别功能的模块,
|
需要产生一个模型文件,通过训练的方式产生
|
对传进来的图片,使用模型去快速匹配到相应的分类,从而实现AI的人脸识别功能
|
|
CNN: 卷积神经网络算法:核心过程--卷积--池化--全连接
|
反向训练:随机梯度下降算法
|
|
搭建:神经网络--需要搭建很多层,逐层去计算并处理各种特征--图片特征--能最终快速找到分类--产生:训练好的模型
|
|
训练:
|
输入:一堆图片特征--都是处理过的图片
|
输出:模型文件
|
|
识别:
|
输入: 一张图片
|
过程:将图片处理之后,去训练好的模型里面,匹配特征,找到分类,返回
|
|
输出: 这张图片对应的所属分类
|
|
提供:
|
模型文件
|
接口函数
|
|
---------------------------------------------
|
迁移学习:
|
已经训练了一个模型了,再来新员工,如何加到模型里面去
|
两种方案:一、加进来之后,重新全部再来一遍
|
二、加进来之后,在已有的基础上,进行二次训练--迁移
|
---------------------------------------------
|
细节:
|
拟合问题:过拟合、欠拟合
|
活体检测问题:3维成像效果--立体的方式
|
配合动作来识别
|
-----------------------------------------
|
技术:
|
框架 TensorFlow--谷歌的开源框架
|
|
真正的智能体,也就是所谓的通用AI,真正牛逼起来的时候:量子计算机量产的时候
|
-----------------------------------------
|
|
|
|
4星 5、图像管理
|
图像--人脸照片
|
用来直接训练的图片--采集好的
|
识别产生的单张照片--识别时保存的
|
|
分类:用工号来作为子目录,保存每个员工的人脸照片
|
什么时候创建子目录?
|
注册成功的时候,产生了员工id,此时就可以触发--调用接口来创建子目录
|
接口:传进来一个工号[字符串],会到图像根目录去创建这个工号子目录
|
|
对于用于不同功能的图片,记录的时候,可以加上标志--训练否
|
|
接口:删除已经无用的照片--不再用于训练的照片、有干扰的照片
|
|
【是否要用界面显示对应子目录下的照片,并进行相应的操作--查询、修改】
|
|
4星 6、模型数据预处理
|
处理的是照片,要把原始的照片--处理--变成矩阵特征
|
处理方式:向量化、灰度化、二值化、浮点归一化、降噪等处理方式
|
原理:图片中的每一个像素点,体现的都是RGB的颜色值 (255,255,255)
|
使用的框架:OpenCV
|
|
3星 7、配置管理
|
作用:使得服务端,不需要再进行二次编码,特别是一些参数要变的时候:ip、port、路径......
|
|
配置信息存放:xml文件来保存,如:config.xml
|
内容:
|
socket:ip、port
|
MySQL: host、user、password、db、port等
|
log: 文件翻滚--大小限定,存放的路径、是否启动异步模式
|
图片存放:根目录
|
配置服务的启动方式:冷启动、热启动
|
内容提供方式:饿汉=0、懒汉=1
|
客户端文件版本存放:根目录
|
|
解析库:tinyxml2 使用三方库的头文件和源文件就可以搞定
|
|
提供内容的方式:
|
在主函数中第一个加载起来
|
饿汉式:一开始就全局所有的内容--可以使用全局变量来存储最新的内容
|
懒汉式:需要时,再提供--提供函数接口,调用--返回结果
|
|
启动方案:
|
定时监控配置内容是否发生变化,变化了,要随时做出相应的重启服务
|
定时监控:使用一条子线程,间隔10秒读一下xml配置文件和上一次的数据对比
|
有变化了,就按配置的方式启动
|
|
5星 8、客户端文件版本管理
|
权限--版本管理权限
|
获取版本号:查询到所有版本号,放到一个下拉框中展示
|
添加已经变化的文件:-- 增量更新
|
专门的UI界面:
|
选择文件的本地路径
|
版本号[规则],依赖版本号
|
服务端的存放路径,客户端的存放路径
|
二维表:点击添加文件之后,会将上述的内容,写到表格中
|
当添加完所有变化的文件之后
|
|
再点击提交按钮,上传到服务端,文件存到磁盘对应目录[服务端的存放路径],相应的信息写到数据库表
|
|
技术: 文件上传、断点续传
|
文件打包:所有文件打包成一个安装包,作为全量更新的安装包
|
|
数据库表:版本信息表--写入
|
|
|
|
3星 9、视频存储管理
|
先铺垫一下:视频文件在哪里?
|
存在硬盘录像机里面
|
|
摄像头--数据线--硬盘录像机[存视频文件]--软件服务端--MySQL数据库[存信息]
|
|
|
客户端
|
|
管理视频文件:
|
连上每一个硬盘录像机--查看对应的摄像头目录下都有哪些视频文件
|
还可以调整一下摄像头对应的文件夹名字--默认是摄像头id
|
|
动作:查询、修改
|
增加--是摄像头的事情
|
|
[还可以加上UI来显示,操作会更加方便]
|
|
设置覆盖周期:只会保存多久的视频--30天、60天...
|
设置每个视频文件的时长:5min,10min......
|
|
品牌:
|
海康威视、大华、宇视科技等[全国前三]
|
|
4星 10、活体检测处理
|
4星 11、推送、通知管理
|
本质:群发,给所有在线的客户端群发的
|
什么时候发? 有新通知的时候,群发
|
群发之后,要记录每一个已经发过的账号信息
|
如果后面在登录,要判断是否已经发过某一条通知,没发过的接着发,发过的不要再发了
|
|
推送记录表:id、用户名、通知id、发送时间、状态
|
通知信息表: id、通知标题、通知内容、创建时间、状态、用户id
|
|
管理通知:
|
增删改查
|
最好是用一个ui界面管理一下相关的通知
|
|
保证所有登录成功的用户,都能收到一次最新的通知
|
【参考邮件系统】
|
|
通知:还可以有推送的记录,以及阅读的状态:未读、已读
|
|
|
|
==================================================================================
|
业务分离:只要是自己业务相关的,不管在客户端还是服务端, 都要写代码去实现
|
|
前后分离:分界线是:前端(客户端),后端(服务端)
|
前端只做前端的业务
|
后端只做后端的业务
|
前后的业务通信,需要商量好特定的格式
|
---------------------------------------
|
业务分离: 必须得2个端的开发语言一样
|
|
前后分离: 2个端开发的语言不一样时,就得使用
|
---------------------------------------
|
现在的项目:采用业务分离的方式
|
==============================================================================================
|
合代码的一些细节:
|
|
1、客户端的代码合并
|
A、保证所有模块使用同一个套接字,这样收包的时候,就统一在一个地方了
|
|
B、模块对应的类名,一定要根据功能来命名,不允许使用默认的名字
|
|
C、合代码的原则:尽量少修改的原则,只需要在主模块添加适当的代码为主
|
子模块的功能保持不动
|
|
D、合代码之后,保证原有的功能不会被修改,且不影响其他模块的使用
|
|
|
|
2、服务端的代码合并
|
A、自己的子服务模块要先合并好,是一种被动调用的方式
|
|
B、客户端的业务要合到服务端来时,要用类的方式来合并[xx.h,xx.cpp]
|
|
|
|
|
|
|
|
|
|
|
|