网站建设推广代理带动画引导的网站

diannao/2026/1/25 20:59:51/文章来源:
网站建设推广代理,带动画引导的网站,网络营销毕业后做什么工作,常州seo第一人目录 1. 作者介绍2. 目标跟踪算法介绍2.1 目标跟踪背景2.2 目标跟踪任务分类2.3 目标跟踪遇到的问题2.4 目标跟踪方法 3. 卡尔曼滤波的目标跟踪算法介绍3.1 所用数据视频说明3.2 卡尔曼滤波3.3 单目标跟踪算法3.3.1 IOU匹配算法3.3.2 卡尔曼滤波的使用方法 3.4 多目标跟踪算法 … 目录 1. 作者介绍2. 目标跟踪算法介绍2.1 目标跟踪背景2.2 目标跟踪任务分类2.3 目标跟踪遇到的问题2.4 目标跟踪方法 3. 卡尔曼滤波的目标跟踪算法介绍3.1 所用数据视频说明3.2 卡尔曼滤波3.3 单目标跟踪算法3.3.1 IOU匹配算法3.3.2 卡尔曼滤波的使用方法 3.4 多目标跟踪算法 4. 单目标跟踪算法实现4.1 环境搭建4.2 数据集使用方法4.3 准备工作4.4 main.py完整代码4.5 结果分析 5. 多目标跟踪算法实现5.1 程序文件架构5.2 const.py5.3 kalman.py5.4 matcher.py5.5 measure.py5.6 utils.py5.7 main.py5.8 结果分析 6. 鸣谢 1. 作者介绍 黄浩磊男西安工程大学电子信息学院2023级硕士研究生张宏伟人工智能课题组 研究方向智能视觉检测与工业自动化技术 电子邮件hhl57303163.com 2. 目标跟踪算法介绍 2.1 目标跟踪背景 目标跟踪是计算机视觉的关键任务之一在军工领域中警戒伺服、制导控制等功能实现中颇有建树也是工领程域中自动驾驶、智能机器人等项目的重要组成部分展现出了广泛的研究价值。目标跟踪就是在连续的视频序列中建立所要跟踪物体的位置关系从而得到物体完整的运动轨迹。其具体原理为给定图像第一帧的目标坐标位置计算在下一帧图像中目标的确切位置。在运动的过程中目标可能会呈现一些图像上的变化比如姿态或形状的变化、尺度的变化、背景遮挡或光线亮度的变化等。目标跟踪算法的研究也围绕着解决这些变化和具体的应用展开。 2.2 目标跟踪任务分类 对于目标跟踪的具体研究领域其可以分为以下几种任务 单目标跟踪——给定单个目标对该目标位置进行追踪多目标跟踪——一次性追踪多个目标位置行人重识别Person Re-ID——利用计算机视觉技术判断图像或者视频序列中是否存在特定行人的技术广泛被认为是一个图像检索的子问题多目标多摄像头跟踪MTMCT——在多个摄像头分别位于完全不同的位置进行拍摄的情况下对视频流中的多个目标进行同时跟踪和识别的技术姿态跟踪——通过对连续图像或视频数据进行处理实现对目标姿态的跟踪和重建。 在本篇中我们将主要实现对于一段视频中的行人进行单目标跟踪和多目标跟踪任务。 2.3 目标跟踪遇到的问题 虽然目标追踪的应用前景非常广泛但还是有一些问题限制了它的应用一般来说跟踪过程中的技术难点主要包括以下几个方面 遮挡Occlusion——遮挡是目标跟踪中最常见的挑战因素之一。遮挡又分为部分遮挡Partial Occlusion以及完全遮挡Full Occlusion。遮挡问题增加了目标跟踪的复杂性因为跟踪器需要处理目标的消失和重新出现同时确保在目标不可见期间不会错误地跟踪其他对象。该问题需要跟踪算法具备处理不同类型遮挡的能力并结合外观建模、运动模型和深度学习等方法来解决。形变Deformation——也是目标跟踪中的一大难题。目标表观的不断变化通常导致跟踪发生漂移Drift这些变化使得目标跟踪变得复杂和困难。形变问题是目标跟踪中的一个重要挑战要求跟踪算法具备适应性强、鲁棒性高以及对不同形变类型有针对性的处理策略以实现准确、稳定的目标跟踪。背景杂乱Background Clutter——指在复杂的场景中背景中存在大量的杂乱、复杂纹理、动态变化等从而影响了跟踪算法对目标对象的准确追踪。这种问题使得跟踪算法很容易将背景中的干扰与目标对象混淆导致误判和失效。跟踪算法需要具备识别和过滤背景干扰的能力以实现在复杂背景环境中准确、稳定的目标跟踪。尺度变换Scale Variation——是指目标对象在视频或图像序列中可能发生尺寸变化导致跟踪算法难以准确追踪目标的大小、位置和运动。这种问题通常涉及到目标的缩放或拉伸可能由于目标靠近或远离摄像机、目标的内部或外部运动引起。该问题要求跟踪算法具备对目标尺度变换的识别和适应能力以实现准确、稳定的目标跟踪。解决这个问题需要综合运用尺度估计、模型预测和多尺度处理等策略。 图1和图2所展示为上述问题的一些实例 图1. 光照以及模糊 图2. 形变以及遮挡 2.4 目标跟踪方法 目标跟踪是计算机视觉领域的一个重要任务有多种不同的方法和技术用于实现在视频序列或图像中跟踪目标对象。以下是目前目标跟踪中常用的一些方法 基于特征的跟踪 光流方法通过分析像素在连续帧之间的运动来跟踪目标常用于低级别的目标跟踪。稀疏特征跟踪例如使用角点或边缘特征来跟踪目标对象。稠密特征跟踪使用像素级别的特征来跟踪目标如基于深度学习的方法。 基于外观的跟踪 模板匹配使用目标的初始外观模板并在后续帧中寻找最匹配的区域来跟踪目标。相关滤波器使用滤波器来估计目标的位置常与目标的外观模型相关联。 基于运动的跟踪 卡尔曼滤波器用于估计目标的状态位置、速度等和外观模型通常用于跟踪稳定运动的目标。粒子滤波器通过采样一组粒子来估计目标的状态适用于非线性和非高斯分布的问题。 基于深度学习的跟踪 卷积神经网络CNN使用卷积神经网络来学习目标的特征表示以改善目标识别和跟踪性能。循环神经网络RNN可以用于建模目标的运动模式提高跟踪的稳定性。Siamese网络通过训练网络来度量目标与候选区域之间的相似性从而实现目标跟踪。 在线学习方法 增量式学习随着时间的推移自适应地更新目标模型以适应目标外观和运动的变化。强化学习使用强化学习技术来优化跟踪决策以最大程度地提高跟踪性能。 多目标跟踪 多目标跟踪同时跟踪多个目标考虑它们之间的相互关系和遮挡等复杂情况。 混合方法 许多跟踪器将不同的方法组合在一起以提高跟踪性能例如结合外观特征和运动信息。 这些方法在不同情境下都具有优势和劣势选择合适的方法取决于应用需求、场景复杂性以及计算资源的可用性。近年来深度学习技术在目标跟踪领域取得了显著进展但传统的计算机视觉方法仍然在特定情景下具有价值。因此通常会根据具体任务的需求来选择最适合的跟踪方法。 3. 卡尔曼滤波的目标跟踪算法介绍 3.1 所用数据视频说明 首先我们先说明一下程序所用到的数据视频。如图3所示为数据视频截图该视频来源于opencv官方数据库视频中包含了多位具有不同特征、不同行动方式的行人是一段非常经典的行人目标检测视频。本次所用的演示视频是从该视频中截取了一部分使用。 图3. 演示视频截图 图4. 边界框位置输出.txt文件 同时本次设计程序主要以基于卡尔曼滤波实现行人目标跟踪为主因此所使用数据视频已提前使用YOLO算法对视频中每一帧所有行人进行检测并输出边界框位置并将每帧的全部边界框位置输出成一个.txt文件如图4所示。其具体原理和方法可参考以下链接 目标检测—教你利用yolov5训练自己的目标检测模型一个很详细的讲解大家可以尝试照猫画虎 基于YOLOv5实现安全帽检测识别人类识别和安全帽识别没啥区别只是训练时数据集不一样 YOLO理解及边界框计算用来理解何为边界框以及它的标注原理 YOLOv5输出检测到的边界框的坐标、类别以及置信度边界框标注代码实现 3.2 卡尔曼滤波 卡尔曼滤波是一种用于估计系统状态的数学方法它被广泛应用于控制系统、导航、机器人技术、金融等领域。卡尔曼滤波的核心原理是通过融合来自不同来源的信息来估计系统的状态同时考虑了测量的不确定性和系统的动态特性。 以下是卡尔曼滤波的主要原理 系统模型卡尔曼滤波假设系统可以用线性动态方程来描述。这些方程通常表示为状态方程和观测方程。 状态方程描述系统状态如何随时间演变。通常表示为 x(k) F × x(k-1) B u(k) w(k)其中 x(k) 是系统状态向量F 是状态转移矩阵B 是控制输入矩阵u(k) 是控制输入w(k) 是过程噪声。观测方程描述测量如何与系统状态相关联。通常表示为 z(k) H * x(k) v(k)其中 z(k) 是测量向量H 是观测矩阵v(k) 是测量噪声。 预测阶段在这个阶段卡尔曼滤波器使用状态方程来预测系统的下一个状态和状态协方差。这一步通常包括以下几个步骤 预测状态根据状态方程和先前的状态估计估计系统的下一个状态。预测状态协方差根据状态方程和先前的状态协方差估计系统状态的不确定性。 更新阶段在这个阶段卡尔曼滤波器使用观测方程来融合测量值和预测的状态从而改进状态估计。这一步通常包括以下几个步骤 计算卡尔曼增益卡尔曼增益(Kalman Gain)表示了预测状态与测量之间的权衡以考虑测量的不确定性和预测的不确定性。更新状态估计使用卡尔曼增益来结合预测状态和测量得到更准确的状态估计。更新状态协方差使用卡尔曼增益来更新状态协方差以反映新的估计的不确定性。 循环迭代卡尔曼滤波是一个迭代过程系统的状态估计会随着时间的推移不断改进。每一次新的测量都会触发一次预测和更新过程以提高状态估计的准确性。 卡尔曼滤波的关键在于优雅地融合了动态系统的预测信息和测量信息同时考虑了这些信息的不确定性从而实现了对系统状态的有效估计。这种方法对于需要实时状态估计的应用非常有用例如导航系统、目标跟踪、自动驾驶汽车等领域。但要注意卡尔曼滤波的有效性在很大程度上取决于系统模型的准确性和噪声的统计特性。 3.3 单目标跟踪算法 3.3.1 IOU匹配算法 在学习如何将卡尔曼滤波应用到目标跟踪中之前我们首先需要了解目标跟踪中常用的一种方法——基于IOU的匹配算法。 IOUIntersection over Union匹配是目标检测和目标跟踪领域常用的一种方法用于衡量两个边界框通常是真实标注框和预测框之间的重叠程度。IOU匹配在评估模型性能、计算准确度以及进行多目标跟踪等任务中都有广泛应用。 IOU是通过计算两个边界框的交集面积与并集面积之间的比率来度量它们的重叠程度。IOU的计算公式如下 在目标检测和跟踪的场景中通常会有一组预测框和一组真实标注框。IOU匹配的主要目标是将预测框与对应的真实标注框进行匹配以评估预测框的准确度或者跟踪目标的连续性。具体的匹配过程如下 对于每个预测框计算其与所有真实标注框的IOU值。将每个预测框与具有最高IOU值的真实标注框进行匹配。这意味着一个预测框只会与一个真实标注框进行匹配而一个真实标注框也只会与一个预测框进行匹配。通常会设定一个IOU阈值例如0.5。如果某个预测框与最高IOU值的真实标注框的IOU大于等于阈值就认为这个预测框是正确匹配的否则认为这个预测框是误检测。对于未匹配到的真实标注框和预测框可以根据具体的任务和需求进行后续处理例如标记为漏检或者虚警。 我们以所用的数据视频举个例子在T0帧时我们指定其中一位行人为我们的跟踪目标如图5左侧红框所示我们假设称之为跟踪框T0 图5. 在T0帧时确定跟踪目标 而在接下来的T1帧中我们可以看到目标的位置发生变化而跟踪框T0的位置却不会变化如图6右侧所示 图6. 跟踪框T0在T1中的位置 此时我们需要使得跟踪框T0能发生更新重新定位到跟踪目标身上变成新的跟踪框T1那么就需要计算跟踪框T0位置与T1帧中所有检测到的行人边界框位置的IOU值通过最大IOU匹配来确定跟踪目标在T1帧时的位置从而更新跟踪框变为跟踪框T1。按此原理在T2帧时我们可以计算T2帧中所有行人位置与跟踪框T1位置的IOU来推断出跟踪框T2的位置不断迭代我们便可以得到每一帧中被跟踪目标的位置从而实现视频中单个目标的持续跟踪。 图7. 跟踪框T0跟新为跟踪框T1 IOU匹配的原理是基于物体的重叠度来评估预测框的准确性。如果IOU值足够高可以认为预测框与真实目标相匹配从而可以用于计算模型的准确率、召回率等指标或者在目标跟踪中维持目标的连续性。然而需要注意的是IOU匹配方法在一些情况下可能存在局限性例如处理重叠较大的目标或者处理目标数量变化较大的场景时。因此在实际应用中还可能会结合其他方法来进行目标匹配和跟踪。 3.3.2 卡尔曼滤波的使用方法 卡尔曼滤波Kalman Filter和最大IOU匹配法Intersection over Union Matching可以结合使用以改善目标跟踪的性能。卡尔曼滤波可以用于预测目标的状态而最大IOU匹配法可以用于关联检测和跟踪的目标。以下是将这两种方法结合使用的一般步骤 目标状态表示首先每个目标需要用状态向量来表示通常包括目标的位置如中心坐标或边界框的坐标、速度、加速度等信息。这是卡尔曼滤波需要的输入。 初始化卡尔曼滤波器在第一帧中对于每个检测到的目标初始化一个对应的卡尔曼滤波器。卡尔曼滤波器将用于对目标状态进行预测和更新。 预测阶段在每一帧中对于每个跟踪目标使用卡尔曼滤波器来进行状态的预测。这一步会提供关于目标在下一帧中可能位置的估计。 最大IOU匹配对于当前帧中的每个检测计算其与已跟踪目标的IOU值。最大IOU匹配法用于将检测与已有的跟踪目标关联起来。通常与某个检测具有最大IOU值的跟踪目标会被认为是最可能与之对应的目标。 更新阶段根据最大IOU匹配的结果将检测信息用于更新卡尔曼滤波器中的目标状态。这包括使用检测的位置信息来修正状态估计。 添加新目标对于未匹配到的检测可以将其视为新目标并初始化新的卡尔曼滤波器。 删除失踪目标如果某个目标在多帧中都未能与检测匹配成功可以将其标记为失踪目标并停止跟踪。 迭代处理重复上述步骤以连续迭代地进行目标跟踪。 通过结合卡尔曼滤波和最大IOU匹配法可以实现对目标的平滑跟踪和关联因为卡尔曼滤波会考虑目标状态的动态变化而最大IOU匹配法可以确保检测与目标之间的一致性。这种结合方法在目标跟踪中非常常见特别是在处理视频序列等连续数据时它可以提供更稳定的跟踪性能。但要注意卡尔曼滤波的性能取决于模型的质量和噪声的统计特性因此需要仔细调整参数和模型来适应不同的应用场景。 3.4 多目标跟踪算法 多目标跟踪是一个重要的计算机视觉和机器学习任务其目标是在连续帧中跟踪多个目标并将它们在不同帧之间进行关联。在多目标跟踪中加入最大权重匹配是一种常见的方法通常基于图论的思想用于解决多目标关联问题。 最大权重匹配是图论中的一个基本问题通常用于寻找一个带权重的二分图中的最佳匹配以使权重总和最大化。这个问题的经典算法是匈牙利算法Hungarian algorithm其原理如下 假设有一个带权重的二分图其中包括两组节点分别是左侧节点和右侧节点。我们的目标是找到一种匹配方式使得连接这些节点的边上的权重之和最大。 下面是将最大权重匹配引入多目标跟踪的一般实现步骤 目标表示首先每个目标需要在每一帧中进行表示。这通常包括目标的位置如边界框或轨迹以及与目标相关的特征或描述子如颜色、速度、外观特征等。这些信息将构成跟踪问题的输入数据。 构建关联图在每一帧中构建一个图其中包括两类节点目标节点和检测节点。目标节点表示已知的跟踪目标检测节点表示在当前帧中检测到的新目标候选。边表示目标节点和检测节点之间的关联关系通常使用目标与检测之间的相似性如距离、外观相似性等来确定边的权重。 最大权重匹配使用图论算法来解决关联问题。其中最大权重匹配算法如匈牙利算法Hungarian algorithm或者线性分配问题Linear Assignment Problem LAP可以用于找到使得总权重最大的节点匹配。这将确定哪些检测节点与已知目标节点关联以及哪些目标节点需要新建。 更新目标状态根据最大权重匹配的结果更新目标的状态位置、速度等以及任何与目标相关的信息。通常使用目标与检测之间的关联关系来更新目标的状态例如使用卡尔曼滤波或其他状态估计方法来融合检测信息和先前的目标状态。 处理未关联的目标在最大权重匹配后可能仍然存在未关联的目标或者未匹配的检测。你可以根据任务需求来处理这些未关联的目标例如保持它们的跟踪状态、删除它们或者将它们标记为新的目标。 迭代处理多目标跟踪是一个逐帧迭代的过程需要在每一帧中执行上述步骤。同时根据应用场景你可能需要考虑在多帧中维护目标的轨迹处理遮挡、目标消失和新目标出现等复杂情况。 最大权重匹配方法在多目标跟踪中通常表现出良好的性能但需要仔细选择相似性度量和匹配算法以适应具体的应用场景。此外考虑到实时性等要求还可以使用一些启发式方法来加速匹配过程。多目标跟踪是一个广泛研究的领域具体的实现会依赖于任务和数据的特点。 4. 单目标跟踪算法实现 4.1 环境搭建 在学习代码之前我们要确保自己的python环境中拥有numpy、matplotlib、opencv-python和networkx四个软件包软件包版本并无要求但尽量不要安装最新的版本防止更新或者删除了某些函数这下代码可不好改对于软件包的安装可以参考如何在VSCode中添加Python解释器并安装Python库。当然我们需要创建一个新的python项目工程。 4.2 数据集使用方法 这里给出程序所用的视频数据和已经使用YOLO检测输出的边界框位置.txt文件。 百度网盘链接 链接https://pan.baidu.com/s/1e6dwULkIaV_M969XlV53vg 提取码fm45 这里给出了所用的视频数据和标注文件夹其中“labels”文件夹中为每一帧的标注文件“testvideo1”为数据视频。我们需要在新建的python工程目录下创建新的文件夹并命名为“data”如图8所示 图8. 工程目录包含“data”文件夹 4.3 准备工作 接着我们需要在新创建的工程中新建一个.py文件并命名为“utils.py”其中会编写一些将会使用到的公式代码如下 import cv2# 将左上右下表示的框转换为中心点坐标和宽高表示的框 def xyxy_to_xywh(xyxy):center_x (xyxy[0] xyxy[2]) / 2center_y (xyxy[1] xyxy[3]) / 2w xyxy[2] - xyxy[0]h xyxy[3] - xyxy[1]return (center_x, center_y, w, h)# 在图像上绘制一个框 def plot_one_box(xyxy, img, color(0, 200, 0), targetFalse):xy1 (int(xyxy[0]), int(xyxy[1]))xy2 (int(xyxy[2]), int(xyxy[3]))if target:color (0, 0, 255)cv2.rectangle(img, xy1, xy2, color, 1, cv2.LINE_AA) # filled# 更新轨迹列表 def updata_trace_list(box_center, trace_list, max_list_len50):if len(trace_list) max_list_len:trace_list.append(box_center)else:trace_list.pop(0)trace_list.append(box_center)return trace_list# 绘制轨迹 def draw_trace(img, trace_list):更新trace_list,绘制trace:param trace_list::param max_list_len::return:for i, item in enumerate(trace_list):if i 1:continuecv2.line(img,(trace_list[i][0], trace_list[i][1]), (trace_list[i - 1][0], trace_list[i - 1][1]),(255, 255, 0), 3)# 计算IOU交并比 def cal_iou(box1, box2)::param box1: xyxy 左上右下:param box2: xyxy:return:x1min, y1min, x1max, y1max box1[0], box1[1], box1[2], box1[3]x2min, y2min, x2max, y2max box2[0], box2[1], box2[2], box2[3]# 计算两个框的面积s1 (y1max - y1min 1.) * (x1max - x1min 1.)s2 (y2max - y2min 1.) * (x2max - x2min 1.)# 计算相交部分的坐标xmin max(x1min, x2min)ymin max(y1min, y2min)xmax min(x1max, x2max)ymax min(y1max, y2max)inter_h max(ymax - ymin 1, 0)inter_w max(xmax - xmin 1, 0)intersection inter_h * inter_wunion s1 s2 - intersection# 计算iouiou intersection / unionreturn iou# 计算两个中心点之间的距离 def cal_distance(box1, box2):计算两个box中心点的距离:param box1: xyxy 左上右下:param box2: xyxy:return:center1 ((box1[0] box1[2]) // 2, (box1[1] box1[3]) // 2)center2 ((box2[0] box2[2]) // 2, (box2[1] box2[3]) // 2)dis ((center1[0] - center2[0]) ** 2 (center1[1] - center2[1]) ** 2) ** 0.5return dis# 将中心点坐标和宽高表示的框转换为左上右下表示的框 def xywh_to_xyxy(xywh):x1 xywh[0] - xywh[2] // 2y1 xywh[1] - xywh[3] // 2x2 xywh[0] xywh[2] // 2y2 xywh[1] xywh[3] // 2return [x1, y1, x2, y2]# 计算框1和框2的IOU if __name__ __main__:box1 [100, 100, 200, 200]box2 [100, 100, 200, 300]iou cal_iou(box1, box2)print(iou)# 修改框1的值box1.pop(0)box1.append(555)print(box1) 4.4 main.py完整代码 以下为单目标跟踪算法主代码 import os import cv2 import numpy as np from utils import plot_one_box, cal_iou, xyxy_to_xywh, xywh_to_xyxy, updata_trace_list, draw_trace# 单目标跟踪 # 检测器获得检测框全程只赋予1个ID有两个相同的东西进来时不会丢失唯一跟踪目标 # 检测器的检测框为测量值 # 目标的状态X [x,y,h,w,delta_x,delta_y],中心坐标宽高中心坐标速度 # 观测值 # 如何寻找目标的观测值 # 观测到的是N个框 # 怎么找到目标的观测值 # t时刻的框与t-1后验估计时刻IOU最大的框的那个作为观测值存在误差交叉情况下观测值会有误差 # 所以需要使用先验估计值进行融合# 状态初始化 initial_target_box [729, 238, 764, 339] # 目标初始bouding boxinitial_box_state xyxy_to_xywh(initial_target_box) initial_state np.array([[initial_box_state[0], initial_box_state[1], initial_box_state[2], initial_box_state[3],0, 0]]).T # [中心x,中心y,宽w,高h,dx,dy] IOU_Threshold 0.3 # 匹配时的阈值# 状态转移矩阵上一时刻的状态转移到当前时刻 A np.array([[1, 0, 0, 0, 1, 0],[0, 1, 0, 0, 0, 1],[0, 0, 1, 0, 0, 0],[0, 0, 0, 1, 0, 0],[0, 0, 0, 0, 1, 0],[0, 0, 0, 0, 0, 1]])# 状态观测矩阵 H np.eye(6)# 过程噪声协方差矩阵Qp(w)~N(0,Q)噪声来自真实世界中的不确定性, # 在跟踪任务当中过程噪声来自目标移动的不确定性突然加速、减速、转弯等 Q np.eye(6) * 0.1# 观测噪声协方差矩阵Rp(v)~N(0,R) # 观测噪声来自于检测框丢失、重叠等 R np.eye(6) * 1# 控制输入矩阵B B None # 状态估计协方差矩阵P初始化 P np.eye(6)if __name__ __main__:# 定义视频路径、标签路径和文件名video_path ./data/testvideo1.mp4label_path ./data/labelsfile_name testvideo1# 打开视频文件cap cv2.VideoCapture(video_path)# cv2.namedWindow(track, cv2.WINDOW_NORMAL)# 是否保存输出视频SAVE_VIDEO False# 如果需要保存输出视频设置视频编码器和帧率if SAVE_VIDEO:fourcc cv2.VideoWriter_fourcc(*XVID)out cv2.VideoWriter(kalman_output.avi, fourcc, 20, (768, 576))# ---------状态初始化---------------------------------------- # 初始化状态变量frame_counter 1X_posterior np.array(initial_state)P_posterior np.array(P)Z np.array(initial_state)trace_list [] # 用于保存目标box的轨迹while (True):# 逐帧捕获视频ret, frame cap.read()# 获取上一帧的后验估计将其用白色框表示last_box_posterior xywh_to_xyxy(X_posterior[0:4])plot_one_box(last_box_posterior, frame, color(255, 255, 255), targetFalse)# 如果视频结束跳出循环if not ret:break# print(frame_counter)# 读取当前帧对应的标签文件label_file_path os.path.join(label_path, file_name _ str(frame_counter) .txt)with open(label_file_path, r) as f:content f.readlines()max_iou IOU_Thresholdmax_iou_matched False# ---------使用最大IOU来寻找观测值------------for j, data_ in enumerate(content):data data_.replace(\n, ).split( )xyxy np.array(data[1:5], dtypefloat)plot_one_box(xyxy, frame)iou cal_iou(xyxy, xywh_to_xyxy(X_posterior[0:4]))# 如果IOU大于阈值认为找到了观测值if iou max_iou:target_box xyxymax_iou ioumax_iou_matched Trueif max_iou_matched True:# 如果找到了最大IOU BOX,则认为该框为观测值plot_one_box(target_box, frame, targetTrue)xywh xyxy_to_xywh(target_box)box_center (int((target_box[0] target_box[2]) // 2), int((target_box[1] target_box[3]) // 2))trace_list updata_trace_list(box_center, trace_list, 100)cv2.putText(frame, Tracking, (int(target_box[0]), int(target_box[1] - 5)), cv2.FONT_HERSHEY_SIMPLEX,0.7,(255, 0, 0), 2)# 计算dx,dydx xywh[0] - X_posterior[0]dy xywh[1] - X_posterior[1]Z[0:4] np.array([xywh]).TZ[4::] np.array([dx, dy])if max_iou_matched:# -----进行先验估计-----------------X_prior np.dot(A, X_posterior)box_prior xywh_to_xyxy(X_prior[0:4])# plot_one_box(box_prior, frame, color(0, 0, 0), targetFalse)# -----计算状态估计协方差矩阵P--------P_prior_1 np.dot(A, P_posterior)P_prior np.dot(P_prior_1, A.T) Q# ------计算卡尔曼增益---------------------k1 np.dot(P_prior, H.T)k2 np.dot(np.dot(H, P_prior), H.T) RK np.dot(k1, np.linalg.inv(k2))# --------------后验估计------------X_posterior_1 Z - np.dot(H, X_prior)X_posterior X_prior np.dot(K, X_posterior_1)box_posterior xywh_to_xyxy(X_posterior[0:4])# plot_one_box(box_posterior, frame, color(255, 255, 255), targetFalse)# ---------更新状态估计协方差矩阵P-----P_posterior_1 np.eye(6) - np.dot(K, H)P_posterior np.dot(P_posterior_1, P_prior)else:# 如果IOU匹配失败此时失去观测值那么直接使用上一次的最优估计作为先验估计# 此时直接迭代不使用卡尔曼滤波X_posterior np.dot(A, X_posterior)# X_posterior np.dot(A_, X_posterior)box_posterior xywh_to_xyxy(X_posterior[0:4])# plot_one_box(box_posterior, frame, color(255, 255, 255), targetFalse)box_center ((int(box_posterior[0] box_posterior[2]) // 2), int((box_posterior[1] box_posterior[3]) // 2))trace_list updata_trace_list(box_center, trace_list, 20)cv2.putText(frame, Lost, (box_center[0], box_center[1] - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.7,(255, 0, 0), 2)draw_trace(frame, trace_list)# 在图像上添加文本信息cv2.putText(frame, ALL BOXES(Green), (25, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 200, 0), 2)cv2.putText(frame, TRACKED BOX(Red), (25, 75), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)cv2.putText(frame, Last frame best estimation(White), (25, 100), cv2.FONT_HERSHEY_SIMPLEX, 0.7,(255, 255, 255), 2)# 显示图像cv2.imshow(track, frame)# 如果需要保存视频将帧写入输出视频文件if SAVE_VIDEO:out.write(frame)frame_counter frame_counter 1# 检测是否按下 q 键如果按下则退出循环。同时我们可以在cv2.waitKey(200)中改变数值大小来控制视频播放速度if cv2.waitKey(200) 0xFF ord(q):break# 当所有操作完成后释放视频捕获和关闭所有窗口cap.release()cv2.destroyAllWindows() 4.5 结果分析 运行main.py后会弹出一个新的窗口窗口中会按帧播放我们的目标跟踪结果这里我们放出两种方法的跟踪结果展示分别是基于最大IOU法的目标跟踪以及基于卡尔曼滤波改良的目标跟踪。 最大IOU匹配法结果 卡尔曼滤波改进后结果 由上述两种方法结果我们可以明显看出被跟踪目标在走到路灯处时被遮挡了被跟踪目标在这一帧中未被检测到也就是发生了漏检这也是上述目标跟踪常见的问题之一——遮挡。因此在这一帧计算IOU更新跟踪框时由于漏检使得并没有该帧中被跟踪目标的边界框位置从而导致没有超过设定阈值的最佳IOU值丢失跟踪目标。 而通过引入卡尔曼滤波之后可以让上一帧的检测框具有运动属性例如输入白框的dx,dy使用卡尔曼不断预测下一帧白框的位置从而使得白色框不再和之前一样来自于上一帧而是根据运动属性预测下一帧保持和当前检测框处于同一时间从而解决IOU匹配的问题。 5. 多目标跟踪算法实现 5.1 程序文件架构 我们需要新建一个python项目并将单目标跟踪项目的数据拷贝一份放入该项目目录下。 多目标跟踪由于加入了多特征方法因此相较于单目标跟踪较为复杂因此将该算法分为多个模块去实现程序文件架构如图10所示接下来我们将分步进行程序的编写与实现。 图9. 多目标跟踪程序文件架构 5.2 const.py # 路径 FILE_DIR ./data/labels VIDEO_PATH ./data/testvideo1.mp4 VIDEO_OUTPUT_PATH ./data/multi-object.mp4 FPS 30 # 帧率 Size (720, 360)GREEN (0, 250, 0) RED (0, 0, 250)COLOR_MEA GREEN COLOR_STA RED COLOR_MATCH (255, 255, 0)5.3 kalman.py import random import numpy as np import utils from matcher import MatcherGENERATE_SET 1 # 设置航迹起始帧数 TERMINATE_SET 7 # 设置航迹终止帧数class Kalman:def __init__(self, A, B, H, Q, R, X, P):# 固定参数self.A A # 状态转移矩阵self.B B # 控制矩阵self.H H # 观测矩阵self.Q Q # 过程噪声self.R R # 量测噪声# 迭代参数self.X_posterior X # 后验状态, 定义为 [中心x,中心y,宽w,高h,dx,dy]self.P_posterior P # 后验误差矩阵self.X_prior None # 先验状态self.P_prior None # 先验误差矩阵self.K None # kalman gainself.Z None # 观测, 定义为 [中心x,中心y,宽w,高h]# 起始和终止策略self.terminate_count TERMINATE_SET# 缓存航迹self.track [] # 记录当前航迹[(p1_x,p1_y),()]self.track_color (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))self.__record_track()def predict(self):预测外推:return:self.X_prior np.dot(self.A, self.X_posterior)self.P_prior np.dot(np.dot(self.A, self.P_posterior), self.A.T) self.Qreturn self.X_prior, self.P_priorstaticmethoddef association(kalman_list, mea_list):多目标关联使用最大权重匹配:param kalman_list: 状态列表存着每个kalman对象已经完成预测外推:param mea_list: 量测列表存着矩阵形式的目标量测 ndarray [c_x, c_y, w, h].T:return:# 记录需要匹配的状态和量测state_rec {i for i in range(len(kalman_list))}mea_rec {i for i in range(len(mea_list))}# 将状态类进行转换便于统一匹配类型state_list list() # [c_x, c_y, w, h].Tfor kalman in kalman_list:state kalman.X_priorstate_list.append(state[0:4])# 进行匹配得到一个匹配字典match_dict Matcher.match(state_list, mea_list)# 根据匹配字典将匹配上的直接进行更新没有匹配上的返回state_used set()mea_used set()match_list list()for state, mea in match_dict.items():state_index int(state.split(_)[1])mea_index int(mea.split(_)[1])match_list.append([utils.state2box(state_list[state_index]), utils.mea2box(mea_list[mea_index])])kalman_list[state_index].update(mea_list[mea_index])state_used.add(state_index)mea_used.add(mea_index)# 求出未匹配状态和量测返回return list(state_rec - state_used), list(mea_rec - mea_used), match_listdef update(self, meaNone):完成一次kalman滤波:param mea::return:status Trueif mea is not None: # 有关联量测匹配上self.Z meaself.K np.dot(np.dot(self.P_prior, self.H.T),np.linalg.inv(np.dot(np.dot(self.H, self.P_prior), self.H.T) self.R)) # 计算卡尔曼增益self.X_posterior self.X_prior np.dot(self.K, self.Z - np.dot(self.H, self.X_prior)) # 更新后验估计self.P_posterior np.dot(np.eye(6) - np.dot(self.K, self.H), self.P_prior) # 更新后验误差矩阵status Trueelse: # 无关联量测匹配上if self.terminate_count 1:status Falseelse:self.terminate_count - 1self.X_posterior self.X_priorself.P_posterior self.P_priorstatus Trueif status:self.__record_track()return status, self.X_posterior, self.P_posteriordef __record_track(self):self.track.append([int(self.X_posterior[0]), int(self.X_posterior[1])])if __name__ __main__:# 状态转移矩阵上一时刻的状态转移到当前时刻A np.array([[1, 0, 0, 0, 1, 0],[0, 1, 0, 0, 0, 1],[0, 0, 1, 0, 0, 0],[0, 0, 0, 1, 0, 0],[0, 0, 0, 0, 1, 0],[0, 0, 0, 0, 0, 1]])# 控制输入矩阵BB None# 过程噪声协方差矩阵Qp(w)~N(0,Q)噪声来自真实世界中的不确定性,# 在跟踪任务当中过程噪声来自于目标移动的不确定性突然加速、减速、转弯等Q np.eye(A.shape[0]) * 0.1# 状态观测矩阵H np.array([[1, 0, 0, 0, 0, 0],[0, 1, 0, 0, 0, 0],[0, 0, 1, 0, 0, 0],[0, 0, 0, 1, 0, 0]])# 观测噪声协方差矩阵Rp(v)~N(0,R)# 观测噪声来自于检测框丢失、重叠等R np.eye(H.shape[0]) * 1# 状态估计协方差矩阵P初始化P np.eye(A.shape[0])box [729, 238, 764, 339]X utils.box2state(box)k1 Kalman(A, B, H, Q, R, X, P)print(k1.predict())mea [730, 240, 766, 340]mea utils.box2meas(mea)print(k1.update(mea)) 5.4 matcher.py import networkx as nx import numpy as np import utilsclass Matcher:def __init__(self):passclassmethoddef match(cls, state_list, measure_list): # 两个list中单个元素数据结构都是[c_x, c_y, w, h].T最大权值匹配:param state_list: 先验状态list:param measure_list: 量测list:return: dict 匹配结果 eg:{state_1: mea_1, state_0: mea_0}graph nx.Graph()for idx_sta, state in enumerate(state_list):state_node state_%d % idx_stagraph.add_node(state_node, bipartite0)for idx_mea, measure in enumerate(measure_list):mea_node mea_%d % idx_meagraph.add_node(mea_node, bipartite1)score cls.cal_iou(state, measure)if score is not None:graph.add_edge(state_node, mea_node, weightscore)match_set nx.max_weight_matching(graph)res dict()for (node_1, node_2) in match_set:if node_1.split(_)[0] mea:node_1, node_2 node_2, node_1res[node_1] node_2return resclassmethoddef cal_iou(cls, state, measure):计算状态和观测之间的IOU:param state:ndarray [c_x, c_y, w, h].T:param measure:ndarray [c_x, c_y, w, h].T:return:state utils.mea2box(state) # [lt_x, lt_y, rb_x, rb_y].Tmeasure utils.mea2box(measure) # [lt_x, lt_y, rb_x, rb_y].Ts_tl_x, s_tl_y, s_br_x, s_br_y state[0], state[1], state[2], state[3]m_tl_x, m_tl_y, m_br_x, m_br_y measure[0], measure[1], measure[2], measure[3]# 计算相交部分的坐标x_min max(s_tl_x, m_tl_x)x_max min(s_br_x, m_br_x)y_min max(s_tl_y, m_tl_y)y_max min(s_br_y, m_br_y)inter_h max(y_max - y_min 1, 0)inter_w max(x_max - x_min 1, 0)inter inter_h * inter_wif inter 0:return 0else:return inter / ((s_br_x - s_tl_x) * (s_br_y - s_tl_y) (m_br_x - m_tl_x) * (m_br_y - m_tl_y) - inter)if __name__ __main__:# state_list [np.array([10, 10, 5, 5]).T, np.array([30, 30, 5, 5]).T]state_list []measure_list [np.array([12, 12, 5, 5]).T, np.array([28, 28, 5, 5]).T]match_dict Matcher.match(state_list, measure_list)print(match_dict)for state, mea in match_dict.items():print(state, mea) 5.5 measure.py import re import pathlibimport numpy as np import cv2 import constdef load_measurement(file_dir):根据file目录产生观测list:param file_dir: 每帧观测分别对应一个txt文件每个文件中多个目标观测逐行写入:return: 所有观测list[[帧1所有观测],[帧2所有观测]]files pathlib.Path(file_dir).rglob(testvideo1_*.txt)files sorted(files, keylambda x: int(re.findall(testvideo1_(.*?).txt, str(x))[0]))return [list(np.loadtxt(str(file), int, usecols[1, 2, 3, 4])) for index, file in enumerate(files)]if __name__ __main__:cap cv2.VideoCapture(const.VIDEO_PATH)mea_list load_measurement(const.FILE_DIR)for mea_frame_list in mea_list:ret, frame cap.read()for mea in mea_frame_list:# print(mea)cv2.rectangle(frame, tuple(mea[:2]), tuple(mea[2:]), const.COLOR_MEA, thickness1)cv2.imshow(Demo, frame)cv2.waitKey(100) # 显示 1000 ms 即 1s 后消失cap.release()cv2.destroyAllWindows() 5.6 utils.py import cv2 import numpy as npdef box2state(box):center_x (box[0] box[2]) / 2center_y (box[1] box[3]) / 2w box[2] - box[0]h box[3] - box[1]return np.array([[center_x, center_y, w, h, 0, 0]]).T # 定义为 [中心x,中心y,宽w,高h,dx,dy]def state2box(state):center_x state[0]center_y state[1]w state[2]h state[3]return [int(i) for i in [center_x - w/2, center_y - h/2, center_x w/2, center_y h/2]]def box2meas(box):center_x (box[0] box[2]) / 2center_y (box[1] box[3]) / 2w box[2] - box[0]h box[3] - box[1]return np.array([[center_x, center_y, w, h]]).T # 定义为 [中心x,中心y,宽w,高h]def mea2box(mea):center_x mea[0]center_y mea[1]w mea[2]h mea[3]return [int(i) for i in [center_x - w/2, center_y - h/2, center_x w/2, center_y h/2]]def mea2state(mea):return np.row_stack((mea, np.zeros((2, 1))))def state2mea(state):return state.X_prior[0:4]if __name__ __main__:# box1 [100, 100, 200, 200]# box2 [100, 100, 200, 300]# iou cal_iou(box1, box2)# print(iou)# box1.pop(0)# box1.append(555)# print(box1)print(mea2state(np.array([[1,2,3,4]]).T)) 5.7 main.py # -*- coding: utf-8 -*-import cv2 import numpy as np import const import utils import measure from kalman import Kalman# --------------------------------Kalman参数--------------------------------------- # 状态转移矩阵上一时刻的状态转移到当前时刻 A np.array([[1, 0, 0, 0, 1, 0],[0, 1, 0, 0, 0, 1],[0, 0, 1, 0, 0, 0],[0, 0, 0, 1, 0, 0],[0, 0, 0, 0, 1, 0],[0, 0, 0, 0, 0, 1]]) # 控制输入矩阵B B None # 过程噪声协方差矩阵Qp(w)~N(0,Q)噪声来自真实世界中的不确定性, # 在跟踪任务当中过程噪声来自于目标移动的不确定性突然加速、减速、转弯等 Q np.eye(A.shape[0]) * 0.1 # 状态观测矩阵 H np.array([[1, 0, 0, 0, 0, 0],[0, 1, 0, 0, 0, 0],[0, 0, 1, 0, 0, 0],[0, 0, 0, 1, 0, 0]]) # 观测噪声协方差矩阵Rp(v)~N(0,R) # 观测噪声来自于检测框丢失、重叠等 R np.eye(H.shape[0]) * 1 # 状态估计协方差矩阵P初始化 P np.eye(A.shape[0]) # -------------------------------------------------------------------------------def main():# 1.载入视频和目标位置信息cap cv2.VideoCapture(const.VIDEO_PATH) # 穿插着视频是为了方便展示meas_list_all measure.load_measurement(const.FILE_DIR)sz (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))fourcc cv2.VideoWriter_fourcc(m, p, 4, v) # opencv3.0video_writer cv2.VideoWriter(const.VIDEO_OUTPUT_PATH, fourcc, const.FPS, sz, True)# 2. 逐帧滤波state_list [] # 单帧目标状态信息存kalman对象frame_cnt 1for meas_list_frame in meas_list_all:# --------------------------------------------加载当帧图像------------------------------------ret, frame cap.read()if not ret:break# ---------------------------------------Kalman Filter for multi-objects-------------------# 预测for target in state_list:target.predict()# 关联mea_list [utils.box2meas(mea) for mea in meas_list_frame]state_rem_list, mea_rem_list, match_list Kalman.association(state_list, mea_list)# 状态没匹配上的更新一下如果触发终止就删除state_del list()for idx in state_rem_list:status, _, _ state_list[idx].update()if not status:state_del.append(idx)state_list [state_list[i] for i in range(len(state_list)) if i not in state_del]# 量测没匹配上的作为新生目标进行航迹起始for idx in mea_rem_list:state_list.append(Kalman(A, B, H, Q, R, utils.mea2state(mea_list[idx]), P))# -----------------------------------------------可视化-----------------------------------# 显示所有mea到图像上for mea in meas_list_frame:cv2.rectangle(frame, tuple(mea[:2]), tuple(mea[2:]), const.COLOR_MEA, thickness1)# 显示所有的state到图像上for kalman in state_list:pos utils.state2box(kalman.X_posterior)cv2.rectangle(frame, tuple(pos[:2]), tuple(pos[2:]), const.COLOR_STA, thickness2)# 将匹配关系画出来for item in match_list:cv2.line(frame, tuple(item[0][:2]), tuple(item[1][:2]), const.COLOR_MATCH, 3)# 绘制轨迹for kalman in state_list:tracks_list kalman.trackfor idx in range(len(tracks_list) - 1):last_frame tracks_list[idx]cur_frame tracks_list[idx 1]# print(last_frame, cur_frame)cv2.line(frame, last_frame, cur_frame, kalman.track_color, 2)cv2.putText(frame, str(frame_cnt), (0, 50), colorconst.RED, fontFacecv2.FONT_HERSHEY_SIMPLEX, fontScale1.5)cv2.imshow(Demo, frame)cv2.imwrite(./image/{}.jpg.format(frame_cnt), frame)video_writer.write(frame)cv2.waitKey(100) # 显示 1000 ms 即 1s 后消失frame_cnt 1cap.release()cv2.destroyAllWindows()video_writer.release()if __name__ __main__:main() 5.8 结果分析 运行main.py结果同样会以视频的形式播放出来结果如下所示。可以看到通过特征取得使得出现在画面中的每一位行人都会被跟踪直到在画面中失去目标。 6. 鸣谢 在此要特别感谢B站大佬oginwe所提供的思路与实现方法原方法视频链接 用卡尔曼滤波器打造一个简易单目标跟踪器 同时还有另一位大佬所修改的多目标跟踪方法大佬GitHub链接 基于卡尔曼滤波的多目标跟踪

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/88174.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

服务范围 网站建设公司做企业网站怎么接活

获取MD5、SHA1、SHA256指纹信息 通过命令的形式获取 winr调出黑窗口cd到证书所在目录输入keytool -list -v -keystore test.keystore,其中 test.keystore为你的证书名称加文件后缀按照提示输入你的证书密码,就可以查看证书的信息 通过uniapp云端查看(证书是在DClou…

建筑行业网站模版百度指数分析报告

1.如何对R语言中两种颜色之间进行细分 2.代码&#xff1a; x <- colorRampPalette(c("#FC8D62","#FDEAE6"))(12) #打印向量值 # 按字典顺序排序颜色值 x_sorted <- sort(x,decreasing TRUE)# 打印排序后的颜色值 print(x_sorted)#展示颜色 scales:…

购门网站建设内丘网站建设

文章目录 前言叶节点 Leafs1、行为 Action2、判断 Condition控制组件 Composites1、顺序执行器 Sequencer2、选择执行器 Selector3、概率选择执行器 Probability Selector4、权重选择执行器 Priority Selector5、平行执行器 Parallel6、轮流选择器 Flip Selector7、完整执行器 …

网站定制设计制作公司网站建设论文的中期报告

如何去区分一个功能测试工程师的水平高和低&#xff1f; 可以从很多个方面去检查&#xff0c;比如测试的思路&#xff0c; 比如测试用例的覆盖度&#xff1f;&#xff0c;比如测试出bug是否能够定位到根因&#xff1f; 上面说的各个方面都很合理&#xff0c;那我们平常如何如更…

dw做网站教程视频各大搜索引擎提交入口地址

注&#xff1a;此为笔者学习狂神说SpringBoot的笔记&#xff0c;其中包含个人的笔记和理解&#xff0c;仅做学习笔记之用&#xff0c;更多详细资讯请出门左拐B站&#xff1a;狂神说!!! 一、整合JDBC使用&#xff08;理解&#xff09; 创建项目 勾选依赖启动器 查看依赖 …

网站 续费wap网站在线生成app

这节课主要讲缓存的基本思想、缓存的优点、缓存的代价三个部分。 缓存的定义 先来看下缓存的定义。 & 缓存最初的含义&#xff0c;是指用于加速 CPU 数据交换的 RAM&#xff0c;即随机存取存储器&#xff0c;通常这种存储器使用更昂贵但快速的静态 RAM&#xff08;SRAM&…

怎样做视频直播网站wordpress关闭会员

作者&#xff1a;苏雷江摘要&#xff1a;在科技英语翻译中&#xff0c;如何正确的理解与表达英语词语对整个翻译过程起着至关重要的作用。本篇文章从词义的选择和词义的引申两个方面来具体阐述如何做到正确的理解与表达科技英语翻译中的英语词语。关键词&#xff1a;科技英语翻…

宁夏做网站的网页游戏软件制作专业

当涉及到网络通信时&#xff0c;OSI参考模型定义了七个层级来描述网络协议和通讯过程。以下是对每个层级的详细介绍&#xff1a; 物理层&#xff08;Physical Layer&#xff09;&#xff1a; 物理层负责将比特流传输到物理媒介上。确定电压、光信号等传输细节&#xff0c;并定义…

淄博网站制作定制视觉国家企业查询官网入口

I love exam 不知道为啥刚开始不写&#xff0c;那么简单的背包预处理dp&#xff0c;太菜了吧 fi,jf_{i,j}fi,j​对于第i门课来说花费j天得到的最大分数 gi,j,pg_{i,j,p}gi,j,p​考虑前i门课&#xff0c;花费j天复习得到的最大分数 #include<bits/stdc.h> using namespa…

网站建设 硬件投入网站安全检测服务

前几天部署Exchange2010时建立了几个通讯组邮箱&#xff0c;测试下来发现只有exchange内部组员进行邮件交流没有问题&#xff0c;外网发送到组邮箱时会收到#550 5.7.1 RESOLVER.RST.AuthRequired; authentication required ##的错误&#xff0c;当时没有找出问题原因&#xff0…

网站设计方案图事件营销ppt

没有服务器和公网IP&#xff0c;想要其他人访问自己做好的网站&#xff0c;使用这款简单免费的内网穿透小工具——ngrok&#xff0c;有了它轻松让别人访问你的项目~ 一、下载ngrok 官网地址&#xff1a;ngrok | Unified Application Delivery Platform for Developers&#x…

上海金山网站设计公司荣耀手机官网入口

不润湿(Nonwetting)/润湿不良(Poor Wetting) 通常润湿不良是指焊点焊锡合金没有很好的铺展开来,从而无法得到良好的焊点并直接影响到焊点的可靠性。 产生原因: 1. 焊盘或引脚表面的镀层被氧化,氧化层的存在阻挡了焊锡与镀层之间的接触; 2. 镀层厚度不够或是加工不良,很…

让家里的电脑做网站服务器连江建设局网站

谁年轻的时候没有遇见过几个渣男&#xff1f;没有买错过几双不合尺码的鞋子&#xff1f;渣男无法巧避&#xff0c;但是买到不合尺码的鞋子这样的囧事倒是可以有效避免的。下面一起来了解下鞋子尺码的量法吧。工具&#xff1a;纸张、笔步骤&#xff1a;1、赤脚踩在白纸上&#x…

人才招聘网站怎么做免费申请qq号

前言 由于最近打算交叉编译 python&#xff0c;依赖 libffi 库&#xff0c;而交叉编译 libffi 库&#xff0c;由于使用的是 github 上的 libffi&#xff0c;又提示 autoconf 版本太低了&#xff0c;所以&#xff0c;先更新 autoconf 的版本 当前 ubuntu 20.04 上安装的 autuco…

电商网站建设的特点营销推广的主要方法

关于 Logback 日志系统是一个线上项目必备的素质之一&#xff0c;代表性的日志框架 Log4j、SLF4J、Logback 这哥仨竟然是亲兄弟&#xff0c;他们有一个亲爹&#xff0c;那就是巨佬 Ceki Gulcu。 由于 Spring Boot 的默认日志框架选用的 Logback&#xff0c;再加上 Log4j2 之前…

一个网站绑定两个域名企业画册宣传设计

博主推荐延展咨询资深顾问 沈靓文章 装备制造企业产品具有单件产值大、技术含量高、生产周期长、完全个性化生产的特点&#xff0c;伴随着制造业整体水平的提高&#xff0c;近几年又兴起了异地制造、移动工厂等模式&#xff0c;而装备制造业现有的管理方式和信息化水平多不能适…

网站做3儿童车开场动画天津智能网站建设价位

项目需求有个数据需要处理,现有两个数组arr1和arr2,其中 arr1为[“香蕉”, “苹果”, “梨子”],arr2为 [{ checked: true, name: “苹果” }] ,现在想实现的目的是,只要有arr1里的项与arr2项里的name一致的话就将其checked设为true,否则设为false,最终得到的数组是arr3,…

网站项目计划书模板范文电子产品网站建设分析的摘要

滑动选择文本内容的组件。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 无 接口 TextPicker(options?: {range: string[] | string[][] | Resource | TextPickerRangeContent[] | Te…

有没有专业做steam创客的网站邢台网站制作哪里做

Rust是一门系统级别的编程语言&#xff0c;注重安全性、性能和并发。在这篇博客中&#xff0c;我们将介绍Rust中的变量、常量声明以及基本数据类型&#xff0c;并通过示例说明每一种类型的用法。 变量声明 在Rust中&#xff0c;使用 let 关键字声明变量。变量默认是不可变的&…

防钓鱼网站宣传网店营销的推广方法有哪些

NVMe前世今生 1 NVMe的由来2 NVMe工作原理3 NVMe优点4 NVMe适用场景 本文属于《 NVMe协议基础系列教程》之一&#xff0c;欢迎查看其它文章。 1 NVMe的由来 目前机械硬盘大多数使用 SATA (Serial ATA Advanced Host Controller Interface) 接口&#xff0c;接口协议为 AHCI&a…