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

车流量监控系统

1.项目介绍

本文档是对于“车流量检测平台”的应用技术进行汇总,适用于此系统所有开发,测试以及使用人员,其中包括设计背景,应用场景,系统架构,技术分析,系统调度,环境依赖,以及运行指导,其中技术分析为主要部分,包括UI设计,视频输入输出,图像预处理,数据提取,处理及预测等。

2.设计背景

政治角度:

随着城市化进程的加快和交通拥堵问题的日益严重,政府对于智能交通系统的建设与管理给予了高度重视。基于视频的车流量检测平台作为智能交通系统的重要组成部分,其开发与应用有助于提升城市治理水平,满足政府对交通状况实时监测与管理的需求。

经济角度:

随着信息技术的快速发展,视频处理技术、计算机视觉和深度学习等领域取得了显著进步,为基于视频的车流量检测平台的开发提供了技术支撑。同时,随着汽车保有量的不断增加,交通管理领域对于智能化、自动化的需求也日益旺盛,推动了基于视频的车流量检测平台的研发与应用。

社会角度:

公众对于出行效率、交通安全和环境质量的关注度不断提高,对于智能交通系统的期待也日益增强。基于视频的车流量检测平台能够实时监测交通状况,为公众提供更加便捷、安全的出行环境,同时也有助于减少交通拥堵和环境污染,提升城市生活质量。

此外,传统的车流量检测方法主要依赖于传感器设备,如地磁传感器、红外线传感器等。这些传感器需要在道路上布设,成本较高且安装维护困难。而基于计算机视觉的车流量检测系统则可以通过分析道路上的摄像头图像来实现,具有成本低、安装方便、实时性强等优势。因此,设计一种高效、准确且易于实现的汽车流量检测系统显得尤为重要。

3.场景应用

随着城市化进程的加快和交通工具的普及,车辆数量的快速增长给城市交通管理带来了巨大的挑战。因此,交通流量检测成为了交通管理的重要组成部分。它能够提供实时的交通状况信息,帮助交通管理部门制定合理的交通策略,优化交通流量,提高道路利用效率,减少交通拥堵和事故发生的可能性。

基于视频的车流量检测平台可广泛应用于城市道路、高速公路、桥梁隧道等交通场景中。通过高清摄像头实时拍摄车辆图像,利用图像处理算法对图像进行分析和处理,提取出车辆的位置、数量和运动轨迹等信息。这些信息可用于交通管理部门对道路交通情况的监测和分析,也可用于交通规划和设计、交通预测和智能交通系统等领域。

解决的社会痛点

1. 交通拥堵问题:

基于视频的车流量检测平台能够实时监测交通流量和车辆速度等信息,为交通管理部门提供实时、准确的数据支持。通过数据分析,可以及时发现交通拥堵点,采取相应的交通控制措施,优化交通流动,减少交通拥堵现象。

2. 交通安全问题:

通过对车辆运动轨迹的监测和分析,平台可以及时发现异常行驶行为,如超速、逆行等,为交通管理部门提供预警信息,有助于减少交通事故的发生。

3. 环境质量问题:

平台还可以监测城市环境质量,如空气质量、噪声等。通过对这些数据的分析,可以及时发现环境质量不佳的区域,采取相应措施减少污染源,提高城市环境质量。

4. 公共服务效率问题:

在公共交通领域,基于视频的车流量检测平台可以实时监测公交、地铁等公共交通的运行情况,为公众提供更加精准的出行信息,提高公共服务的效率和质量。

4.系统架构

4.1用户界面层

使用QT框架开发图形用户界面(GUI),展示实时视频流、预处理视频流,流量统计数据、当天车流信息以及未来车流信息等。用户可以通过此界面进行参数设置、启动/停止检测等操作。

4.2视频处理层

接入摄像头或视频流,利用OpenCV库进行视频捕获和预处理。实现车辆检测算法,包括提取物体掩码、运动目标检测、车辆识别等步骤。将检测到的车辆信息传递给下一层。

4.3数据处理与存储层

接收视频处理层传递的车辆信息,并进行进一步的分析和处理,包括提取真实汽车掩码,以及Opencv格式的图片与Qt支持的图片进行格式转化。将可用数据提取出来并进一步的过滤,并且利用梯度下降法拟合数据的函数模型。

4.5数据存储层

将处理后的数据存储在数据库中,包括车辆流量统计数据、时间戳。实现数据查询,预测和报表生成功能,供用户层调用和展示。

5.技术分析

1视频处理流程图

5.1UI设计

2 UI设计图

客户端界面利用QT5搭建而成,这些窗口分别是源视频识别并标记显示窗口,计算机图像学处理后的窗口,未来数据预期窗口,用来显示未来某天二十四小时的车流量,当天的车流量情况展示窗口,最后一个是日历,可以选择日期,还有对于视频流的播放控制有两个按钮控制。

使用Qlabel控件,在其之上利用绘图事件,分别将标记后的视频流和预处理视频流播放出来。

折线统计图用于展示以前某天或未来某天24小时的车流量变化情况,条形统计图用于实时展示当天的车流情况。

中间两个窗口分别显示实时监控的视频图像以及汽车轮廓和视频流处理过程。

利用QToolButton控件设置两个按钮来控制视频流的播放。

两个QEditLine 控件用于输入机器学习的频率和次数。

那个大的按钮是主动学习的控制开关,点击触发后变为红色,开始学习,并再右上角的编辑框显示学习进度。

使用日历控件可以先择事件,如果选择过去的某天,就将过去的某天二十四小时的车流量情况图像化的显示,如果选择未来某天,就将这天预测的数据显示出来。

5.2视频流的输入输出

在C++中,使用OpenCV库处理视频流时,cv::VideoCapture 类是一个非常重要的组件,它用于捕获视频流,可以从摄像头、视频文件或IP摄像头流中读取帧。

使用实例

cv::VideoCapture cap(0); // 检查摄像头是否成功打开

if (!cap.isOpened())

{

std::cerr << "Error opening video stream or file" << std::endl;

return -1;

}

cv::namedWindow("Video", cv::WINDOW_AUTOSIZE);

while (true)

{ // 读取一帧图像 cap >> frame; // 检查是否成功读取帧

   if (frame.empty())

{

std::cout << "Can't receive frame (stream end?). Exiting ..." << std::endl;

break;

}

cv::imshow(Video,res);

}

5.3图像预处理

3 最终呈现图

5.3.1获取前景掩码

图片前景掩码(通常简称为前景掩码)在图像处理中是一个重要的概念,主要用于从图片中分离出前景元素。掩码是一个二值图像,其中前景元素被标记为白色(或其他高亮颜色),而背景元素则被标记为黑色(或其他暗色)。通过这种方式,掩码可以帮助我们在后续的图像处理过程中只处理或操作前景元素,而忽略背景元素。基于颜色或亮度的差异:如果前景和背景在颜色或亮度上有明显的差异,可以使用阈值操作或色彩分割等方法来生成掩码。一旦生成了前景掩码,就可以将其应用于各种图像处理任务,如前景元素的提取、背景的替换、图像合成等。

4 汽车前景掩码图

接口解释:

setShadowThreshold()

这个方法是用来设置阴影检测阈值的。阴影阈值决定了算法如何区分前景对象和其可能产生的阴影。通过调整这个阈值,你可以影响算法对阴影的敏感度。

apply()

apply()方法是BackgroundSubtractorMOG2类的主要方法,用于执行背景减除。当你调用这个方法时,它会处理传入的图像,并返回一个新的图像,其中前景对象(即移动的对象)被高亮显示(通常是白色),而背景则被抑制(通常是黑色)。

5.3.2形态学开运算

二值图像中一类主要处理是对提取的目标图形进行形态分析。形态学处理中最基本的是腐蚀和膨胀。腐蚀和膨胀是两个互为对偶的运算。腐蚀的作用是将目标图像收缩,而膨胀是将图像扩大。结构元素是指具有某种确定形状的基本结构元素,例如,一定大小的矩形、圆形等。结构元素具有原点。

5.3.2.1 形态学

形态学操作是根据图像形状进行的简单操作。一般情况下对二值化图像/灰度图像进行操作。它需要输入两个操作,一个是原始图像,另一个被称为结构化元素或核,它是用来决定操作的性质的。两个基本的形态学操作是腐蚀和膨胀,它们的变体构成了开运算、闭运算和梯度等。

5 腐蚀/膨胀对比图

5.3.2.2 腐蚀

腐蚀的效果是把图片"变瘦",其原理是在原图的小区域内取局部最小值。因为是二值化图,只有 0 和 255,所以小区域内有一个是 0 该像素点就为 0:

5.3.2.3 膨胀

膨胀与腐蚀相反,取的是局部最大值,效果是把图片"变胖"。

5.3.2.4 开/闭运算

开运算:先腐蚀后膨胀,可用以消除黑色背景中的白点杂质。

闭运算:先膨胀后腐蚀,可用以消除白色前景中的黑点杂质。

6 形态学闭运算处理图

接口:

腐蚀(Erosion)

void erode(InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1), intiterations=1,IntborderType=BORDER_CONSTANT,

const Scalar&borderValue=morphologyDefaultBorderValue());

参数解释:

src:输入图像,通常是二值图像。

dst:输出图像,与输入图像具有相同的尺寸和类型。

kernel:用于腐蚀的结构元素,定义了邻域的形状和大小。

anchor:结构元素的锚点位置。默认值是(-1, -1),表示锚点位于结构元素的中心。

iterations:腐蚀操作的迭代次数。

borderType:像素外推法的类型。

borderValue:使用边界类型BORDER_CONSTANT时的边界值。

膨胀(Dilation)

void dilate(InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1),

int iterations=1,int borderType=BORDER_CONSTANT,

 const Scalar& borderValue=morphologyDefaultBorderValue());

参数解释:

src:输入图像,通常是二值图像。

dst:输出图像,与输入图像具有相同的尺寸和类型。

kernel:用于膨胀的结构元素,定义了邻域的形状和大小。

anchor:结构元素的锚点位置。默认值是(-1, -1),表示锚点位于结构元素的中心。

iterations:膨胀操作的迭代次数。

borderType:像素外推法的类型。

borderValue:使用边界类型BORDER_CONSTANT时的边界值。

5.3.3高斯滤波

高斯滤波(Gauss Filter)是线性滤波中的一种。在OpenCV图像滤波处理中,高斯滤波用于平滑图像,或者说是图像模糊处理,因此高斯滤波是低通的。其广泛的应用在图像处理的减噪过程中,尤其是被高斯噪声所污染的图像上。

高斯滤波的基本思想是: 图像上的每一个像素点的值,都由其本身和邻域内其他像素点的值经过加权平均后得到。其具体操作是,用一个核(又称为卷积核、掩模、矩阵)扫描图像中每一个像素点,将邻域内各个像素值与对应位置的权值相称并求和。从数学的角度来看,高斯滤波的过程是图像与高斯正态分布做卷积操作。

注意: 高斯滤波是将二维高斯正态分布放在图像矩阵上做卷积运算。考虑的是邻域内像素值的空间距离关系,因此对彩色图像处理时应分通道进行操作,也就是说操作的图像原矩阵时用单通道数据,最后合并为彩色图像。

5.3.3.1 一维高斯函数

可以看到,G(x)的跟sigma的取值有极大的关系。sigma取值越大,图像越平缓,sigma取值越小,图像越尖锐。

7 一维高斯函数

5.3.3.2 二维高斯函数

二维高斯是构建高斯滤波器的基础。可以看到,G(x,y)在x轴y轴上的分布是一个突起的帽子的形状。这里的sigma可以看作两个值,一个是x轴上的分量sigmaX,另一个是y轴上的分量sigmaY。对图像处理可以直接使用sigma并对图像的行列操作,也可以用sigmaX对图像的行操作,再用sigmaY对图像的列操作。它们是等价的。当sigmaX和sigmaY取值越大,整个形状趋近于扁平;当sigmaX和sigmaY取值越小,整个形状越突起。

高斯滤波原理就是将上图的二维正态分布应用在二维的矩阵上,G(x,y)的值就是矩阵上的权值,将得到的权值进行归一化,将权值的范围约束在[0,1]之间,并且所有的值的总和为1。可以看到,权值的分布是以中间高四周低来分布的。并且距离中心越远,其对中心点的影响就越小,权值也就越小。

因此可以总结:

(1)在核大小固定的情况下,sigma值越大,权值分布越平缓。因此,邻域各个点的值对输出值的影响越大,最终结果造成图像越模糊。

(2)在核大小固定的情况下,sigma值越小,权值分布越突起。因此,邻域各个点的值对输出值的影响越小,图像变化也越小。假如中心点权值为1,其他点权值为0,那么最终结果是图像没有任何变化。

(3)sigma固定时,核越大图像越模糊。

(4)sigma固定时,核越小图像变化越小。

9 采用高斯滤波后的图

接口解释:

void GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType=BORDER_DEFAULT);

参数解释:

src:输入图像,可以是多通道图像。

dst:输出图像,与输入图像具有相同的尺寸和类型。

ksize:高斯核的大小。它必须是正奇数。

sigmaX:表示高斯核函数在X方向的标准差。

sigmaY:表示高斯核函数在Y方向的标准差。如果sigmaY设置为0,那么它会被设置为与sigmaX相同的值。两个sigma值决定了高斯核的形状。

borderType:像素外推法的类型,决定了当高斯核应用到图像边界时如何处理边界外的像素。默认值是BORDER_DEFAULT。

5.4数据处理

5.4.1 数据预处理

原图通过一系列图形学处理后,已经可以提取出想要的数据了,接下来就是数据数据除杂和过滤的过程。

5.4.1.1提取汽车掩码

寻找所有汽车掩码前景的连通图,如果连通图的长宽,以及面积都复合实验阈值,那么此掩码就是汽车的掩码。

10 计算汽车前景掩码流程图

核心算法

 findContours(dst, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

    for (size_t i = 0; i < contours.size(); i++)

    {

        Rect2d re = c2d(boundingRect(contours[i]));

        if (re.width>90&& re.width<440 &&re.height>140&& re.height<440)

        {

            box3.push_back(re);

            rectangle(frame, re, cv::Scalar(0, 255, 0), 2);

        }

    }

5.4.1.2 数据过滤

依次和前一次的连通图组逐个进行比较,如果出现重叠面积大于等于当前面积的百分之十,则认为此汽车已经计数,否则依次向更久的连通组比较,直到遍历完所有历史数据。最终用所有车减去历史出现的车等于新出现的车。

11 统计汽车数量流程图

核心算法

int Run::findsum()

{

    int sum = 0;

    for (size_t i = 0; i < box3.size(); i++)

    {

        bool bo = false;

        for (size_t j = 0; j < box2.size(); j++)

        {

            if (overlapArea(box3[i], box2[j]) / box3[i].area()> 0.1)

            {

                bo = true;

                break;

            }

            else

            {

                for (size_t k = 0; k < box1.size(); k++)

                {

                    if (overlapArea(box3[i], box1[k]) / box3[i].area()> 0.1)

                    {

                        bo = true;

                        break;

                    }

                }

            }

        }

        if (bo)sum++;

    }

    return sum;

}

5.4.2 流量检测

如图所示,利用连续三帧图像来确定是否有新出现的车辆,这三帧中总共出现了七辆车。

流量检测过程图:

12-1 第一帧有四辆车

12-2 第二帧有两辆车,其中新出现了一辆

12-3 第三帧有四辆车,其中新出现了量辆

5.4.3 结果统计

利用当帧图像中汽车的总数量-前一帧汽车的数量=当前帧新出现的汽车数量。

而其中计算是否为之前已经出现过的车利用了面积重叠法。

13 判断是否为已经扫描过的车辆示意图

核心算法

double Run::overlapArea(Rect2d rect1, Rect2d rect2)

{

    int overlapLeft = std::max(rect1. x, rect2.x);

    int overlapRight = std::min(rect1.x+rect1.width, rect2.x+rect2.width);

    int overlapTop = std::max(rect1.y, rect2.y);

    int overlapBottom = std::min(rect1.y+rect1.height, rect2.y+rect2.height);

    // 如果重叠区域的左右或上下边界无效(即没有重叠),则返回0

    if (overlapLeft >= overlapRight || overlapTop >= overlapBottom)

    {

        return 0;

    }

    // 计算重叠区域的宽度和高度

    int overlapWidth = overlapRight - overlapLeft;

    int overlapHeight = overlapBottom - overlapTop;

    // 计算重叠面积

    return overlapWidth * overlapHeight;

}

5.4.4 数据存储

数据存储利用关系型数据SQLite。SQLite是一个功能强大且易于使用的数据库系统,特别适用于那些需要轻量级、嵌入式和跨平台数据库解决方案的场景。这个表tim字段是一个INTEGER类型,可转为long long,用于存储UNIX时间戳。num字段是一个整型,用于存储车辆数量。可以从数据库中拿到历史数据,也可以将新扫描的数据存放到数据库中。

建表语句

CREATE TABKE car_table (

tim INTEGER PRIMARY KEY,

num INT NOT NULL);

5.4.5 流量预测

我们首先想到简单线性回归分析,但是通过观察发现车流量变化的函数曲线接近于正弦曲线,因此采用梯度下降拟合曲线。

使用梯度下降法来拟合y = a * sin(b * X + c) + d形式的模型是一个迭代的过程,其中我们逐步调整模型的参数a, b, c, d,以最小化预测值和实际值之间的误差。

5.4.5.1梯度下降

14梯度下降求极值示意图

5.4.5.1.1算法简介

梯度下降法(Gradient Descent)是一种优化算法,常用于机器学习和深度学习的训练过程中,特别是用于求解损失函数的最小值。该算法的基本思想是通过迭代的方式调整模型参数,以使得损失函数逐渐减小,从而逼近最小值。

梯度下降法的工作原理如下:

1.选择初始参数:首先,需要为模型的参数选择一个初始值。这些参数可以是随机选择的,也可以是基于某种启发式方法选择的。

2.计算梯度:在每一次迭代中,计算损失函数关于模型参数的梯度。梯度表示了损失函数在各个方向上的变化率,因此指向了损失函数减小最快的方向。

3.更新参数:根据计算得到的梯度,按照一定的学习率(learning rate)来更新模型的参数。学习率是一个超参数,它决定了每次参数更新的步长。过大的学习率可能导致算法不稳定,而过小的学习率则可能导致算法收敛速度过慢。

4.重复迭代:重复执行步骤2和步骤3,直到满足某种停止条件,如损失函数值小于某个阈值,或者达到预设的最大迭代次数。

1.为什么按负梯度下降

《数学分析》中,负梯度方向是函数下降最快的方向,即x=[2,3],如果梯度为[1,2],则x往[1,2]方向调整,能令函数f(x)下降最快的方向(所谓最快,即调整同样的步长,该方向能令函数下降最快)按负梯度下降,保证了调整方向的正确性。

2.为什么要设置学习率

目的是为了保证按梯度方向调整一定能下降。梯度方向能下降是瞬时的,如果调整步长过大,则不一定能保证函数能下降,但只要调整步长足够小,函数就能下降(前提是梯度不为0)。所以,我们在调整时,加入学习率lr,以控制步长:

3、学习率的设置与自适应学习率

要保证能下降,学习率就不能过大,但学习率很小,每次迭代调整都很小,就需要迭代很多次。为此,我们可以设定一个较中肯的学习率(例如,lr = 0.1)。如果更智能一些,在程序中把学习率改为自适应学习率: 函数能下降,我们把学习率调大些,如果函数本次迭代不能下降,我们就把学习率调小些。

5.4.5.1.2初始化参数

A = -100.0; // 振幅初始估计

B = 2.0 * std::acos(-1.0) / (7680/2); // 频率初始估计,假设周期为12h

C = 0.0; // 相位初始估计

D = 150.0; // 偏移量初始估计

5.4.5.1.3正弦函数拟合模型

double myData::sine_model(long long x, double A, double B, double C, double D)

{

return A * std::sin(B * x + C) + D;

}

5.4.5.1.4计算误差平方和

double myData:: compute_error(const std::vector<long long>& x_data,

const std::vector<int>& y_data,

double A, double B, double C, double D)

{

    double error = 0.0;

    for (size_t i = 0; i < x_data.size(); ++i)

    {

        double y_pred = sine_model(x_data[i], A, B, C, D);

        error += std::pow(y_data[i] - y_pred, 2);

    }

    return error;

}

5.4.5.1.5梯度下降法优化参数

void myData::gradient_descent(const std::vector<long long>& x_data, const std::vector<int>& y_data,double& A, double& B, double& C, double& D,double learning_rate, int iterations)

{

for (int iter = 0; iter < iterations; ++iter)

{

   double dA = 0.0, dD = 0.0;

   double dB = 0.0, dC = 0.0;

   //double error = compute_error(x_data, y_data, A, B, C, D);

   // 计算梯度

   for (size_t i = 0; i < x_data.size(); ++i)

   {

      long long x = x_data[i];

      double y = y_data[i];

      //qDebug()<<x<<"---------"<<y;

      double y_pred = sine_model(x,A,B,C,D);

          dA +=  (y - y_pred) * std::sin(B * x + C);

      dB +=  (y - y_pred) * A * x * std::cos(B * x + C);

      dC +=  (y - y_pred) * A * std::cos(B * x + C);

      dD +=  (y - y_pred);

   }

   // 更新参数

   A -= learning_rate * dA / x_data.size();

   B -= learning_rate * dB / x_data.size();

   C -= learning_rate * dC / x_data.size();

   D-= learning_rate * dD / x_data.size();

  // 输出迭代信息(可选)

  if (iter % 100 == 0)

  {

    qDebug() << "Iteration " << iter << ": A=" << A << ", B=" << B << ", C=" << C << ", D=" << D<< ";

  }

}

}

5.4.5.2线性回归

线性回归是一种统计学上分析数据的方法,用来确定两种或两种以上变量之间关系的强度和方向。它通常用于预测一个因变量(或响应变量)基于一个或多个自变量(或预测变量)的变化。这种方法得名于它使用一个或多个独立变量(或特征)的线性组合来预测因变量(或目标变量)。

通过将时间转化为时间戳:X;汽车流量:Y之后就可以进行线性回归分析,Y=K*X+b;

通过最小二乘法计算线性回归的系数:

pair<double,double>calculateLinearRegression(vector<double>& x, vector<double>& y)

 {

    int n = x.size();  

    // 计算x和y的均值  

    double mean_x = accumulate(x.begin(), x.end(), 0.0) / n;  

    double mean_y = accumulate(y.begin(), y.end(), 0.0) / n;  

    // 计算x和y的乘积之和,以及x的平方和  

    double sum_xy = 0.0;  

    double sum_x2 = 0.0;  

    for (int i = 0; i < n; ++i) {  

        sum_xy += x[i] * y[i];  

        sum_x2 += pow(x[i], 2);  

    }    

    // 计算斜率m和截距b  

double m = (n * sum_xy - accumulate(x.begin(), x.end(), 0.0) * accumulate(y.begin(), y.end(), 0.0)) /(n * sum_x2 - pow(accumulate(x.begin(), x.end(), 0.0), 2));  

    double b = mean_y - m * mean_x;    

    return {m, b};  

}  

5.4.6 图像格式转换

 OpenCV 的图像格式转换为 Qt 的图像格式。函数检查输入的 cv::Mat 对象的类型。OpenCV 支持多种图像类型,但此函数主要处理三种类型:CV_8UC1(单通道8位无符号整数,通常用于灰度图像)、CV_8UC3(三通道8位无符号整数,通常用于彩色图像)和 CV_8UC4(四通道8位无符号整数,通常用于带有 alpha 通道的彩色图像)。

QImage Run:: getQImage(const cv::Mat& mat)

{

    if (mat.type() == CV_8UC1)

    {

        QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);

        image.setColorCount(256);

        for (int i = 0; i < 256; i++)

        {

            image.setColor(i, qRgb(i, i, i));

        }

        uchar* pSrc = mat.data;

        for (int row = 0; row < mat.rows; row++)

        {

            uchar* pDest = image.scanLine(row);

            memcpy(pDest, pSrc, mat.cols);

            pSrc += mat.step;

        }

        return image;

}

else if (mat.type() == CV_8UC3)

{

    const uchar* pSrc = (const uchar*)mat.data;

        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);

        return image.rgbSwapped();

    }

    else if (mat.type() == CV_8UC4)

{

    const uchar* pSrc = (const uchar*)mat.data;

        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);

        return image.copy();

    }

        return QImage();

}

6.系统调度

6.1事件循环机制

QT事件循环是Qt框架中处理事件的核心机制,它确保了应用程序能够响应并处理各种异步事件,事件循环通过一个事件队列来管理和调度事件。当队列中有事件时,事件循环会从队列中依次取出事件并处理,直到队列为空或者事件循环被中断。

6.2信号&槽机制

QT信号槽是Qt框架中一种独特且强大的对象间通信机制。信号(signal)是对象发出的一种特定事件,而槽(slot)则是用于响应这些信号的特定函数或方法。当某个对象发出信号时,与之相关联的槽函数会被自动调用,从而实现了对象间的通信和协作。

信号和槽的连接可以是一对一、多对一、一对多或者多对多,这使得对象间的通信非常灵活。同时,信号和槽机制还具有解耦和灵活性的优点,因为对象之间通过信号和槽进行通信,彼此之间不需要显式的引用,从而实现了松耦合的设计。此外,这种机制还具有可扩展性,因为可以动态地连接和断开信号和槽,使得系统更容易扩展和维护。

在程序开始就新建一个线程,用于专门处理图像并计数,这样异步的设计将鼠标事件,绘图事件以及视频处理异步解耦,这种设计方式不仅提高了程序运行速度,而且使得人机交互更加灵活。

7.模块依赖

SqLite,QT-5.15.2,OpenCV-4.5.2

8.运行指导

在Windows下直接解压压缩包,双击exe文件即可执行;启动之初会加载一段时间,这是机器学习的过程;由于没有外接摄像头,因此只在可执行程序目录下放了一段模拟视频,视频较短,视频播放结束程序就停止运行。

相关文章:

车流量监控系统

1.项目介绍 本文档是对于“车流量检测平台”的应用技术进行汇总&#xff0c;适用于此系统所有开发&#xff0c;测试以及使用人员&#xff0c;其中包括设计背景&#xff0c;应用场景&#xff0c;系统架构&#xff0c;技术分析&#xff0c;系统调度&#xff0c;环境依赖&#xf…...

LAMP集群分布式实验报告

前景&#xff1a; 1.技术成熟度和稳定性&#xff1a; LAMP架构&#xff08;Linux、Apache、MySQL、PHP&#xff09;自1998年提出以来&#xff0c;经过长时间的发展和完善&#xff0c;已经成为非常成熟和稳定的Web开发平台。其中&#xff0c;Linux操作系统因其高度的灵活性和稳…...

vue3中函数必须有返回值么?

在 Vue 3 中&#xff0c;特别是涉及到Composition API的使用时&#xff0c;setup() 函数确实必须有返回值。setup() 函数是组件的入口点&#xff0c;它的返回值会被用来决定哪些数据和方法是可被模板访问的。返回的对象中的属性和方法可以直接在模板中使用。如果setup()没有返回…...

经常用到的函数

创建文件夹和删除文件夹的函数 def make_dirs(*dirs):for new_dir in dirs:if not os.path.exists(new_dir):try:os.makedirs(new_dir)except RuntimeError:return Falsereturn Truedef remove_files(file_path_list):""" 删除列表中指定路径文件Args:file_pat…...

vue3学习(六)

前言 接上一篇学习笔记&#xff0c;今天主要是抽空学习了vue的状态管理&#xff0c;这里学习的是vuex&#xff0c;版本4.1。学习还没有学习完&#xff0c;里面有大坑&#xff0c;难怪现在官网出的状态管理用Pinia。 一、vuex状态管理知识点 上面的方式没有写全&#xff0c;还有…...

[数据集][目标检测]猫狗检测数据集VOC+YOLO格式8291张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;8291 标注数量(xml文件个数)&#xff1a;8291 标注数量(txt文件个数)&#xff1a;8291 标注…...

简单模拟实现shell(Linux)

目录​​​​​​​ 前言 展示效果 实现代码 前言 该代码模拟了shell的实现&#xff0c;也就是解析类似于“ls -a -l"的命令&#xff0c;当我们启动我们自己写的shell的可执行程序时&#xff0c;我们输入"ls"的命令&#xff0c;也可以展示出在shell中输入&…...

SQL深度解析:从基础到高级应用

SQL&#xff08;Structured Query Language&#xff09;是用于管理关系型数据库的语言&#xff0c;广泛应用于数据管理、分析和查询。本文将详细介绍SQL的基础知识、高级特性以及一些常见的代码示例&#xff0c;帮助您全面掌握SQL的应用。 一、SQL基础语法 数据库操作 创建数据…...

乡村振兴与脱贫攻坚相结合:巩固拓展脱贫攻坚成果,推动乡村全面振兴,建设更加美好的乡村生活

目录 一、引言 二、巩固拓展脱贫攻坚成果 1、精准施策&#xff0c;确保稳定脱贫 2、强化政策支持&#xff0c;巩固脱贫成果 3、激发内生动力&#xff0c;促进持续发展 三、推动乡村全面振兴 1、加快产业发展&#xff0c;增强乡村经济实力 2、推进乡村治理体系和治理能力…...

[AI Google] Google I/O 2024: 为新一代设计的 I/O

编辑注&#xff1a;以下是 Sundar Pichai 在 I/O 2024 上讲话的编辑版&#xff0c;并包含了更多在舞台上宣布的内容。查看我们收藏中的所有公告。 Google 完全进入了我们的 Gemini 时代。 在开始之前&#xff0c;我想反思一下我们所处的这一刻。我们已经在 AI 上投资了十多年…...

CentOS配置DNS

1.打开/etc/resolv.conf文件 sudo vi /etc/resolv.conf2.添加配置 nameserver 114.114.114.1143.保存并关闭文件。 4.为了确保配置生效&#xff0c;重启网络服务或重启系统。例如&#xff1a; 重启网络&#xff1a; sudo systemctl restart network重启系统&#xff1a; …...

ArcGIS空间数据处理、空间分析与制图;PLUS模型和InVEST模型的原理,参量提取与模型运行及结果分析;土地利用时空变化以及对生态系统服务的影响分析

工业革命以来&#xff0c;社会生产力迅速提高&#xff0c;人类活动频繁&#xff0c;此外人口与日俱增对土地的需求与改造更加强烈&#xff0c;人-地关系日益紧张。此外&#xff0c;土地资源的不合理开发利用更是造成了水土流失、植被退化、水资源短缺、区域气候变化、生物多样性…...

Linux基于V4L2的视频捕捉

简介 linux环境使用V4l2实现摄像头捕捉&#xff0c;界面流畅播放并可以保存图片到本地。 代码 void VideoCapture::run() {qDebug() << "VideoCapture start";// 打开设备int fd open("/dev/video0", O_RDWR);if(fd < 0){qDebug("video设…...

ECS搭建2.8版本的redis

要在ECS&#xff08;Elastic Compute Service&#xff09;上手动搭建Redis 2.8版本&#xff0c;你可以按照以下步骤操作&#xff1a; 步骤1&#xff1a;更新系统和安装依赖 首先&#xff0c;登录到你的ECS实例&#xff0c;确保系统是最新的并安装必要的依赖包&#xff1a; s…...

[机器学习]GPT LoRA 大模型微调,生成猫耳娘

往期热门专栏回顾 专栏描述Java项目实战介绍Java组件安装、使用&#xff1b;手写框架等Aws服务器实战Aws Linux服务器上操作nginx、git、JDK、VueJava微服务实战Java 微服务实战&#xff0c;Spring Cloud Netflix套件、Spring Cloud Alibaba套件、Seata、gateway、shadingjdbc…...

代码随想录算法训练营Day24|216.组合总和III、17.电话号码的字母组合

组合总和III 216. 组合总和 III - 力扣&#xff08;LeetCode&#xff09; 思路和昨日的组合题类似&#xff0c;但注意对回溯算法中&#xff0c;收获时的条件需要写对&#xff0c;path的长度要为k的同时&#xff0c;path中元素总和要为n。 class Solution { public:vector<…...

【Python系列】Python 中方法定义与方法调用详解

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

Java 基础面试300题 (201-230)

Java 基础面试300题 &#xff08;201-230&#xff09; 201.下面代码片段的输出是什么&#xff1f; Predicate<Integer> numberChecker (num)–> num > 20; int input 10; System.out.println(input” greater than 20–”numberChecker.test(input)); //Line 1…...

Go-知识并发控制Context

Go-知识并发控制Context 1. 介绍2. 实现原理2.1 接口定义2.2 Deadline()2.3 Done()2.4 Err()2.5 Value() 3. 空 context4. cancelCtx4.1 Done()4.2 Err()4.3 cancel()4.4 WithCancel4.5 例子4.6 总结 5. timerCtx5.1 Deadline5.2 cancel5.3 WithDeadline5.4 WithTimeout5.5 例子…...

Vue + Nodejs + socket.io 实现聊天

Vue 代码 // 安装 socket.io-clientnpm i socket.io-clientimport io from socket.io-client;mounted () {// * location.origin 表示你的 socket 服务地址// * /XXXX/socket.io 表示 你的 socket 在服务器配置的 访问地址let socket io(location.origin, {path: "/XX…...

cocos creator 3.x实现手机虚拟操作杆

简介 在许多移动游戏中&#xff0c;虚拟操纵杆是一个重要的用户界面元素&#xff0c;用于控制角色或物体的移动。本文将介绍如何在Unity中实现虚拟操纵杆&#xff0c;提供了一段用于移动控制的代码。我们将讨论不同类型的虚拟操纵杆&#xff0c;如固定和跟随&#xff0c;以及如…...

【数据分享】中国电力年鉴(2004-2022)

大家好&#xff01;今天我要向大家介绍一份重要的中国电力统计数据资源——《中国电力年鉴》。这份年鉴涵盖了从2004年到2022年中国电力统计全面数据&#xff0c;并提供限时免费下载。&#xff08;无需分享朋友圈即可获取&#xff09; 数据介绍 自1993年首次出版以来&#xf…...

两个数组的交集Ⅱ-力扣

想到的解法是使用两个map来进行记录&#xff0c;mp1用来统计num1中每个元素出现的次数。当nums2的元素能够在mp1中查找到时&#xff0c;将这个元素添加到mp2&#xff0c;按照这个规则统计得到nums2和nums1重复的元素&#xff0c;mp2中的value记录了nums2中这个元素出现的次数最…...

【TCP协议中104解析】wireshark抓取流量包工具,群殴协议解析基础

Tcp ,104 ,wireshark工具进行解析 IEC104 是用于监控和诊断工业控制网络的一种标准&#xff0c;而 Wireshark则是一款常用的网络协议分析工具&#xff0c;可以用干解析TEC104 报文。本文将介绍如何使用 Wireshark解析 IEC104报文&#xff0c;以及解析过 程中的注意事项。 一、安…...

[个人笔记] 记录docker-compose使用和Harbor的部署过程

容器技术 第三章 记录docker-compose使用和Harbor的部署过程 容器技术记录docker-compose使用和Harbor的部署过程Harborhttps方式部署&#xff1a;测试环境部署使用自签名SSL证书https方式部署&#xff1a;正式环境部署使用企业颁发的SSL证书给Docker守护进程添加Harbor的SSL证…...

详细介绍运算符重载函数,清晰明了

祝各位六一快乐~ 前言 1.为什么要进行运算符重载&#xff1f; C中预定义的运算符的操作对象只能是基本数据类型。但实际上&#xff0c;对于许多用户自定义类型&#xff08;例如类&#xff09;&#xff0c;也需要类似的运算操作。这时就必须在C中重新定义这些运算符&#xff…...

国内外知名的低代码开发平台下载地址

以下是国内外几款低代码开发平台的列表&#xff0c;包含了下载地址、适应操作系统、是否可以独立部署、优点、缺点以及是否包含流程引擎的信息。 平台名称 下载地址 适应操作系统 是否可以独立部署 优点 缺点 是否包含流程引擎 国内平台 阿里云宜搭 阿里云官网 跨平台…...

【Pr学习】01新建项目起步

【Pr学习】01新建项目起步 1、新建项目2.序列设置2.1新建序列2.2序列参数讲解2.3自定义设置 3.PR窗口认识3.1 项目窗口3.2 源窗口2.4 保存面板 4.剪辑导入4.1 素材导入4.2 视图切换4.3 时间轴4.4轨道工具4.5 节目窗口素材导入 5.基础操作5.1 取消视频音频链接5.2 单独渲染&…...

【Redis延迟队列】redis中的阻塞队列和延迟队列

阻塞队列&#xff08;RBlockingQueue&#xff09; 作用和特点&#xff1a; 实时性&#xff1a;阻塞队列用于实时处理消息。生产者将消息放入队列&#xff0c;消费者可以立即从队列中取出并处理消息。阻塞特性&#xff1a;如果队列为空&#xff0c;消费者在尝试获取消息时会被…...

el-tree常用操作

一、定义 <el-treeclass"myTreeClass":data"dirTreeData":props"dirTreeProps":filter-node-method"filterDirTree":expand-on-click-node"false"node-key"id"node-click"dirTreeNodeClick":allow-…...

SQL 语言:存储过程和触发器

文章目录 基本概述创建触发器更改和删除触发器总结 基本概述 存储过程&#xff0c;类似于高阶语言的函数或者方法&#xff0c;包含SQL语句序列&#xff0c;是可复用的语句&#xff0c;保存在数据库中&#xff0c;在服务器中执行。特点是复用&#xff0c;提高了效率&#xff0c…...

Ubuntu Linux 24.04 使用certbot生成ssl证书

设置域名 1. 将需要生成SSL证书的域名解析到IP地址 idealand.xyz <> 64.176.82.190 检查防火墙的设置 1. 首先查看防火墙的状态&#xff1a; # ufw status 2. 如果防火墙开启了&#xff0c;要开放80和443端口用于certbot验证 # ufw allow 80 # ufw allow 443 生…...

Vivado 比特流编译时间获取以及FPGA电压温度获取(实用)

Vivado 比特流编译时间获取以及FPGA电压温度获取 语言 &#xff1a;Verilg HDL 、VHDL EDA工具&#xff1a;ISE、Vivado Vivado 比特流编译时间获取以及FPGA电压温度获取一、引言二、 获取FPGA 当前程序的编译时间verilog中直接调用下面源语2. FPGA电压温度获取&#xff08;1&a…...

Window下VS2019编译WebRTC通关版

这段时间需要实现这样一个功能&#xff0c;使用WebRTC实现语音通话功能&#xff0c;第一步要做的事情就是编译WebRTC源码&#xff0c;也是很多码友会遇到的问题。 经过我很多天的踩坑终于踩出来一条通往胜利的大路&#xff0c;下面就为大家详细介绍&#xff0c;编译步骤以及踩…...

【云原生 | 60】Docker中通过docker-compose部署kafka集群

&#x1f341;博主简介&#xff1a; &#x1f3c5;云计算领域优质创作者 &#x1f3c5;2022年CSDN新星计划python赛道第一名 &#x1f3c5;2022年CSDN原力计划优质作者 &#x1f3c5;阿里云ACE认证高级工程师 &#x1f3c5;阿里云开发者社区专…...

allure测试报告用例数和 pytest执行用例数不相同问题

我出现的奇怪问题&#xff1a; pytest执行了9条用例&#xff0c;但是测试报告确只显示3条用例 我将其中的一个代码删除后&#xff0c;发现allure测试报告又正常了 我觉得很奇怪这个代码只是删除了二维数组的第一列&#xff0c;我检查了半天都找不到问题&#xff0c;只有降低版本…...

Ubuntu 离线安装 gcc、g++、make 等依赖包

前言 项目现场的服务器无法连接互联网&#xff0c;需要提前获取 gcc、g、make 等依赖包。 一、如何获取依赖包 需要准备一台可以连接互联网的电脑&#xff08;如&#xff1a;个人电脑上的虚拟机安装一个与服务器一样的系统&#xff09;&#xff0c;用于下载依赖包。之后把通过…...

Vxe UI vxe-upload 上传组件,显示进度条的方法

vxe-upload 上传组件 查看官网 https://vxeui.com 显示进度条很简单&#xff0c;需要后台支持进度就可以了&#xff0c;后台实现逻辑具体可以百度&#xff0c;这里只介绍前端逻辑。 上传附件 相关参数说明&#xff0c;具体可以看文档&#xff1a; multiple 是否允许多选 li…...

探索API接口:技术深度解析与应用实践

在当今的软件开发和数据交换领域&#xff0c;API&#xff08;应用程序编程接口&#xff09;已经成为了一个不可或缺的工具。它允许不同的软件应用程序或组件之间进行交互和通信&#xff0c;从而实现了数据的共享和功能的扩展。本文将深入探讨API接口的技术原理、设计原则以及在…...

ARM-V9 RME(Realm Management Extension)系统架构之系统安全能力的系统隔离属性

安全之安全(security)博客目录导读 目录 一、系统隔离属性 1、系统配置完整性 1.1、时间隔离 2、关键错误的报告 一、系统隔离属性 1、系统配置完整性 MSD必须确保任何可能危及其安全保证的系统寄存器的正确性和完整性。例如&#xff0c;MSD必须确认内存控制器配置是一致…...

一个班有n个学生,需要把每个学生的简单材料(姓名和学号)输入计算机保存。然后可以通过输入某一学生的姓名查找其有关资料。

当输入一个姓名后&#xff0c;程序就查找该班中有无此学生&#xff0c;如果有&#xff0c;则输出他的姓名和学号&#xff0c;如果查不到&#xff0c;则输出"本班无此人"。 为解此问题&#xff0c;可以分别编写两个函数&#xff0c;函数input_data用来输人n个…...

python的range() 函数

range() 函数 《红楼梦》&#xff0c;又名《石头记》&#xff0c;实际上是一颗神石在人间游历的故事。而这块石头&#xff0c;就是我们的主人公贾宝玉。神石在投胎成宝玉前&#xff0c;向茫茫大士和渺渺真人讲起了自己的故事&#xff1a; 女娲氏炼石补天之时&#xff0c;于大…...

ClickHouse数据管理与同步的关键技术

2024年 5 月 18 日&#xff0c;ClickHouse官方首届杭州 Meetup 活动成功举行。本次活动由 ClickHouse 和阿里云主办&#xff0c;NineData 和云数据库技术社区协办。围绕ClickHouse的核心技术、应用案例、最佳实践、数据管理、以及迁移同步等方面&#xff0c;和行业专家展开交流…...

【一竞技DOTA2】东南亚Bleed战队官宣Emo正式加盟

1、近日东南亚Bleed战队正式发布公告官宣&#xff0c;中国选手Emo以及来自蒙古选手Se加盟战队。 【公告内容如下】 我们很高兴宣布&#xff0c;战队DOTA2名单中添加了两位新成员&#xff0c;请和我们一起欢迎来自中国经验丰富的老将Emo以及来自蒙古的后起之秀Se 一号位&#…...

算法学习笔记(7.3)-贪心算法(最大切分乘问题)

目录 ##问题描述 ##问题思考 ##贪心策略确定 ##代码实现 ##时间复杂度 ##正确性验证 ##问题描述 给定一个正整数 &#x1d45b; &#xff0c;将其切分为至少两个正整数的和&#xff0c;求切分后所有整数的乘积最大是多少 ##问题思考 假设我们将 &#x1d45b; 切分为 &…...

大型企业用什么文件加密软件,五款适合企业的文件加密软件

大型企业在选择文件加密软件时&#xff0c;通常会倾向于那些能够提供全面数据保护、具有高度可定制性、易于管理且能适应复杂组织结构的解决方案。以下是一些适合大型企业使用的文件加密软件&#xff1a; 1.域智盾软件&#xff1a; 作为一款企业级文件加密软件&#xff0c;支持…...

【数据结构】二叉树运用及相关例题

文章目录 前言查第K层的节点个数判断该二叉树是否为完全二叉树例题一 - Leetcode - 226反转二叉树例题一 - Leetcode - 110平衡二叉树 前言 在笔者的前几篇篇博客中介绍了二叉树的基本概念及基本实现方法&#xff0c;有兴趣的朋友自己移步看看。 这篇文章主要介绍一下二叉树的…...

Java基础知识点(反射、注解、JDBC、TCP/UDP/URL)

文章目录 反射反射的定义class对象反射的操作 注解注解的定义注解的应用注解的分类基准注解元注解 自定义注解自定义规则自定义demo JDBCTCP/UDP/URLTCPUDPURL 反射 反射的定义 Java Reflection是Java被视为动态语言的基础啊&#xff0c; 反射机制允许程序在执行期间接入Refl…...

postgressql——Tuple学习(2)

Tuple含义 作用 PG并没有像Oracle那样的undo来存放旧数据&#xff0c;而且PG没有真正意义上的delete&#xff0c;而是将旧版本直接存放于relation文件中&#xff0c;也就是成为了dead tuple。我们可以理解成“过期的数据”含义 tuple就相当于一个存储数据的小容器&#xff0c;…...

Linux日志管理

文章目录 一、日志管理概述1.1、日志管理介绍1.2、日志管理的重要性1.3、日志管理的组件1.4、日志管理的流程1.5、日志管理的挑战 二、日志分类介绍2.1、windows日志类别2.1.1、Application Log2.1.2、Security Log2.1.3、System Log2.1.4、Setup Log2.1.5、ForwardedEvents Lo…...