实时车辆行人多目标检测与跟踪系统(含UI界面,Python代码)

2023-11-08

算法架构:

目标检测:yolov5
目标跟踪:OCSort

其中, Yolov5 带有详细的训练步骤,可以根据训练文档,训练自己的数据集,及其方便。
另外后续 目标检测会添加 yolov7 、yolox,目标跟踪会添加 ByteTrack、deepsort等经典算法,代码主要部分添加了详细注释,方便自己学习。

一、简介

本文将详细介绍如何使用深度学习中的YOLOv5和OCTrack算法实现车辆、行人等多目标的实时检测和跟踪,并利用PyQt5设计了简约的系统UI界面。在界面中,您可以选择自己的视频文件进行检测和跟踪,也可以通过电脑自带的摄像头进行实时处理。此外,您还可以更换自己训练的yolov5模型,进行自己数据的跟踪。

该系统界面优美,检测精度高,功能强大。它具备多目标实时检测、跟踪和计数功能,同时可以自由选择感兴趣的跟踪目标。

本博文提供了完整的Python程序代码和使用教程,适合新入门的朋友参考。您可以在文末的下载链接中获取完整的代码资源文件。以下是本博文的目录:

二、效果展示

三、环境安装

以链接下均是博主个人的博客,总结的非常详细,按照此步骤安装,一定可以安装成功,相信自己欧。(后续会出详细的安装视频)

见 代码资源中 README.md 文件中 环境安装部分,以下是文档截图:
在这里插入图片描述

四、YOLOV5介绍

从实际效果来看YOLOv5已经相当优秀,是发展的比较完备、使用比较广泛的一个版本;而更重要的是YOLOv5的调用、训练和预测都十分方便。YOLOv5的另一个特点就是它为不同的设备需求和不同的应用场景提供了大小和参数数量不同的网络。

以下是YoloV5改进的部分(不完全):

(1)主干部分:使用了Focus网络结构,具体操作是在一张图片中每隔一个像素拿到一个值,这个时候获得了四个独立的特征层,然后将四个独立的特征层进行堆叠,此时宽高信息就集中到了通道信息,输入通道扩充了四倍。该结构在YoloV5第5版之前有所应用,最新版本中未使用。
(2)数据增强:Mosaic数据增强、Mosaic利用了四张图片进行拼接实现数据中增强,根据论文所说其拥有一个巨大的优点是丰富检测物体的背景!且在BN计算的时候一下子会计算四张图片的数据!
(3)多正样本匹配:在之前的Yolo系列里面,在训练时每一个真实框对应一个正样本,即在训练时,每一个真实框仅由一个先验框负责预测。YoloV5中为了加快模型的训练效率,增加了正样本的数量,在训练时,每一个真实框可以由多个先验框负责预测。

一、整体结构解析

在这里插入图片描述

和之前版本的Yolo类似,整个YoloV5可以依然可以分为三个部分,分别是Backbone,FPN以及Yolo Head

Backbone可以被称作YoloV5的主干特征提取网络,根据它的结构以及之前Yolo主干的叫法,我一般叫它CSPDarknet,输入的图片首先会在CSPDarknet里面进行特征提取,提取到的特征可以被称作特征层,是输入图片的特征集合。在主干部分,我们获取了三个特征层进行下一步网络的构建,这三个特征层我称它为有效特征层

FPN可以被称作YoloV5的加强特征提取网络,在主干部分获得的三个有效特征层会在这一部分进行特征融合,特征融合的目的是结合不同尺度的特征信息。在FPN部分,已经获得的有效特征层被用于继续提取特征。在YoloV5里依然使用到了Panet的结构,我们不仅会对特征进行上采样实现特征融合,还会对特征再次进行下采样实现特征融合。

Yolo Head是YoloV5的分类器与回归器,通过CSPDarknet和FPN,我们已经可以获得三个加强过的有效特征层。每一个特征层都有宽、高和通道数,此时我们可以将特征图看作一个又一个特征点的集合,每一个特征点都有通道数个特征。Yolo Head实际上所做的工作就是对特征点进行判断,判断特征点是否有物体与其对应。与以前版本的Yolo一样,YoloV5所用的解耦头是一起的,也就是分类和回归在一个1X1卷积里实现。

因此,整个YoloV5网络所作的工作就是 特征提取-特征加强-预测特征点对应的物体情况

yolov5模型的训练步骤

我们以 VOC 数据格式进行训练,如果自己的数据集是其他格式,可以通过https://blog.csdn.net/qq_28949847/article/details/130246098这篇博客进行格式转换。

1. 准备数据集(以VOC.yaml数据集为例)
2. 使用datasets文件夹下的voc2v5.py 将xml文件转为txt文件
只需修改下方红框位置处的参数, 具体含义见注释。
在这里插入图片描述

3. 参照datasets文件夹下创建的示例,创建文件夹结构,并将数据集放入在对应的文件夹下,截图如下:

在这里插入图片描述
4. 修改 data文件夹下的VOC.yaml

 # 数据集路径
 path: D:/lg/BaiduSyncdisk/project/person_code/project_self/Yolov5_OCtrack/datasets/airplane
 train: # train数据集
   - train
 val: # val 数据集
   - train
 test: # test 数据集
   - train

 # 修改为自己的类
 names:
   0: airplane

在这里插入图片描述

5. 根据自己的需求,修改 train.py文件夹下的参数,主要是以下画红框的这几个

在这里插入图片描述

6. 修改完参数后,点击运行即可训练
在这里插入图片描述

7. 训练结果(模型、PR曲线、数据分布情况、训练loss变化过程等)保存在 runs 文件夹下

在这里插入图片描述
在这里插入图片描述

五、OCtrack介绍

我们这里不做详细的原理介绍了,大部分的博客都已对其原理进行了详细介绍。我们主要对代码进行了详细的注释,有助于帮助我们更好的理解代码。其核心主要是两个类 OCSortKalmanBoxTracker, 下面代码对其进行了详细的注释:


class OCSort(object):
    def __init__(self, det_thresh, max_age=50, min_hits=-1,
                 iou_threshold=0.3, delta_t=3, asso_func="diou", inertia=0.2, use_byte=False):
        """
        初始化OCSort对象,并设置关键参数。

        参数:
        - det_thresh: float,目标检测结果的阈值
        - max_age: int,允许的跟踪器未更新的最大帧数,默认为30
        - min_hits: int,跟踪器更新所需的最小帧数,默认为3
        - iou_threshold: float,用于关联跟踪器和检测结果的IOU(交并比)阈值,默认为0.3
        - delta_t: int,时间步长,默认为3
        - asso_func: str,关联函数的名称,默认为"diou"
        - inertia: float,跟踪器的惯性权重,默认为0.2
        - use_byte: bool,是否使用字节级别的特征,默认为False
        """
        self.max_age = max_age
        self.min_hits = min_hits
        self.iou_threshold = iou_threshold
        # 存储跟踪器的列表
        self.trackers = []
        self.frame_count = 0
        self.det_thresh = det_thresh
        # 时间步长
        self.delta_t = delta_t
        self.asso_func = ASSO_FUNCS[asso_func]
        # 跟踪器的惯性权重
        self.inertia = inertia
        self.use_byte = use_byte
        # 跟踪器对象的计数器
        KalmanBoxTracker.count = 0
        self.label = {}
        # 存储label 对应关系
        self.idx_to_label = {}

    def update(self, results, img_size):
        """
            更新跟踪器状态。

            参数:
            - results: numpy数组,表示检测结果,格式为[[x1,y1,x2,y2,score],[x1,y1,x2,y2,score],...]
            - img_size: 元组,表示图像的尺寸 (height, width)

            要求:即使没有检测结果,每帧都必须调用此方法(对于没有检测结果的帧,请使用 np.empty((0, 5)))。
            返回一个类似的数组,其中最后一列是对象的ID。
            注意:返回的对象数量可能与提供的检测数量不同。
        """

        # img 大小
        img_h, img_w = img_size[0], img_size[1]
        # 当前帧数
        self.frame_count += 1
        # 将 目标检测结果[[label, conf, [x1, y1, x2, y2],...] 转为 [[x1,y1,x2,y2,score],[x1,y1,x2,y2,score],...]格式
        output_results = []
        for r_i, res in enumerate(results):
            label, conf, bbox = res[:3]
            if label not in self.label:
                self.label[label] = 0 if len(self.label) == 0 else (max(self.label.values()) + 1)
                self.idx_to_label = {v: k for k, v in self.label.items()}
            cls = self.label[label]
            output_results.append([bbox[0], bbox[1], bbox[2], bbox[3], conf, cls])

        output_results = np.array(output_results) if len(output_results) else np.empty((0, 6))
        # x1y1x2y2
        bboxes = output_results[:, :4]
        scores = output_results[:, 4]
        classes = output_results[:, 5:6]
        dets = np.concatenate((bboxes, np.expand_dims(scores, axis=-1), classes), axis=1)
        # 选出self.det_thresh > score > 0.1阈值的数据,为低分数据, 设置 BYTE association 为 True 时会用到
        inds_low = scores > 0.1
        inds_high = scores < self.det_thresh
        inds_second = np.logical_and(inds_low, inds_high)
        dets_second = dets[inds_second]

        # 选出 score > self.det_thresh 的数据
        remain_inds = scores > self.det_thresh
        dets = dets[remain_inds]

        # 存储卡尔曼预测后的位置信息
        trks = np.zeros((len(self.trackers), 5))
        to_del = []
        ret = []

        # 对已经存在的self.trackers中的跟踪器进行卡尔曼位置预测
        for t, trk in enumerate(trks):
            # 根据trackers中的信息,进行卡尔曼位置预测
            pos = self.trackers[t].predict()[0]
            # 更新跟踪器的位置信息
            trk[:] = [pos[0], pos[1], pos[2], pos[3], 0]
            # 如果预测的位置出现NaN值(无效值)
            if np.any(np.isnan(pos)):
                # 将该跟踪器的索引添加到待删除列表中
                to_del.append(t)
        # 移除包含NaN等无效值的行
        trks = np.ma.compress_rows(np.ma.masked_invalid(trks))
        # 从跟踪器列表中删除无效的跟踪器, 逆序删除元素, 防止索引发送变化
        for t in reversed(to_del):
            self.trackers.pop(t)

        # 获取跟踪器的速度
        velocities = np.array([trk.velocity if trk.velocity is not None else np.array((0, 0)) for trk in self.trackers])
        # 获取最后观察到的边界框
        last_boxes = np.array([trk.last_observation for trk in self.trackers])
        # 获取K个先前观察结果 ???
        k_observations = np.array([k_previous_obs(trk.observations, trk.age, self.delta_t) for trk in self.trackers])

        """
            第一次:
            将目标检测得到的box同卡尔曼预测后的box进行级联匹配
        """
        matched, unmatched_dets, unmatched_trks = associate(dets, trks, self.iou_threshold, velocities, k_observations,
                                                            self.inertia)
        for m in matched:
            # 根据最新匹配的box进行卡尔曼更新
            self.trackers[m[1]].update(dets[m[0], :])

        """
            # BYTE association
            Second round of associaton by OCR
            对未匹配的追踪器 同 低分的box进行2次匹配
        """
        if self.use_byte and len(dets_second) > 0 and unmatched_trks.shape[0] > 0:
            # 提取未匹配的追踪器
            u_trks = trks[unmatched_trks]
            # 计算低分检测结果和未匹配追踪器之间的IOU
            iou_left = self.asso_func(dets_second, u_trks)  # iou between low score detections and unmatched tracks
            iou_left = np.array(iou_left)

            # 检查最大的IOU是否超过阈值
            if iou_left.max() > self.iou_threshold:
                """
                    注意:通过使用较低的阈值,例如 self.iou_threshold - 0.1,在MOT17/MOT20数据集上可能会获得更高的性能。
                    但出于简单起见,我们在这里保持阈值的一致性。
                """
                # 使用线性分配算法进行匹配
                matched_indices = linear_assignment(-iou_left)
                # 存储待删除的追踪器索引
                to_remove_trk_indices = []
                # 遍历匹配的索引对
                for m in matched_indices:
                    det_ind, trk_ind = m[0], unmatched_trks[m[1]]
                    # 如果IOU低于阈值,则跳过继续下一次迭代
                    if iou_left[m[0], m[1]] < self.iou_threshold:
                        continue
                    # 更新对应的追踪器状态
                    self.trackers[trk_ind].update(dets_second[det_ind, :])
                    # 将待删除的追踪器索引添加到列表中
                    to_remove_trk_indices.append(trk_ind)
                # 从未匹配的追踪器中移除已匹配的部分
                unmatched_trks = np.setdiff1d(unmatched_trks, np.array(to_remove_trk_indices))

        # 对未匹配的检测结果和追踪器 进行第2次重新匹配
        if unmatched_dets.shape[0] > 0 and unmatched_trks.shape[0] > 0:
            # 提取未匹配的检测结果和追踪器
            left_dets = dets[unmatched_dets]
            left_trks = last_boxes[unmatched_trks]
            # 计算未匹配的检测结果和追踪器之间的IOU
            iou_left = self.asso_func(left_dets, left_trks)
            iou_left = np.array(iou_left)
            # 检查最大的IOU是否超过阈值
            if iou_left.max() > self.iou_threshold:
                """
                    注意:通过使用较低的阈值,例如 self.iou_threshold - 0.1,在MOT17/MOT20数据集上可能会获得更高的准确度。
                    但出于简单起见,我们在这里保持阈值的一致性。
                """
                # 使用线性分配算法进行重新匹配
                rematched_indices = linear_assignment(-iou_left)
                # 存储待删除的检测结果和追踪器的索引
                to_remove_det_indices = []
                to_remove_trk_indices = []
                for m in rematched_indices:
                    det_ind, trk_ind = unmatched_dets[m[0]], unmatched_trks[m[1]]
                    # 如果IOU低于阈值,则跳过继续下一次迭代
                    if iou_left[m[0], m[1]] < self.iou_threshold:
                        continue
                    # 更新对应的追踪器状态,索引是一直对应的,所以此处可以直接更新
                    self.trackers[trk_ind].update(dets[det_ind, :])
                    # 将待删除的检测结果和追踪器索引添加到列表中
                    to_remove_det_indices.append(det_ind)
                    to_remove_trk_indices.append(trk_ind)
                # 从未匹配的检测结果和追踪器中移除已匹配的部分
                unmatched_dets = np.setdiff1d(unmatched_dets, np.array(to_remove_det_indices))
                unmatched_trks = np.setdiff1d(unmatched_trks, np.array(to_remove_trk_indices))

        # 没有匹配上的tracker,也就是在没有新的测量值时,传入None,冻结滤波器状态并保持先前的预测结果,但是里面的后验状态 self.x_post、后验协方差 self.P_post、残差 self.y 进行了更新
        for m in unmatched_trks:
            self.trackers[m].update(None)

        # 对未匹配上的目标检测框,创建一个新的 KalmanBoxTracker 跟踪器对象
        for i in unmatched_dets:
            trk = KalmanBoxTracker(dets[i, :], delta_t=self.delta_t)
            self.trackers.append(trk)
        i = len(self.trackers)

        for trk in reversed(self.trackers):
            # 如果跟踪器的最近观测的总和小于0(即没有有效的观测)
            if trk.last_observation.sum() < 0:
                d = trk.get_state()[0]
            else:
                '''
                使用最近的观测box还是卡尔曼滤波器的预测box是可选的,这里没有注意到显著的差异。
                '''
                # 跟踪器有最近的观测(last_observation),则将变量 d 设置为该观测的前四个元素(即边界框的box)
                d = trk.last_observation[:4]
            if (trk.time_since_update <= 3) and (trk.hit_streak >= self.min_hits or self.frame_count <= self.min_hits):
                # +1 as MOT benchmark requires positive
                ret.append(np.concatenate((d, [trk.id, trk.cls, trk.conf])).reshape(1, -1))
            i -= 1
            # 当超过 max_age 没有更新时,删除此跟踪信息
            if trk.time_since_update > self.max_age:
                self.trackers.pop(i)

        outputs = []
        if len(ret) > 0:
            ret = np.concatenate(ret)
            for idx, t in enumerate(ret):
                x1, y1, x2, y2 = int(t[0]), int(t[1]), int(t[2]), int(t[3])
                track_id = int(t[4])
                cls = int(t[5])
                det_conf = t[6]
                class_name = self.idx_to_label[cls]

                x1 = min(img_w - 1, max(0, x1))
                x2 = min(img_w - 1, max(0, x2))
                y1 = min(img_h - 1, max(0, y1))
                y2 = min(img_h - 1, max(0, y2))
                res = [x1, y1, x2, y2, class_name, det_conf, track_id]
                outputs.append(res)

        return outputs
class KalmanBoxTracker(object):
    """
        这个类表示以bbox形式观察到的单个被跟踪对象的内部状态。
    """
    count = 0

    def __init__(self, bbox, delta_t=3, orig=False):
        """
            使用目标检测框box初始化跟踪器。

            参数:
            - bbox:表示要跟踪的对象的初始边界框(目标检测框)。
            - delta_t:时间间隔,用于估计速度,计算速度是用 当前的box - 倒数第delta_t的box。
            - orig:一个布尔值,如果orig为False,则使用自定义的KalmanFilterNew作为卡尔曼滤波器模型,
                    否则使用filterpy库中的KalmanFilter。

        """
        # 定义Kalman滤波器模型
        if not orig:
            from .kalmanfilter import KalmanFilterNew as KalmanFilter
            self.kf = KalmanFilter(dim_x=7, dim_z=4)
        else:
            from filterpy.kalman import KalmanFilter
            self.kf = KalmanFilter(dim_x=7, dim_z=4)
        # 设置状态转移矩阵 7 * 7 矩阵,通过状态转移矩阵和当前状态的乘积,可以预测对象在下一个时间步的状态。
        # 7个位置分别代表:cx(中心位置)、cy(中心位置)、宽度、高度、速度(水平)、速度(垂直)、加速度
        # 当状态转移矩阵中的元素被设置为1时,表示在系统的状态转移过程中,对应状态之间的关系是线性的,并且该状态在时间推进时保持不变。
        self.kf.F = np.array([[1, 0, 0, 0, 1, 0, 0],
                              [0, 1, 0, 0, 0, 1, 0],
                              [0, 0, 1, 0, 0, 0, 1],
                              [0, 0, 0, 1, 0, 0, 0],
                              [0, 0, 0, 0, 1, 0, 0],
                              [0, 0, 0, 0, 0, 1, 0],
                              [0, 0, 0, 0, 0, 0, 1]])
        # 设置观测矩阵
        self.kf.H = np.array([[1, 0, 0, 0, 0, 0, 0],
                              [0, 1, 0, 0, 0, 0, 0],
                              [0, 0, 1, 0, 0, 0, 0],
                              [0, 0, 0, 1, 0, 0, 0]])

        self.kf.R[2:, 2:] *= 10.
        # 对不可观测的初始速度给予较高的不确定性
        self.kf.P[4:, 4:] *= 1000.
        self.kf.P *= 10.
        self.kf.Q[-1, -1] *= 0.01
        self.kf.Q[4:, 4:] *= 0.01

        self.kf.x[:4] = convert_bbox_to_z(bbox)
        self.conf = bbox[4]
        self.time_since_update = 0
        self.id = KalmanBoxTracker.count
        KalmanBoxTracker.count += 1
        self.history = []
        self.hits = 0
        self.hit_streak = 0
        self.age = 0
        """
          注意:[-1,-1,-1,-1,-1]是一个妥协的占位符,表示非观测状态,
          对于函数k_previous_obs的返回值也是如此。虽然不够美观,但为了以快速和统一的方式支持生成观测数组,
          如下所示:k_observations = np.array([k_previous_obs(...)]])。
        """
        self.last_observation = np.array([-1, -1, -1, -1, -1])  # placeholder
        self.observations = dict()
        self.history_observations = []
        self.velocity = None
        self.delta_t = delta_t

        self.cls = int(bbox[5])


    def update(self, bbox):
        """
        Args:
        bbox (array or None): 观测到的边界框,可以是数组或 None。

        Returns:
            None

        Notes:
            - self.velocity的计算:
            - 对于每个时间步 dt,从当前时间步 self.age 开始向前查找,找到与当前观测 bbox 相隔 delta_t 步的观测数据。
            - 如果找不到与当前观测相隔 delta_t 步的观测数据,使用最近的观测数据作为之前的边界框。
        """
        if bbox is not None:
            if self.last_observation.sum() >= 0:  # no previous observation
                previous_box = None
                for i in range(self.delta_t):
                    dt = self.delta_t - i
                    if self.age - dt in self.observations:
                        previous_box = self.observations[self.age - dt]
                        break
                if previous_box is None:
                    previous_box = self.last_observation

                # 估计跟踪速度方向,使用与当前观测的bbox相隔 delta_t  步的观测数据
                self.velocity = speed_direction(previous_box, bbox)

            # 插入新的观测数据
            self.last_observation = bbox[:5]
            self.conf = bbox[4]

            self.observations[self.age] = bbox[:5]
            # 重置自上次更新以来的时间步数和历史记录
            self.time_since_update = 0
            self.history = []
            # 增加命中计数和命中连续次数
            self.hits += 1
            self.hit_streak += 1
            # 根据最新匹配的 bbox,进行卡尔曼更新
            self.kf.update(convert_bbox_to_z(bbox))

        else:
            self.kf.update(bbox)

    def predict(self):
        """
        对跟踪器的速度和宽度之和进行判断,如果其小于等于零,则将跟踪器的水平加速度置零。

        具体解释如下:
            self.kf.x[6] 表示状态向量中的第 7 个元素,即水平加速度。
            self.kf.x[2] 表示状态向量中的第 3 个元素,即宽度。
            self.kf.x[6] + self.kf.x[2] 表示跟踪器的水平加速度和宽度之和。
            if self.kf.x[6] + self.kf.x[2] <= 0: 判断跟踪器的水平加速度和宽度之和是否小于等于零。

            如果条件成立,即跟踪器的速度和宽度之和小于等于零,那么 self.kf.x[6] *= 0.0 将跟踪器的水平加速度置零,相当于将其速度减小为零或停止水平运动。
        """
        # 判断速度和宽度之和是否小于等于零
        if (self.kf.x[6] + self.kf.x[2]) <= 0:
            # 若小于等于零,将水平加速度置零
            self.kf.x[6] *= 0.0

        # 利用卡尔曼滤波器进行状态预测
        self.kf.predict()
        # 增加跟踪器的age
        self.age += 1
        # 如果自上次更新以来经过的时间步数大于零
        if self.time_since_update > 0:
            # 将命中计数置零
            self.hit_streak = 0
        # 增加自上次更新以来的时间步数
        self.time_since_update += 1
        # 将当前状态向量 self.kf.x 转换为边界框信息,并添加到历史记录中
        self.history.append(convert_x_to_bbox(self.kf.x))
        # 返回历史记录中的最后一个边界框作为预测的边界框估计
        return self.history[-1]

    def get_state(self):
        """
        Returns the current bounding box estimate.
        """
        return convert_x_to_bbox(self.kf.x)

目标跟踪效果:
在这里插入图片描述
至此视频中多目标检测跟踪的代码实现部分介绍完毕,后面的博文中将给出训练程序以及UI界面的详细介绍,至于程序如何使用、依赖包安装、pycharm软件的安装过程将通过博主的B站视频进行演示介绍,敬请关注!

六、下载链接

若您想获得博文中涉及的实现完整全部程序文件(包括模型权重,py, UI文件等,如下图),这里已打包上传至博主的面包多平台,已将所有涉及的文件同时打包到里面,点击即可运行,完整文件截图如下:
在这里插入图片描述
面包多:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

实时车辆行人多目标检测与跟踪系统(含UI界面,Python代码) 的相关文章

  • 如何恢复tensorflow inceptions检查点文件(ckpt)?

    I have inception resnet v2 2016 08 30 ckpt文件是预先训练的初始模型 我想使用恢复这个模型 saver restore sess ckpt filename 但为此 我将需要编写训练该模型时使用的变量
  • 类的 IPython 表示

    我正在使用我创建的模块尝试 IPython 但它没有显示类对象的实际表示 相反 它显示类似的内容 TheClass module TheClass name I heavily在这个模块中使用元类 我有真正有意义的类表示 应该向用户显示 是
  • Python - 比较同一字典中的值

    我有一本字典 d Trump MAGA FollowTheMoney Clinton dems Clinton Stein FollowTheMoney Atlanta 我想删除字符串列表中的重复字符串 该字符串是键的值 对于这个例子 期望
  • 为什么 dataclasses.astuple 返回类属性的深层副本?

    在下面的代码中astuple函数正在执行数据类的类属性的深层复制 为什么它不能产生与函数相同的结果my tuple import copy import dataclasses dataclasses dataclass class Dem
  • 在 Python 中将列表元素作为单独的项目返回

    Stackoverflow 的朋友们大家好 我有一个计算列表的函数 我想单独返回列表的每个元素 如下所示 接收此返回的函数旨在处理未定义数量的参数 def foo my list 1 2 3 4 return 1 2 3 4 列表中的元素数
  • 从Django中具有外键关系的两个表中检索数据? [复制]

    这个问题在这里已经有答案了 This is my models py file from django db import models class Author models Model first name models CharFie
  • Python 3d 绘图设置固定色阶

    我正在尝试绘制两个 3d 数组 第一个数组的 z 值在范围内 0 15 0 15 第二个来自 0 001 0 001 当我绘图时 色标自动遵循数据范围 如何设置自定义比例 我不想看到 0 001 的浅色 而应该看到 0 15 的浅色 如何修
  • 为什么 web2py 在启动时崩溃?

    我正在尝试让 web2py 在 Ubuntu 机器上运行 所有文档似乎都表明要在 nix 系统上运行它 您需要下载源代码并执行以下操作 蟒蛇 web2py py 我抓住了source http www web2py com examples
  • 更好地相当于这个疯狂的嵌套 python for 循环

    for a in map for b in map a for c in map b for d in map c for e in map d print a b c d e 上面的代码用于创建图中一定长度的所有路径 map a 表示从
  • Tensorboard SyntaxError:语法无效

    当我尝试制作张量板时 出现语法错误 尽管开源代码我还是无法理解 我尝试搜索张量板的代码 但不清楚 即使我不擅长Python 我这样写路径C Users jh902 Documents logs因为我正在使用 Windows 10 但我不确定
  • 矩形函数的数值傅里叶变换

    本文的目的是通过一个众所周知的分析傅里叶变换示例来正确理解 Python 或 Matlab 上的数值傅里叶变换 为此 我选择矩形函数 这里报告了它的解析表达式及其傅立叶变换https en wikipedia org wiki Rectan
  • Python 内置的 super() 是否违反了 DRY?

    显然这是有原因的 但我没有足够的经验来认识到这一点 这是Python中给出的例子docs http docs python org 2 library functions html super class C B def method se
  • 如何使用 Selenium 和 ChromeDriver 解决 TypeError: 'module' object is not callable 错误 [重复]

    这个问题在这里已经有答案了 代码试验 from selenium import webdriver from selenium webdriver chrome options import Options as Chromeoptions
  • 无法导入 langchain.agents.load_tools

    我正在尝试使用 LangChain Agents 但无法导入 load tools 版本 langchain 0 0 27 我尝试过这些 from langchain agents import initialize agent from
  • Python GTK+ 画布

    我目前正在通过 PyGobject 学习 GTK 需要画布之类的东西 我已经搜索了文档 发现两个小部件似乎可以完成这项工作 GtkDrawingArea 和 GtkLayout 我需要一些基本函数 如 fillrect 或 drawline
  • 在 Google App Engine 中,如何避免创建具有相同属性的重复实体?

    我正在尝试添加一个事务 以避免创建具有相同属性的两个实体 在我的应用程序中 每次看到新的 Google 用户登录时 我都会创建一个新的播放器 当新的 Google 用户在几毫秒内进行多个 json 调用时 我当前的实现偶尔会创建重复的播放器
  • 重新分配唯一值 - pandas DataFrame

    我在尝试着assign unique值在pandas df给特定的个人 For the df below Area and Place 会一起弥补unique不同的价值观jobs 这些值将分配给个人 总体目标是使用尽可能少的个人 诀窍在于这
  • 如何将 Django 中的权限添加到模型并使用 shell 进行测试

    我在模型中添加了 Meta 类并同步了数据库 然后在 shell 中创建了一个对象 它返回 false 所以我真的无法理解错误在哪里或者缺少什么是否在其他文件中可能存在某种配置 class Employer User Employer in
  • 将索引与值交换的最快方法

    考虑pd Series s s pd Series list abcdefghij list ABCDEFGHIJ s A a B b C c D d E e F f G g H h I i J j dtype object 交换索引和值并
  • NLTK:查找单词大小为 2k 的上下文

    我有一个语料库 我有一个词 对于语料库中该单词的每次出现 我想获取一个包含该单词之前的 k 个单词和该单词之后的 k 个单词的列表 我在算法上做得很好 见下文 但我想知道 NLTK 是否提供了一些我错过的功能来满足我的需求 def size

随机推荐

  • 微软云搭建服务器,快速入门:创建服务器 - Azure 门户 - Azure Database for PostgreSQL - 单个服务器

    您现在访问的是微软AZURE全球版技术文档网站 若需要访问由世纪互联运营的MICROSOFT AZURE中国区技术文档网站 请访问 https docs azure cn 快速入门 使用 Azure 门户创建 Azure Database
  • Transaction rolled back because it has been marked as rollback-only事务问题

    1 复现 public Class ClassOne private ClassTwo classTwo Transactional public void one try classTwo two catch Exception e lo
  • Eclipse中新建动态Web工程

    前提 Tomcat已安装好 此处以6 0为例 高版本也一样 在Eclipse中新建动态网站工程Eclipse gt new gt Dynamic Web projectProject name a04Target runtime Tomca
  • 爬虫是个啥

    走进爬虫 爬虫是什么 初识网络爬虫 隐藏在身边的网页蜘蛛 爬虫是黑客吗 为什么要学爬虫 数据来源 爬虫的应用领域 爬虫是什么 初识网络爬虫 网页蜘蛛 网络机器人 按照一定规则 自动抓取万维信息的程序或脚本 也就是说 爬虫可以自动浏览网页信息
  • hql语句

    简介 hql为hive sql的缩写 hive本身为java语言开发而成 所以hive上面如果有什么特殊需求 完全可以是用hive udf订制自己的需求 后续会介绍udf的开发方法 语法 以下只列举一些对作者有用的语法 LIKE操作 语法
  • 小白刚入门Python,学完基础后,接下来的学习步骤!

    自学Python要学多久可以学会 如果是自学 从零基础开端学习python的话 按照每个人理解能力的不同 大致上需求半年到一年半左右的时刻 当然 如果有其它编程言语的经历 入门还是比较快的 大概需求2 3个月可以用Python言语编写一些简
  • 关于 maven 中 SNAPSHOT 的 jar包的更新机制

    前言 我们知道maven包的版本有两类 一类是 SNAPSHOT 一类是 RELEASE 这两类有个重要的区别 RELEASE 的包需要改 pom xml 中的
  • Android Studio使用Lint进行代码检查

    Android Studio目前已经更新到1 4版本 它作为Google官方推荐的IDE 功能非常强大 其中提供了一套静态代码分析工具 它可以帮助我们检查项目中存在的问题 让我们更有规范性的开发App 它可以检查出 xml文件中是否存在ha
  • 2022年java中级开发工程师最新面试题

    1 JDK 和 JRE 有什么区别 JDK Java Development Kit 的简称 java 开发工具包 提供了 java 的开发环境和运行环境 JRE Java Runtime Environment 的简称 java 运行环境
  • 2023华为od机试统一考试B卷 Java【最小循环子数组】

    前言 本题使用Java解答 如果需要Python版本的代码 请参考以下链接 点我 题目描述 给定一个由若干整数组成的数组nums 请检查数组是否是由某个子数组重复循环拼接而成 请输出这个最小的子数组 输入描述 第一行输入数组中元素个数n 1
  • matlab中使用colormap没有效果

    在做数字图像处理实验的时候 需要将灰度图像做fft变换 显示其频谱图 代码如下 clc clear close all figure 1 grayimg imread grayimg jpg imshow grayimg figure 2
  • A Review on Deep Learning Techniques Applied to Semantic Segmentation

    Introduction Terminology and Background Concepts 1 Common Deep Network Architectures AlexNet VGG 16 GoogLeNet ResNet ReN
  • Pytest接口自动化测试实战演练

    结合单元测试框架pytest 数据驱动模型 allure 目录 api 存储测试接口 conftest py 设置前置操作 目前前置操作 1 获取token并传入headers 2 获取命令行参数给到环境变量 指定运行环境 commmon
  • 线下实践阿里云:「 云原生技术实践营 - 容器微服务专场 」

    一 前言 自己在杭州工作和生活也有将近10年 由于有些前同事和朋友在阿里上班 也过去玩过几次 在印象中 作为联谊公司 还和阿里组织过一些小规模的活动 比如相亲和篮球比赛 所以 对阿里杭州的滨江园区和西溪园区还都比较熟悉 如今 在南京工作和生
  • HTML标签概述及<html>,<head>,<title>,<link>,<form>,<meta>详细介绍

    HTML部分标签及其介绍 介绍 引用 HTML标签概述 基本标签 常用格式标签 表单标签 列表标签 应用标签 视频标签 创建链接 关系标签 表格标签 样式 节标签 元信息标签 编程标签 HTML组成 Html声明 Html头部 body部分
  • FastAPI从入门到实战(0)——初识FastAPI

    本文主要介绍一下FastAPI是什么 多数内容摘自官网 https fastapi tiangolo com zh FastAPI是什么 FastAPI 是一个用于构建 API 的现代 快速 高性能 的 web 框架 使用 Python 3
  • 写正确的整数二分

    二分 第一篇二分搜索论文是 1946 年发表 然而第一个没有 bug 的二分查找法却是在 1962 年才出现 中间用了 16 年的时间 不知道哪里看的 整数二分 yxc二分模板 二分的本质是二段性不是单调性 当想找不满足性质的边界值 红色区
  • 简单的hardfault追踪以及cm_backtrace错误追踪

    最近和朋友聊关于错误追踪的一些问题 有不少人知道使用 但是原理却不是很理解 正好最近没事我打算简单写一下 写的不好或者有错误的地方多多理解啊 首先是我们以前使用一种简单的错误追踪hardfault 这个原理比较简单 大概说一下 就是在进ha
  • 常见算子使用_LaTeX系列笔记(4)-微分算子要不要写正体?

    上一篇笔记中介绍了数学运算符的使用 其中有一个问题是微分算子 是否应该是正体 孙孟越 LaTeX系列笔记 3 数学运算符 Math Operator zhuanlan zhihu com 这个问题是非常常见的 我们来分析一下 正体 斜体的优
  • 实时车辆行人多目标检测与跟踪系统(含UI界面,Python代码)

    算法架构 目标检测 yolov5 目标跟踪 OCSort 其中 Yolov5 带有详细的训练步骤 可以根据训练文档 训练自己的数据集 及其方便 另外后续 目标检测会添加 yolov7 yolox 目标跟踪会添加 ByteTrack deep