当前位置: 首页 > article >正文

远程监控系统项目里练习

1、项目目标

  • 设备端

(1)基于stm32mp157开发板,裁剪linux5.10.10,完成ov5640摄像头移植;

(2)完成用户层程序,完成对摄像头的控制及与云端服务的数据交互。

  • 云端

(1)完成TCP服务器,完成用户端<---->设备端的数据转发;

(2)使用关系型数据库,存储用户与设备的基础信息。

  • 用户端

(1)Qt开发应用界面,包括用户注册、用户登录、设备绑定、设备控制等功能;

(2)移植opencv,实现人脸框选功能。(未实现)

2、项目设计

2.1 Qt用户端设计(原型图)

2.1.1 用户登录和用户注册

  

点击眼睛:展示密码

2.1.2 主界面(Tab1: 设备监控)

双击左侧表格,设备具体信息展示在右侧;

点击开始按钮,黑色区域展示远程摄像头拍摄的内容(此时不可切换至其他页面,直至点击结束按钮)。

2.1.3 设备绑定(Tab2: 我的设备)

  

主要功能:将登录的用户与远程的摄像头设备关联。

2.2 Qt用户端程序设计

2.2.1 单例模式

        设计了 MyWidgetFactory,管理LoginWidget、RegistWidget、MainWidget和AddDevWidget的单例,并提供静态接口获取这些单例。避免了各个页面之间跳转需要将其他页面的示例注入到自身,解决了管理麻烦的问题。以下是部分代码展示:

class MyWidgetFactory
{
public:MyWidgetFactory()=delete;static void init();static LoginWidget* getLoginWidget();static RegistWidget* getRegistWidget();static MainWidget* getMainWidget();static AddDeviceWidget* getAddDeviceWidget();
};

2.2.2 工厂方法模式或代理模式

   设计了MyTcpProxy代理:

(1)QTcpSocket管理:以单例的方式管理QTcpSocket,将QTcpSocket与各个UI界面进行了解耦,在MyTcpProxy集中管理QTcpSocket单例,UI只处理UI的事情;

(2)报文发送:对外提供sendXXX的静态接口给各个界面调用以发送消息,在Proxy内部统一组包;

(3)报文解析:在MyTcpProxy内部完成TcpSocket返回消息的报文解析,并根据不同的报文种类,通过信号发送到各个界面,各界面通过槽函数进行消息返回处理及刷新界面;

(4)类MVC设计:对于复杂结构,如主界面的tab1和tab2的设备表格,构造表格设备模型,将解析内容刷新到模型,再通过信号发送到界面,实现类似MVC的模式。

class MyTcpProxy:public QObject
{
private:QTcpSocket* socket;  //单例: 全局有且仅有一个QSocketpublic:MyTcpProxy();static MyTcpProxy* getTcpProxy(); //获取代理:也单例,所有界面可通过此代理操作socket//发送报文(若干个函数),类似工厂方法模式static bool sndLogin(const QString & user,const QString & pwd);static bool sndReg(const QString & user,const QString & pwd);static bool sndStartCamera(const QString& userid,const QString& devid);// 省略......public slots://socket通信的槽函数,所有远端来的消息先通过Pro需要处理,Proxy再将通过信号发送到各个UI中//(1)报文的统一拆解//(2)预处理,例如视频数据,等一帧收齐并进行格式转换后,再发送给UI界面//(3)UI与逻辑分离,UI只处理UI的事情    void msgRecved();void onDisconn();signals://信号(若干)void loginRet(const bool& ret,const QString& msg);void regRet(const bool& ret,const QString& msg);void videoRecv(QPixmap& pic);// 省略......};

2.2.3 config.ini配置文件

        设计MyConfig类和config.ini文件,通过MyConfig::getValue(const QString & key)接口获取config.ini配置内容,避免将一些重要且需要频繁修改的参数写死在代码中,仅仅通过修改配置文件即可完成参数修改。

class MyConfig
{
private:static QSettings* settings;
public:MyConfig()=delete;static QString getConfigString(QString key);static int getConfigInt(QString key);static double getConfigDouble(QString key);
};

配置文件:

[network]
host=127.0.0.1
port=8080

虽然配置内容较少了,但体现了配置与代码分离的思想。

2.2.4 yuyv4与RGB32的格式转换

这个是有公式的,见源码的 ImageUtil类。 我是从yuyv4转成RGB32格式的。

QImage ImageUtil::yuyvArr2QImage(const uchar *data, int width, int height)
{QImage image(width, height, QImage::Format_RGB32);for (int y = 0; y < height; ++y) {// 获取当前行的YUV数据指针const uchar *yuyvLine = data + y * width * 2; // 每行占用 width*2 字节QRgb *rgbLine = reinterpret_cast<QRgb*>(image.scanLine(y));// 每4字节处理两个像素(YUYV格式)for (int x = 0; x < width; x += 2) {// 提取YUV分量uchar Y0 = yuyvLine[0];  // 第一个像素的Yuchar U  = yuyvLine[1];  // 共用U分量uchar Y1 = yuyvLine[2];  // 第二个像素的Yuchar V  = yuyvLine[3];  // 共用V分量yuyvLine += 4;           // 移动到下一个YUYV块// YUV转RGB(BT.601标准,TV范围)auto convert = [](uchar Y, uchar U, uchar V) -> QRgb {// 调整YUV到有效范围int y = qMax((int)Y, 16) - 16;  // Y范围: 16-235 → 0-219int u = U - 128;           // U范围: 0-255 → -128-127int v = V - 128;           // V范围: 0-255 → -128-127// 整数运算(使用64位防溢出)int r = (298 * y + 409 * v + 128) >> 8;int g = (298 * y - 100 * u - 208 * v + 128) >> 8;int b = (298 * y + 516 * u + 128) >> 8;// 限制到0-255范围r = qBound(0, r, 255);g = qBound(0, g, 255);b = qBound(0, b, 255);return qRgb(r, g, b);};// 转换两个像素rgbLine[x]     = convert(Y0, U, V);rgbLine[x + 1] = convert(Y1, U, V);}}return image;
}

2.3 云端数据库设计

2.3.1 数据库

        其实就两张表,tbl_user用户表、tbl_dev设备表。一般按照数据库设计范式,应该再添加一张关联关系表,例如tbl_user_dev,但是,我把userid字段直接放到了tbl_dev中,然后让userid和devid成为tbl_dev的联合主键。E-R就不画了。

        实际中,应该用关联关系表还是把关联关系放到某个实体表中,要看实际应用情况,按我的理解,如果需要通过关联关系查询的频率很高且数据量还不小,我认为还是沉到实体表中更好,但这样实体表,确实就不能叫实体表了,可以称之为数据表。

2.3.2 网络数据接口设计

        本案例中均使用tcp进行通信,除了设备心跳报文,其他报文都是一问一答的形式。相对麻烦的视频数据发送的时序图如下图所示:

2.3.3 关键的数据结构设计

(1)手写hashmap: 目的通过devid快速查找qt端的socketfd和设备端的socketfd,本案例实际上用不着,纯粹为了练手。贴下头文件

typedef struct{char devid[20];//keyint devfd;//设备端fdint userfd;//qt端fd
}data_t;typedef struct pn{union{ int subLen; data_t data; };struct pn* next;
}node_t;typedef struct{ node_t* arr[20]; int len; }hashmap_t;hashmap_t* hashmap_create();
void hashmap_destroy(hashmap_t* mp);
int hashmap_hashcode(char* key);
void hashmap_put(hashmap_t* mp, char* key, data_t value);
data_t* hashmap_get(hashmap_t* mp, char* key);
void hashmap_remove(hashmap_t* mp, char* key);
int hashmap_size(hashmap_t* mp);  
void hashmap_printself(hashmap_t* map);

(2)设备表与用户表对应的结构体

typedef struct{char userid[20];//用户名char pwd[20];//密码
}my_user_t;typedef struct{char userid[20];//用户名char devid[20];//设备idchar devname[20];//设备名称int state;//设备状态char desc[50];//设备描述
}my_dev_t;

2.3.4 模块设计

(1)qt_server和dev_server: 两个基于EPoll模型的tcp服务端

(2)sqlite3的DAO层:贴下头文件

bool mysql_init();//初始化表
void mysql_deinit();//销毁资源sqlite3* mysql_getConn();//获取sqlite3连接: 上锁!
void mysql_closeConn(sqlite3* db);//解锁!
bool mysql_user_exit(sqlite3* db, char* userid,char* pwd);//user表:查询
bool mysql_user_add(sqlite3* db, my_user_t* user);//user表:添加用户
//dev表:查询userid 关联的 设备列表
bool mysql_dev_list(sqlite3* db, char* userid, my_dev_t* arr, int* len);
bool mysql_dev_add(sqlite3* db, my_dev_t* dev);//dev表:添加关联的设备
//dev表:删除关联的设备
bool mysql_dev_del(sqlite3* db, char* userid, char* devid);

(3)统一的报文解析、处理与回复,思想类似Qt端的设计。

2.4 设备端设计

2.4.1 驱动层设计

外设: OV5640

驱动: linux5.10.10源码自带驱动 (基于V4L2驱动框架),通过make menuconfig直接配置内核

 Device Drivers  --->    <*> Multimedia support  ---> Media core support  --->  <*> Video4Linux core Media drivers  ---[*] V4L platform devices  ---><*>   STM32 Digital Camera Memory Interface (DCMI) support  Media ancillary drivers  --->   Camera sensor devices  --->   <*> OmniVision OV5640 sensor support

设备树的配置: 比较多,我也按照教程来做的,此处不写了。完成后,可以通过ls /dev/video0查看到这个设备文件。

2.4.2 用户层设计

(1)线程1: 定时拍照,生成图片。封装函数通过调用驱动生成拍摄图片

(2)线程2: 读取生成的图片文件,若有文件,上送到云端的dev_server

(3)线程3: 心跳线程

3、总结

3.1 图片传输效率

其实我使用的方法传输的效率特别,但由于时间原因,又不想做更多的改动,我能想到的可以改善的方法如下:

(1)改用udp,多包发送,确认后,再回复补包,补充缺少的包;

(2)采用一些压缩算法,减少数据量;

(3)本案例中已经将图片数据生成了文件,可以通过tftp直接发送文件;

(4)视频流传输(我还不会);

(5)采用一些专用的传输协议(我也还不会);

3.2 Qt的QSocket的readyRead信号绑定

3.3 hashmap的封装碰到的问题

3.4 缺陷

这个系统只是为了给小编自己练手用的,存在蛮多BUG的,例如:

(1)本来设计的用户端与设备端是多对多的,cloud_server需要维护多个hashmap来保存对应管理与通信时序,偷懒,在进行远程拍摄的时候,只能1对1;

(2)cloud_server用了不少全局变量;

(3)通过图片的方式再进行视频拍摄,视频应该有专门的方法,尚未研究;

(4)本来现在Qt端调用opencv的人脸框选接口,这是一个比较独立的功能,且,时间有限,先这样吧;

(5)QSS没有加,这个不是练习重点。

..... 如果要用的我源码,请注意这些坑以及还没有发现的坑。回归实际,如果云端程序面临比较的并发,且不用太考虑硬件资源的问题,我更建议用java来写,开发效率高、运维成本较低。

4、源码

tjzhuorui@163.com/远程监控系统

相关文章:

远程监控系统项目里练习

1、项目目标 设备端&#xff1a; &#xff08;1&#xff09;基于stm32mp157开发板&#xff0c;裁剪linux5.10.10&#xff0c;完成ov5640摄像头移植&#xff1b; &#xff08;2&#xff09;完成用户层程序&#xff0c;完成对摄像头的控制及与云端服务的数据交互。 云端&…...

安装并配置Maven

如图所示&#xff0c;解压安装包&#xff0c;配置环境变量&#xff0c;在bin目录那个界面新建文件夹repository&#xff0c;写上安装路径的坐标&#xff0c;修改Maven仓库镜像&#xff0c;输入cmd验证是否安装成功 <mirror><id>alimaven</id><mirrorOf>…...

PlatformIO 自定义脚本选择编译库源文件 - 设置只用于C++ 的编译选项

PlatformIO 只支持以文件夹为单位选择要编译的源文件&#xff0c;不像Keil 或者CMake&#xff0c;可以手动控制每一个源文件。而且默认只会将库的src 文件夹下的源文件全部加入编译。比如&#xff0c;某个库的文件结构如下&#xff1a; libx src include mem| a.c| b.c| c.c…...

dolphinscheduler单机部署链接oracle

部署成功请给小编一个赞或者收藏激励小编 1、安装准备 JDK版本:1.8或者1.8oracle版本&#xff1a;19Coracle驱动版本&#xff1a;8 2、安装jdk 下载地址&#xff1a;https://www.oracle.com/java/technologies/downloads/#java8 下载后上传到/tmp目录下。 然后执行下面命…...

MongoDB常见面试题总结(上)

MongoDB 基础 MongoDB 是什么&#xff1f; MongoDB 是一个基于 分布式文件存储 的开源 NoSQL 数据库系统&#xff0c;由 C 编写的。MongoDB 提供了 面向文档 的存储方式&#xff0c;操作起来比较简单和容易&#xff0c;支持“无模式”的数据建模&#xff0c;可以存储比较复杂…...

java基础 迭代Iterable接口以及迭代器Iterator

Itera迭代 Iterable < T>迭代接口(1) Iterator iterator()(2) forEach(Consumer<? super T> action)forEach结合Consumer常见场景forEach使用注意细节 (3)Spliterator spliterator() Iterator< T>迭代器接口如何“接收” Iterator<T>核心方法迭代器的…...

CentOS禁用nouveau驱动

1、验证 nouveau 是否在运行 lsmod | grep nouveau如果命令返回结果&#xff0c;说明 nouveau 驱动正在运行。 2、编辑黑名单文件 通过编辑黑名单配置文件来禁用 nouveau 驱动&#xff0c;这样在系统启动时不会加载它。 vi /etc/modprobe.d/blacklist-nouveau.conf修改以下…...

Linux 时间同步工具 Chrony 简介与使用

一、Chrony 是什么&#xff1f; chrony 是一个开源的网络时间同步工具&#xff0c;主要由两个组件组成&#xff1a; chronyd&#xff1a;后台服务进程&#xff0c;负责与时间服务器交互&#xff0c;同步系统时钟。chronyc&#xff1a;命令行工具&#xff0c;用于手动查看或修…...

C语言:字符串处理函数strstr分析

在 C 语言中&#xff0c;strstr 函数用于查找一个字符串中是否存在另一个字符串。它的主要功能是搜索指定的子字符串&#xff0c;并返回该子字符串在目标字符串中第一次出现的位置的指针。如果没有找到子字符串&#xff0c;则返回 NULL。 详细说明&#xff1a; 头文件&#xf…...

28--当路由器开始“宫斗“:设备控制面安全配置全解

当路由器开始"宫斗"&#xff1a;设备控制面安全配置全解 引言&#xff1a;路由器的"大脑保卫战" 如果把网络世界比作一座繁忙的城市&#xff0c;那么路由器就是路口执勤的交通警察。而控制面&#xff08;Control Plane&#xff09;就是警察的大脑&#xf…...

Vue知识点(5)-- 动画

CSS 动画是 Vue3 中实现组件动画效果的高效方式&#xff0c;主要通过 CSS transitions 和 keyframes 动画 CSS Keyframes&#xff08;关键帧动画&#xff09; 用来创建复杂的动画序列&#xff0c;可以精确控制动画的各个阶段。 核心语法&#xff1a; keyframes animationNa…...

MATLAB2024a超详细图文安装教程(2025最新版保姆级教程)附安装钥

目录 前言 一、MATLAB下载 二、MATLAB安装 二、MATLAB启动 前言 MATLAB&#xff08;Matrix Laboratory&#xff09;是由MathWorks公司开发的一款高性能的编程语言和交互式环境&#xff0c;主要用于数值计算、数据分析和算法开发。内置数学函数和工具箱丰富&#xff0c;开发…...

基于 Spring Boot 瑞吉外卖系统开发(二)

基于 Spring Boot 瑞吉外卖系统开发&#xff08;二&#xff09; 员工登录功能实现 员工登录页面login.html存放在/resources/backend/page/login目录下。 启动项目&#xff0c;在浏览器中通过地址“http://localhost:8080/backend/page/login/login.html”访问员工登录页面。…...

软考系统架构设计师之大数据与人工智能笔记

一、大数据架构设计 1. 核心概念与挑战 大数据特征&#xff1a;体量大&#xff08;Volume&#xff09;、多样性&#xff08;Variety&#xff09;、高速性&#xff08;Velocity&#xff09;、价值密度低&#xff08;Value&#xff09;。传统数据库问题&#xff1a;数据过载、性…...

146. LRU 缓存 带TTL的LRU缓存实现(拓展)

LRU缓存 方法一:手动实现双向链表 哈希表 struct Node{int val;int key;Node* prev;Node* next;Node(int a, int b): key(a), val(b), prev(nullptr), next(nullptr) {}Node():key(0), val(0), prev(nullptr), next(nullptr) {} }; class LRUCache { private:Node* removeTai…...

浅层神经网络:全面解析(扩展)

浅层神经网络&#xff1a;全面解析&#xff08;扩展&#xff09; 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;可以分享一下给大家。点击跳转到网站。 https://www.captainbed.cn/ccc 一、神经网络架构演进图谱 #mermaid-svg-…...

Python监控网站更新则推送到企业微信

import requests from lxml import etree import redis r redis.Redis(host"localhost", port6379, db0)def get_page_content(url):# 获取指定网页中的标题和链接url_lists []headers {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)…...

下一代智能爬虫框架:ScrapeGraphAI 详解

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、ScrapeGraphAI 概述1.1 ScrapeGraphAI介绍1.2 核心特点1.3 工作流程1.4 关键模块1.5 对比传统爬虫框架1.6 安装二、基础操作2.1 自定义解析规则2.2 数据后处理2.3 分布式爬取三、高级功能3.1 多步骤交互采集3.2 动态…...

Dubbo(30)如何配置Dubbo的服务分片?

配置Dubbo的服务分片&#xff08;也称为服务分组&#xff09;可以帮助你将不同的服务实例分组&#xff0c;以实现隔离和管理。通过服务分片&#xff0c;可以在同一个注册中心中注册多个相同接口的服务&#xff0c;但它们属于不同的分组&#xff0c;消费者可以根据需要选择特定分…...

Qt 事件系统负载测试:深入理解 Qt 事件处理机制

Qt 事件系统负载测试&#xff1a;深入理解 Qt 事件处理机制 文章目录 Qt 事件系统负载测试&#xff1a;深入理解 Qt 事件处理机制摘要引言实现原理1. 自定义事件类型2. 事件队列管理3. 性能指标监控4. 事件发送机制 性能监控实现1. 负载计算2. 内存监控3. 延迟计算 使用效果优化…...

Unity3D仿星露谷物语开发33之光标位置可视化

1、目标 当从道具栏中拖出一个道具到地面的时候&#xff0c;光标区域会显示是否可放置物体的可视化显示。绿色表示可以放置物体&#xff0c;红色表示不可以放置物体。 2、优化InventoryManager脚本 添加2个方法&#xff1a; /// <summary>/// Returns the itemDetails&…...

蓝桥杯冲刺题单--二分

二分 知识点 二分&#xff1a; 1.序列二分&#xff1a;在序列中查找&#xff08;不怎么考&#xff0c;会比较难&#xff1f;&#xff09; 序列二分应用的序列必须是递增或递减&#xff0c;但可以非严格 只要r是mid-1&#xff0c;就对应mid&#xff08;lr1&#xff09;/2 2.答…...

《深度探秘:SQL助力经典Apriori算法实现》

在数据的广袤世界里&#xff0c;隐藏着无数有价值的信息&#xff0c;等待着我们去挖掘和发现。关联规则挖掘算法&#xff0c;作为数据挖掘领域的关键技术&#xff0c;能够从海量数据中找出事物之间潜在的关联关系&#xff0c;为商业决策、学术研究等诸多领域提供有力支撑。其中…...

MySQL原理(一)

目录 一、理解MySQL的服务器与客户端关系 1&#xff1a;MySQL服务器与客户端 2&#xff1a;服务器处理客户端请求 3&#xff1a;常见的存储引擎 二、字符集和比较规则 1&#xff1a;字符集和比较规则简介 2&#xff1a;字符集和比较规则应用 3&#xff1a;乱码原因&…...

Docker+Jenkins+Gitee自动化项目部署

前置条件 docker安装成功 按照下面配置加速 sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-EOF {"registry-mirrors": ["https://register.librax.org"] } EOF sudo systemctl daemon-reload sudo systemctl restart docker一、…...

Nginx 499 错误的原因及解决方法

Nginx 499 错误的原因及解决方法 原因 客户端超时&#xff1a; 客户端在等待服务器响应时超时&#xff0c;导致连接被关闭。 解决方法&#xff1a;优化服务端响应时间&#xff0c;或调大客户端的连接超时时间。 服务端响应过慢&#xff1a; 后端服务处理请求时间过长。 解决方法…...

Linux网络多进程并发服务器和多线程并发服务器

多进程 还是以大小写转换为例子 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <sys/socket.h> #include <arpa/inet.h> #include "wrap.h" #include…...

VScode 画时序图(FPGA)

1、先安装插件&#xff1a; 2、然后就可以编写一个.js文件&#xff0c;如下&#xff1a; {signal: [{name: clk, wave: p.......|..},{name: rstn, wave: 01......|..},{name: din_vld, wave: 0.1.0...|..},{name: din, wave: "x.x...|..", data: ["D0", …...

Kubernetes 集群搭建(二):搭建k8s集群 (1.28版本)

&#xff08;一&#xff09;虚拟环境准备 名称ip备注m1192.168.101.131mastern1192.168.101.132workern2192.168.101.133worker &#xff08;二&#xff09;所有主机统一配置 2.1 关闭防火墙和selinux systemctl stop firewalld systemctl disable firewalld sed -i s/enfo…...

一文详解OpenCV环境搭建:Windows使用CLion配置OpenCV开发环境

在计算机视觉和图像处理领域&#xff0c;OpenCV 是一个不可或缺的工具。其为开发者提供了一系列广泛的算法和实用工具&#xff0c;支持多种编程语言&#xff0c;并且可以在多个平台上运行。对于希望在其项目中集成先进视觉功能的开发者来说&#xff0c;掌握如何配置和使用OpenC…...