基于YOLOv8与DeepSORT实现多目标跟踪——算法与源码解析

一、概述

"目标跟踪 (Object Tracking)"是机器视觉领域中的一个重要研究领域。根据跟踪的目标数量,可以将其分为两大类:单目标跟踪 (Single Object Tracking,简称 SOT) 和多目标跟踪 (Multi Object Tracking,简称 MOT)。

多目标跟踪往往面临一些挑战,例如需要同时跟踪多个目标、目标可能频繁遮挡,这些因素使得目标跟丢成为一个常见问题。为了解决这些问题,可以借助跟踪器 DeepSORT 以及检测器 YOLO v8,从而构建一个高性能的实时多目标跟踪模型。

二、算法与项目流程

在深度学习领域中,目标跟踪是一项任务,旨在使用对象在空间和时间上的特征来预测它们在整个视频序列中的位置。从技术上讲,目标跟踪包括获取初始的目标检测集,为每个目标分配唯一的标识(ID),并在整个视频帧序列中跟踪它们,同时保持它们的标识不变。

1.目标检测与目标追踪

目标检测
在计算机视觉任务中,目标检测是在图像和视频(一系列的图像)中扫描和搜寻目标并给出目标所在图像的位置坐标(边界框):
在这里插入图片描述

在对视频进行检测时,也是把视频拆分成一帧帧来进行处理,这处理的过程中,检测所获取目标在帧与帧之间是无法进行关联的,假设,要对视频进行行人检测时,第一帧检测到了行人,第二帧也检测到同一个行人,但这两帧的这个行人目标是无法进行关联的,假设当前视频中有五个行人,目标检测只能检测到当前视频每一帧都有这个几个目标,并不能确定这几个目标中哪个是目标A,哪个是目标B,那个目标C等等。
视频示例:

行人检测

目标追踪
从上面的示例可以看出,当使用对象检测器时,只会得到一个包含对象位置信息的输出数组。这个输出数组可能包含多个坐标,每个坐标代表一个检测到的对象的位置。然而,这个输出数组通常不提供有关对象之间的关联信息,因此在查看输出数组时,你无法知道哪个坐标对应于哪个检测框。

与此不同,目标跟踪器在处理检测结果时为每个对象分配一个唯一的标识符(ID),并且会在整个帧序列中保持该ID不变,直到该对象的生命周期结束。这意味着,无论对象在视频中如何移动或遮挡,跟踪器都能够将相同的ID与该对象关联起来,以维护对象的一致性标识。这种ID分配使得跟踪器能够区分不同的对象,并跟踪它们的轨迹,而不仅仅是提供它们的位置信息。
视频示例:

运动目标追踪

目标检测和目标跟踪的区别
目标检测:

  • 目标检测任务要求同时完成对象的定位(即确定对象的边界框位置)和分类(即确定对象的类别)。这意味着目标检测算法必须不仅能够确定对象是否存在,还要知道它是什么。
  • 目标检测通常用于识别和定位图像或视频帧中的对象,通常需要明确的目标类别信息。

目标跟踪:

  • 目标跟踪任务更关注对象在帧与帧之间的连续性,通常更注重对象的运动特征,而不要求进行目标的分类。
  • 目标跟踪可以不涉及目标的类别,它的主要目标是维护对象的位置和轨迹,以实现在视频序列中的跟踪。

2.目标追踪的类型

目标跟踪器根据不同的分类标准可以分为多种类型:

  1. 单目标跟踪(Single Object Tracking,SOT):

    • 这类跟踪器专注于跟踪单个目标,即使在帧中存在多个其他对象。它们通常在第一帧中初始化目标的位置,然后在整个帧序列中跟踪它。一些传统的SOT方法包括CSRT、KCF等,但现在基于深度学习的跟踪器如GOTURN和SiamRPN表现更准确。
  2. 多目标跟踪(Multi Object Tracking,MOT):

    • 这些跟踪器具有能力同时跟踪多个目标,甚至可以跟踪不同类别的目标,并保持高速性能。它们通常在大规模数据集上进行训练,因此具有更高的准确性。一些强大的MOT算法包括DeepSORT、JDE和CenterTrack。
  3. 通过检测跟踪(Detection-Based Tracking):

    • 这种类型的跟踪算法首先使用目标检测器检测帧中的对象,然后跨帧执行数据关联以生成目标的轨迹,实现目标的跟踪。它们能够同时跟踪多个对象,并具备处理新对象引入的能力。即使目标检测失败,这些算法也有助于保持目标的跟踪。
  4. 无检测跟踪(Detection-Free Tracking):

    • 这种类型的跟踪算法需要手动初始化目标的位置,然后在后续帧中跟踪这些目标。这种方法通常使用传统的计算机视觉算法,而不依赖于目标检测。它们在一些特定应用中仍然有用。

不同类型的目标跟踪器适用于不同的应用场景,选择适当的跟踪器取决于任务要求、对象数量和性能要求。

3.目标跟踪的应用

  1. 交通监控:

    • 交通流量管理:目标跟踪可用于监控道路上的车辆,帮助交通管理部门更好地理解交通流量,进行交通优化和拥堵监测。
    • 违规行为检测:跟踪器可以检测和记录交通违规行为,如闯红灯、违规变道等,以提供证据用于执法。
  2. 体育运动/赛事:

    • 运动员跟踪:跟踪器可用于追踪运动员在比赛中的位置和移动,为教练和观众提供实时数据和分析。
    • 比赛统计:通过跟踪球员和球的位置,可以自动记录得分、犯规和其他比赛统计数据,减轻人工记录的工作量。
  3. 多摄像头监控:

    • 重新识别:核心思想是在多个摄像头之间重新识别相同的对象。如果一个对象在一个带有独特ID的摄像头中被跟踪,然后离开画面并在另一台摄像头中再次出现,跟踪器能够保持相同的ID,帮助重新识别对象。
    • 入侵检测:跟踪器可以用于监控区域,以检测不明对象的出现或不寻常的行为,从而帮助提高安全性。
  4. 智能监控和安全:

    • 安防监控:跟踪器可用于监控大型场所,如机场、商场和公共交通站,以监测潜在的威胁或异常行为。
    • 人脸跟踪:用于跟踪和记录人员的位置,特别是在人脸识别系统中,以进行出入记录或提供定位服务。
  5. 无人机和自动驾驶:

    • 无人机导航:目标跟踪可用于协助无人机导航和跟踪地面目标,例如搜索和救援、农业监测等。
    • 自动驾驶车辆:跟踪技术可以用于自动驾驶车辆中,以帮助车辆理解和预测其他交通参与者的行为。

4. 算法整合

在实际应用中,结合目标检测和目标跟踪可以实现更高效的处理方式。可以使用目标检测来定期锁定目标,然后使用目标跟踪来跟踪目标的位置,这样可以降低计算成本,同时可以定期进行目标分类,从而减轻系统的负担。这种方法可以有效提高处理速度,并在实际场景中得到广泛应用。

  1. 目标检测:

    • 使用目标检测算法在每一帧中检测出目标的位置和边界框。这一步可以提供当前帧中的目标位置信息。
  2. 特征提取:

    • 对每个检测到的目标,使用深度学习模型(如卷积神经网络,CNN)提取目标的特征表示。这些特征表示捕捉了目标的外观和特征,通常是高维向量。
  3. 目标匹配:

    • 将每个检测到的目标与先前帧中已跟踪的目标进行匹配,以确定目标的身份和轨迹。匹配过程通常考虑多个因素,包括目标的特征相似度、运动一致性、外观相似度等。
  4. 外观特征描述符:

    • 在目标匹配中,使用强大的外观特征描述符,如DeepSORT中所使用的,可以更准确地区分不同目标之间的相似度。这些描述符帮助算法区分不同目标,即使它们具有相似的外观特征。
  5. 处理复杂情况:

    • 目标跟踪还需要处理各种复杂情况,如目标的消失和重新出现、遮挡、变形等。算法需要具备鲁棒性,以支持长期目标跟踪,并能够应对这些挑战。

三、DeepSORT算法

DeepSORT是一种计算机视觉目标跟踪算法,旨在为每个对象分配唯一的ID并跟踪它们。它是SORT(Simple Online and Realtime Tracking,简单在线实时跟踪)算法的扩展和改进版本。SORT是一种轻量级目标跟踪算法,用于处理实时视频流中的目标跟踪问题。DeepSORT引入了深度学习技术,以加强SORT的性能,并特别关注在多个帧之间跟踪目标的一致性。

1. SORT目标追踪

SORT 是一种对象跟踪方法,其中使用卡尔曼滤波器和匈牙利算法等基本方法来跟踪对象,并声称比许多在线跟踪器更好。SORT 由以下 4 个关键组件组成:

  1. 检测:首先,在跟踪流程的第一步,目标检测器被用来检测当前帧中需要跟踪的目标对象。常用的目标检测器包括Faster R-CNN、YOLO等。

  2. 估计:在估计阶段,检测结果从当前帧传播到下一帧,使用恒速模型来估计下一帧中目标的位置。当检测结果与已知的目标相关联时,检测到的边界框信息用于更新目标的状态,包括速度分量,这是通过卡尔曼滤波器框架来实现的。

  3. 数据关联:在数据关联步骤中,目标的边界框信息与检测结果结合,从而形成一个成本矩阵,该矩阵计算每个检测与已知目标的所有预测边界框之间的交并比(IOU)距离。然后,使用匈牙利算法来优化分配,以确保正确地将检测结果与目标关联起来。这个技术有助于解决遮挡问题并保持目标的唯一身份。

  4. 管理目标ID的创建与删除:跟踪模块负责创建和销毁目标的唯一身份(ID)。如果检测结果与目标的IOU小于某个预定义的阈值(通常称为IOUmin),则不会将检测结果与目标相关联,这表示目标未被跟踪。此外,如果在连续TLost帧中没有检测到目标,跟踪将终止该目标的轨迹,其中TLost是一个可配置的参数。如果目标重新出现,跟踪将在新的身份下恢复。

2. DeepSORT算法

SORT在目标跟踪的精度和准确性方面表现出色,但它在生成大量不断切换的ID轨道和遇到遮挡情况时表现不佳。这是因为SORT使用关联矩阵来进行数据关联,而这种方法在复杂场景下存在一些限制。

DeepSORT是一种进化的跟踪算法,它改进了数据关联的方式,引入了更好的关联度量。DeepSORT可被定义为一种跟踪算法,它不仅仅基于目标的速度和运动来进行跟踪,还结合了目标的外观特征。

为了实现这些改进,DeepSORT首先在实际跟踪之前离线训练了一个具有出色区分性的特征嵌入网络。这个网络在大规模人员重新识别数据集上进行了训练,以确保在目标跟踪的上下文中具有高度区分性的特征。

在DeepSORT中,余弦距离度量方法用于训练深度关联度量模型。根据DeepSORT的论文,余弦距离考虑了目标的外观信息,这在处理遮挡和运动估计失败的情况下尤为有用。这意味着余弦距离是一种度量方法,有助于在目标长时间遮挡或其他复杂情况下准确恢复目标的身份。

四、Yolov8目标检测

1.算法简介

YOLOv8是一种基于图像全局信息进行预测并且它是一种端到端的目标检测系统,最初的YOLO模型由Joseph Redmon和Ali Farhadi于2015年提出,并随后进行了多次改进和迭代,产生了一系列不同版本的YOLO模型,如YOLOv2、YOLOv3、YOLOv4,YOLOv5等。这些更新和迭代旨在提高模型的性能、精度和速度,使其在实际应用中更具竞争力。

YOLOv8的核心思想是将图像划分为网格,并在每个网格单元中预测物体的边界框和类别。这种设计使得YOLO非常适合实时目标检测应用,因为它可以在较短的时间内完成目标检测任务。

2. 算法源码与部署

关于YOLOv8目标检测的相关内容可以看之前的博客:YoloV8目标检测与实例分割——目标检测onnx模型推理。

五、目标检测与追踪源码解析

1.检测

在每一帧中,目标检测器识别并提取出边界框(bbox),这些边界框表示在当前帧中检测到的目标物体。

 def detect(self,cv_src):
        boxes, scores, class_ids = self.detector(cv_src)

        pred_boxes = []
        for i in range(len(boxes)):
            x1,y1 = int(boxes[i][0]),int(boxes[i][1])
            x2,y2 = int(boxes[i][2]),int(boxes[i][3])
            lbl = class_names[class_ids[i]]
            # print(class_ids[i])

            # if lbl in ['person','sack','elec','bag','box','caron']:
            #     continue

            pred_boxes.append((x1,y1,x2,y2,lbl,class_ids[i]))

        return cv_src,pred_boxes

2. 生成detections

从这些检测到的边界框中,生成称为"detections"的目标检测结果。每个detection通常包含有关目标的信息,如边界框坐标和可信度分数。

#  deep_sort.py
def update(self, bbox_xywh, confidences, ori_img):
    self.height, self.width = ori_img.shape[:2]
    # 提取每个bbox的feature
    features = self._get_features(bbox_xywh, ori_img)
    # [cx,cy,w,h] -> [x1,y1,w,h]
    bbox_tlwh = self._xywh_to_tlwh(bbox_xywh)
    # 过滤掉置信度小于self.min_confidence的bbox,生成detections
    detections = [Detection(bbox_tlwh[i], conf, features[i]) for i,conf in enumerate(confidences) if conf > self.min_confidence]
    # NMS (这里self.nms_max_overlap的值为1,即保留了所有的detections)
    boxes = np.array([d.tlwh for d in detections])
    scores = np.array([d.confidence for d in detections])
    indices = non_max_suppression(boxes, self.nms_max_overlap, scores)
    detections = [detections[i] for i in indices]
    ...

3. 卡尔曼滤波预测

对于已知的跟踪对象(“tracks”),在下一帧中进行卡尔曼滤波预测,以估计其新的位置和速度。

#  track.py
def predict(self, kf):
    """Propagate the state distribution to the current time step using a 
       Kalman filter prediction step.
    Parameters
    ----------
    kf: The Kalman filter.
    """
    self.mean, self.covariance = kf.predict(self.mean, self.covariance)  # 预测
    self.age += 1  # 该track自出现以来的总帧数加1
    self.time_since_update += 1  # 该track自最近一次更新以来的总帧数加1

4.使用匈牙利算法将预测后的tracks和当前帧中的detections进行匹配

这是DeepSORT中的核心步骤。DeepSORT使用匈牙利算法来将预测的tracks和当前帧的detections进行匹配。这个匹配可以采用两种级联方法:首先,通过计算马氏距离来估算预测对象与检测对象之间的关联,如果马氏距离小于指定的阈值,则将它们匹配为同一目标。其次,DeepSORT还使用外观特征余弦距离度量,通过一个重识别模型获得不同物体的特征向量,然后构建余弦距离代价函数,以计算预测对象与检测对象的相似度。这两个代价函数的结果都趋向于小,如果边界框接近且特征相似,则将它们匹配为同一目标。

#  tracker.py
def _match(self, detections):
    def gated_metric(racks, dets, track_indices, detection_indices):
        """
        基于外观信息和马氏距离,计算卡尔曼滤波预测的tracks和当前时刻检测到的detections的代价矩阵
        """
        features = np.array([dets[i].feature for i in detection_indices])
        targets = np.array([tracks[i].track_id for i in track_indices]
 # 基于外观信息,计算tracks和detections的余弦距离代价矩阵
        cost_matrix = self.metric.distance(features, targets)
 # 基于马氏距离,过滤掉代价矩阵中一些不合适的项 (将其设置为一个较大的值)
        cost_matrix = linear_assignment.gate_cost_matrix(self.kf, cost_matrix, tracks, 
                      dets, track_indices, detection_indices)
        return cost_matrix

    # 区分开confirmed tracks和unconfirmed tracks
    confirmed_tracks = [i for i, t in enumerate(self.tracks) if t.is_confirmed()]
    unconfirmed_tracks = [i for i, t in enumerate(self.tracks) if not t.is_confirmed()]

    # 对confirmd tracks进行级联匹配
    matches_a, unmatched_tracks_a, unmatched_detections = \
        linear_assignment.matching_cascade(
            gated_metric, self.metric.matching_threshold, self.max_age,
            self.tracks, detections, confirmed_tracks)

    # 对级联匹配中未匹配的tracks和unconfirmed tracks中time_since_update为1的tracks进行IOU匹配
    iou_track_candidates = unconfirmed_tracks + [k for k in unmatched_tracks_a if
                                                 self.tracks[k].time_since_update == 1]
    unmatched_tracks_a = [k for k in unmatched_tracks_a if
                          self.tracks[k].time_since_update != 1]
    matches_b, unmatched_tracks_b, unmatched_detections = \
        linear_assignment.min_cost_matching(
            iou_matching.iou_cost, self.max_iou_distance, self.tracks,
            detections, iou_track_candidates, unmatched_detections)
 
    # 整合所有的匹配对和未匹配的tracks
    matches = matches_a + matches_b
    unmatched_tracks = list(set(unmatched_tracks_a + unmatched_tracks_b))
    
    return matches, unmatched_tracks, unmatched_detections


# 级联匹配源码  linear_assignment.py
def matching_cascade(distance_metric, max_distance, cascade_depth, tracks, detections, 
                     track_indices=None, detection_indices=None):
    ...
    unmatched_detections = detection_indice
    matches = []
    # 由小到大依次对每个level的tracks做匹配
    for level in range(cascade_depth):
 # 如果没有detections,退出循环
        if len(unmatched_detections) == 0:  
            break
 # 当前level的所有tracks索引
        track_indices_l = [k for k in track_indices if 
                           tracks[k].time_since_update == 1 + level]
 # 如果当前level没有track,继续
        if len(track_indices_l) == 0: 
            continue
  
 # 匈牙利匹配
        matches_l, _, unmatched_detections = min_cost_matching(distance_metric, max_distance, tracks, detections, 
                                                               track_indices_l, unmatched_detections)
        
 matches += matches_l
 unmatched_tracks = list(set(track_indices) - set(k for k, _ in matches))
    return matches, unmatched_tracks, unmatched_detections

5. 卡尔曼滤波更新

匹配后,DeepSORT使用检测到的detections来更新每个已知的跟踪对象的状态,例如位置和速度。这有助于保持跟踪对象的准确性和连续性。

def update(self, detections):
    """Perform measurement update and track management.
    Parameters
    ----------
    detections: List[deep_sort.detection.Detection]
                A list of detections at the current time step.
    """
    # 得到匹配对、未匹配的tracks、未匹配的dectections
    matches, unmatched_tracks, unmatched_detections = self._match(detections)

    # 对于每个匹配成功的track,用其对应的detection进行更新
    for track_idx, detection_idx in matches:
        self.tracks[track_idx].update(self.kf, detections[detection_idx])
    
	# 对于未匹配的成功的track,将其标记为丢失
	for track_idx in unmatched_tracks:
        self.tracks[track_idx].mark_missed()
	
    # 对于未匹配成功的detection,初始化为新的track
    for detection_idx in unmatched_detections:
        self._initiate_track(detections[detection_idx])
    
	...

6.检测结果

目标追踪

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

openpnp - 74路西门子飞达控制板(主控板STM32_NUCLEO-144) - 验证

文章目录 openpnp - 74路西门子飞达控制板(主控板STM32_NUCLEO-144) - 验证概述笔记重复数字IO的问题想法手工实现程序实现确定要摘掉的数字重合线自动化测试的问题测试程序的场景测试程序的运行效果测试程序实现备注END openpnp - 74路西门子飞达控制板(主控板STM32_NUCLEO-14…

【Linux】编译Linux内核

之所以编译内核,是因为gem5全系统仿真需要vmlinux文件,在此记录一下以备后面需要。 此过程编译之后会获得vmlinux和bzImage两个文件; 主要参考知行大佬的编译内核与gem5官方教程 文章目录 一、Linux源码下载二、安装编译依赖三、编译1. 内核编…

【uniapp】文件授权验真系统(含代码)

文章目录 前言一、框架选用二、数据库设计三、设计上传列表四、上传操作1.前端2.后端 五、修改操作六、访问操作七、二维码生成八、二维码访问九、删除操作总结 前言 吐槽:终于开通了【资源绑定】的功能了,之前还要一个一个的去贴链接 之前的同学联系…

Java12新增特性

前言 前面的文章,我们对Java9、Java10、Java11的特性进行了介绍,对应的文章如下 Java9新增特性 Java10新增特性 Java11新增特性 今天我们来介绍一下Java12版本的新增特性 版本介绍 Java 12是Java SE的第12个版本,于2019年3月19日发布。这个…

口袋参谋:新品上架如何实现月销1w?

​如今在淘宝天猫上,开新店上新品,想要出单是很不容易的。很多商家在新品上架之后,都是非常焦虑的,总是在担心一直没销量该咋办? 以下这几个方法,大家不妨尝试一下; ①打造店铺和产品人群的一致…

MYSQL5.7和MYSQL8配置主从

1、创建专门主从的账号 #登录 mysql -u root -p #创建用户 我这里用户名为test5,注意这里的ip是从库服务器的ip CREATE USER test5192.168.1.20 IDENTIFIED WITH mysql_native_password BY xxxxx; #给主从复制账号授权 grant replication slave on *.* to test5192…

基于Qt Linux开发板USER-KEY按键实现

介绍如何在 Qt 应用上使用嵌入式 GET6818 Linux 开发板 上的按键。 工具:Qt Creator 5.14.2 平台:windows ## 资源简介 在GET6818 开发板,开发板板载资源上有两个用户按键。如下图原理图(下图开发板的按键原理图)。 ## 应用实例 想要监测这个 KEY0,首先出厂内核已经…

Spring的缓存机制-循环依赖

群公告 Java每日大厂面试题: 1、Spring 是如何解决循环依赖? 答案:三级缓存,简单来说,A创建过程中需要B,于是A将自己放到三级缓存里面,去实例化B,B实例化的时候发现需要…

01 计算机图形学概述

什么是图形学 合成和操作视觉信息。 图形学的应用 游戏 电影 动画 模拟 设计 可视化 虚拟现实VR&增强现实AR 电子绘画 图形化UI 字体 图形学的挑战 思维上的挑战 创建与虚拟世界互动需要了解物理世界的各个方面新的计算方法,显示,技术 技术上…

SpringBoot不同环境加载不同配置文件(dev,sit,uat)

目录 一、springboot的profile配置profile多配置文件 二、maven的profiles策略 我们在使用spring的时候,一般都会有不同的环境需要部署:开发环境、测试环境和验收环境,而不同的环境则会有不同的配置,比如数据库ip。解决这个问题&a…

视频批量剪辑:视频合并技巧全攻略,成为视频剪辑专家

在视频制作的过程中,我们常常会遇到需要将多个视频片段合并的需求。这不仅涉及到视频的排列和组合,还需要考虑过渡效果、音频同步等因素。在视频制作过程中,视频批量剪辑是一个非常关键的环节。它可以大大提高工作效率,减少重复劳…

经典OJ题:奇偶链表

目录 题目: 示例: 解题思路: 方法一:双链表链接法 图例: 代码演示: 解题效果: 方法二:奇偶指针 图例: 代码演示: 题目: 给定单链表…

双H桥直流马达步进电机驱动芯片SS8833E

由工采网代理的率能SS8833E是一款适用于有刷直流或双极步进电机的集成电机驱动芯片;采用eTSSOP16封装;该器件集成了两个PNMOS H桥和电流调节电路;电机输出电流可以由外部脉宽调制器(PWM)或内部PWM电流控制器控制。 工…

【Swagger 】提示 ‘Unable to find specification for group default‘

接口文档用的好好的,突然就开始找不到模块 问题记录 1. 接口文档访问不了 swagger 提示 ‘Unable to find specification for group default’ unable to find specification for group default 找不到组默认值的规范 原因:实体类里面是属性使用public…

补坑:Java的字符串String类(2):一些OJ题目

有关String的方法可以看看我上一篇博客 补坑:Java的字符串String类(1)-CSDN博客 387. 字符串中的第一个唯一字符 - 力扣(LeetCode) 给定一个字符串 s ,找到 它的第一个不重复的字符,并返回它…

计算机提示找不到xinput1_3.dll怎么办?6个xinput1_3.dll丢失完美解决方案分享

xinput1_3.dll是Windows操作系统中的一个重要动态链接库文件,它负责处理游戏控制器和其他输入设备的相关功能。当计算机出现xinput1_3.dll缺失的问题时,可能会导致无法正常使用游戏控制器或其他输入设备。下面是针对这个问题的6个解决方法: 方…

物联网AI MicroPython学习之语法 uhashlib哈希算法

学物联网,来万物简单IoT物联网!! uhashlib 介绍 实现二进制数据散列算法,支持sha256,sha1,MD5。 接口介绍 sha256 - 创建一个SHA256哈希对象 参数原型:hash_obj uhashlib.sha256([bytes]) …

时序预测 | MATLAB实现WOA-CNN-GRU-Attention时间序列预测(SE注意力机制)

时序预测 | MATLAB实现WOA-CNN-GRU-Attention时间序列预测(SE注意力机制) 目录 时序预测 | MATLAB实现WOA-CNN-GRU-Attention时间序列预测(SE注意力机制)预测效果基本描述模型描述程序设计参考资料 预测效果 基本描述 1.MATLAB实现…

threejs(11)-shader着色器打造漫天飞舞孔明灯

src/main/main.js import * as THREE from "three";import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; import gsap from "gsap"; // 动画库 import vertexShader from "../shaders/flylight/vertex.glsl"…

类和对象(2):构造函数,析构函数

一、构造函数 1.1 概念 构造函数是一种特殊的成员函数,名字与类名相同,创建类类型对象时编译器自动调用——初始化对象,在对象整个生命周期内只调用一次。 PS: 1. 构造函数无返回值;2. 构造函数支持重载。 class Date { public:…