ONNX版本YOLOV5-DeepSort (rknn版本已经Ready)

news2025/2/27 1:37:41

目录

1. 前言

2. 储备知识

3. 准备工作

4. 代码修改的地方

5.结果展示


1. 前言

        之前一直在忙着写文档,之前一直做分类,检测和分割,现在看到跟踪算法,花了几天时间找代码调试,看了看,展示效果比单纯的检测要更加的炸裂一点。

2. 储备知识

        DeepSORT(Deep Learning to Track Multi-Object in SORT)是一种基于深度学习的多目标跟踪算法,它结合了深度学习的目标检测和传统的轨迹跟踪方法,旨在实现在复杂场景中准确和稳定地跟踪多个移动目标。以下是关于DeepSORT的检测思想、特点和应用方面的介绍:

        检测思想: DeepSORT的核心思想是结合深度学习目标检测和轨迹跟踪方法,以实现多目标跟踪。首先,利用深度学习目标检测模型(如YOLO、Faster R-CNN等)检测出每一帧图像中的所有目标物体,并提取其特征。然后,通过应用传统的轨迹跟踪算法(如卡尔曼滤波器和轨迹关联等),将目标在连续帧之间进行关联,从而生成每个目标的运动轨迹。

        特点:

  1. 多目标跟踪: DeepSORT专注于同时跟踪多个目标,适用于需要同时监测和追踪多个物体的场景,如交通监控、人群管理等。
  2. 深度特征: 通过使用深度学习模型提取目标的特征,DeepSORT可以更准确地表示目标,从而提高跟踪的精度和鲁棒性。
  3. 轨迹关联: DeepSORT使用传统的轨迹关联技术来连接不同帧之间的目标,确保在物体出现、消失、重叠等情况下仍能准确跟踪。
  4. 实时性能: DeepSORT设计用于实时应用,可以在视频流中高效地进行目标跟踪,适用于要求实时性能的应用场景。

需要了解的算法内容:详细介绍

  1. 目前主流的目标跟踪算法都是基于Tracking-by-Detecton策略,即基于目标检测的结果来进行目标跟踪。DeepSORT运用的就是这个策略,上面的视频是DeepSORT对人群进行跟踪的结果,每个bbox左上角的数字是用来标识某个人的唯一ID号。
  2. 这里就有个问题,视频中不同时刻的同一个人,位置发生了变化,那么是如何关联上的呢?答案就是匈牙利算法和卡尔曼滤波。

    匈牙利算法可以告诉我们当前帧的某个目标,是否与前一帧的某个目标相同。卡尔曼滤波可以基于目标前一时刻的位置,来预测当前时刻的位置,并且可以比传感器(在目标跟踪中即目标检测器,比如Yolo等)更准确的估计目标的位置。

3. 准备工作

        基础代码:黄老师的github,参考的是这位博主的,我做了相应的修改

4. 代码修改的地方

具体需要修改的有两个py文件

(1) main.py文件,里面的检测器yolo用onnx做推理,onnx模型参考我的博文yolov5转rknn(聪明的你应该会的)

import cv2
import torch
import numpy as np
import onnxruntime as rt


def sigmoid(x):
    return 1 / (1 + np.exp(-x))


def nms_boxes(boxes, scores):
    """Suppress non-maximal boxes.

    # Arguments
        boxes: ndarray, boxes of objects.
        scores: ndarray, scores of objects.

    # Returns
        keep: ndarray, index of effective boxes.
    """
    x = boxes[:, 0]
    y = boxes[:, 1]
    w = boxes[:, 2] - boxes[:, 0]
    h = boxes[:, 3] - boxes[:, 1]

    areas = w * h
    order = scores.argsort()[::-1]

    keep = []
    while order.size > 0:
        i = order[0]
        keep.append(i)

        xx1 = np.maximum(x[i], x[order[1:]])
        yy1 = np.maximum(y[i], y[order[1:]])
        xx2 = np.minimum(x[i] + w[i], x[order[1:]] + w[order[1:]])
        yy2 = np.minimum(y[i] + h[i], y[order[1:]] + h[order[1:]])

        w1 = np.maximum(0.0, xx2 - xx1 + 0.00001)
        h1 = np.maximum(0.0, yy2 - yy1 + 0.00001)
        inter = w1 * h1

        ovr = inter / (areas[i] + areas[order[1:]] - inter)
        inds = np.where(ovr <= 0.45)[0]
        order = order[inds + 1]
    keep = np.array(keep)
    return keep


def process(input, mask, anchors):

    anchors = [anchors[i] for i in mask]
    grid_h, grid_w = map(int, input.shape[0:2])

    box_confidence = sigmoid(input[..., 4])
    box_confidence = np.expand_dims(box_confidence, axis=-1)

    box_class_probs = sigmoid(input[..., 5:])

    box_xy = sigmoid(input[..., :2])*2 - 0.5

    col = np.tile(np.arange(0, grid_w), grid_w).reshape(-1, grid_w)
    row = np.tile(np.arange(0, grid_h).reshape(-1, 1), grid_h)
    col = col.reshape(grid_h, grid_w, 1, 1).repeat(3, axis=-2)
    row = row.reshape(grid_h, grid_w, 1, 1).repeat(3, axis=-2)
    grid = np.concatenate((col, row), axis=-1)
    box_xy += grid
    box_xy *= int(img_size/grid_h)

    box_wh = pow(sigmoid(input[..., 2:4])*2, 2)
    box_wh = box_wh * anchors

    box = np.concatenate((box_xy, box_wh), axis=-1)

    return box, box_confidence, box_class_probs


def filter_boxes(boxes, box_confidences, box_class_probs):
    """Filter boxes with box threshold. It's a bit different with origin yolov5 post process!

    # Arguments
        boxes: ndarray, boxes of objects.
        box_confidences: ndarray, confidences of objects.
        box_class_probs: ndarray, class_probs of objects.

    # Returns
        boxes: ndarray, filtered boxes.
        classes: ndarray, classes for boxes.
        scores: ndarray, scores for boxes.
    """
    box_classes = np.argmax(box_class_probs, axis=-1)
    box_class_scores = np.max(box_class_probs, axis=-1)
    pos = np.where(box_confidences[..., 0] >= 0.5)


    boxes = boxes[pos]
    classes = box_classes[pos]
    scores = box_class_scores[pos]

    return boxes, classes, scores


def yolov5_post_process(input_data):
    masks = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
    anchors = [[10, 13], [16, 30], [33, 23], [30, 61], [62, 45],
              [59, 119], [116, 90], [156, 198], [373, 326]]

    boxes, classes, scores = [], [], []
    for input,mask in zip(input_data, masks):
        b, c, s = process(input, mask, anchors)
        b, c, s = filter_boxes(b, c, s)
        boxes.append(b)
        classes.append(c)
        scores.append(s)

    boxes = np.concatenate(boxes)
    boxes = xywh2xyxy(boxes)
    classes = np.concatenate(classes)
    scores = np.concatenate(scores)

    nboxes, nclasses, nscores = [], [], []
    for c in set(classes):
        inds = np.where(classes == c)
        b = boxes[inds]
        c = classes[inds]
        s = scores[inds]

        keep = nms_boxes(b, s)

        nboxes.append(b[keep])
        nclasses.append(c[keep])
        nscores.append(s[keep])

    if not nclasses and not nscores:
        return None, None, None

    boxes = np.concatenate(nboxes)
    classes = np.concatenate(nclasses)
    scores = np.concatenate(nscores)

    return boxes, classes, scores


def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, stride=32):
    # Resize and pad image while meeting stride-multiple constraints
    shape = img.shape[:2]  # current shape [height, width]
    if isinstance(new_shape, int):
        new_shape = (new_shape, new_shape)

    # Scale ratio (new / old)
    r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
    if not scaleup:  # only scale down, do not scale up (for better test mAP)
        r = min(r, 1.0)

    # Compute padding
    ratio = r, r  # width, height ratios
    new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))
    dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1]  # wh padding
    if auto:  # minimum rectangle
        dw, dh = np.mod(dw, stride), np.mod(dh, stride)  # wh padding
    elif scaleFill:  # stretch
        dw, dh = 0.0, 0.0
        new_unpad = (new_shape[1], new_shape[0])
        ratio = new_shape[1] / shape[1], new_shape[0] / shape[0]  # width, height ratios

    dw /= 2  # divide padding into 2 sides
    dh /= 2

    if shape[::-1] != new_unpad:  # resize
        img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR)
    top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))
    left, right = int(round(dw - 0.1)), int(round(dw + 0.1))
    img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)  # add border
    return img, ratio, (dw, dh)


def clip_coords(boxes, img_shape):
    # Clip bounding xyxy bounding boxes to image shape (height, width)
    boxes[:, 0].clamp_(0, img_shape[1])  # x1
    boxes[:, 1].clamp_(0, img_shape[0])  # y1
    boxes[:, 2].clamp_(0, img_shape[1])  # x2
    boxes[:, 3].clamp_(0, img_shape[0])  # y2


def xywh2xyxy(x):
    # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right
    y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)
    y[:, 0] = x[:, 0] - x[:, 2] / 2  # top left x
    y[:, 1] = x[:, 1] - x[:, 3] / 2  # top left y
    y[:, 2] = x[:, 0] + x[:, 2] / 2  # bottom right x
    y[:, 3] = x[:, 1] + x[:, 3] / 2  # bottom right y
    
    return y


CLASSES  = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light',
        'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
        'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee',
        'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard',
        'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich',
        'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed',
        'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink',
        'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush']


def preprocess(img, img_size):
    img0 = img.copy()
    img = letterbox(img, new_shape=img_size)[0]
    img = img[:, :, ::-1].transpose(2, 0, 1)
    img = np.ascontiguousarray(img).astype(np.float32)
    img = torch.from_numpy(img)
    img /= 255.0
    if img.ndimension() == 3:
        img = img.unsqueeze(0)

    return img0, img


def draw(image, boxes, scores, classes):
    """Draw the boxes on the image.

    # Argument:
        image: original image.
        boxes: ndarray, boxes of objects.
        classes: ndarray, classes of objects.
        scores: ndarray, scores of objects.
        all_classes: all classes name.
    """
    for box, score, cl in zip(boxes, scores, classes):
        top, left, right, bottom = box
        # print('class: {}, score: {}'.format(CLASSES[cl], score))
        # print('box coordinate left,top,right,down: [{}, {}, {}, {}]'.format(top, left, right, bottom))
        top = int(top)
        left = int(left)
        right = int(right)
        bottom = int(bottom)

        cv2.rectangle(image, (top, left), (right, bottom), (255, 0, 0), 2)
        cv2.putText(image, '{0} {1:.2f}'.format(CLASSES[cl], score),
                    (top, left - 6),
                    cv2.FONT_HERSHEY_SIMPLEX,
                    0.6, (0, 0, 255), 2)


def detect(im, img_size, sess, input_name, outputs_name):
    im0, img = preprocess(im, img_size)
    input_data = onnx_inference(img.numpy(), sess, input_name, outputs_name)
    boxes, classes, scores = yolov5_post_process(input_data)
    
    if boxes is not None:
        draw(im, boxes, scores, classes)
    cv2.imshow('demo', im)
    cv2.waitKey(1)


def onnx_inference(img, sess, input_name, outputs_name):
    
    # 模型推理:模型输出节点名,模型输入节点名,输入数据(注意节点名的格式!!!!!)
    outputs = sess.run(outputs_name, {input_name: img})
    input0_data = outputs[0]
    input1_data = outputs[1]
    input2_data = outputs[2]

    input0_data = input0_data.reshape([3, 80, 80, 85])
    input1_data = input1_data.reshape([3, 40, 40, 85])
    input2_data = input2_data.reshape([3, 20, 20, 85])

    input_data = list()
    input_data.append(np.transpose(input0_data, (1, 2, 0, 3)))
    input_data.append(np.transpose(input1_data, (1, 2, 0, 3)))
    input_data.append(np.transpose(input2_data, (1, 2, 0, 3)))

    return input_data


def load_onnx_model():
    # onnx模型前向推理
    sess = rt.InferenceSession('./weights/modified_yolov5s.onnx')
    # 模型的输入和输出节点名,可以通过netron查看
    input_name = 'images'
    outputs_name = ['396', '440', '484']
    
    return sess, input_name, outputs_name


if __name__ == '__main__':
    # create onnx_model
    sess, input_name, outputs_name = load_onnx_model()
    # input_model_size
    img_size = 640
    # read video
    video = cv2.VideoCapture('./video/cut3.avi')
    print("Loaded video ...")
    frame_interval = 2  # 间隔帧数,例如每隔10帧获取一次
    frame_count = 0
    while True:
        # 读取每帧图片
        _, im = video.read()
        if frame_count % frame_interval == 0:
            if im is None:
                break
            # 缩小尺寸,1920x1080->960x540
            im = cv2.resize(im, (640, 640))
            list_bboxs = []
            # det_object
            detect(im, img_size, sess, input_name, outputs_name)
        frame_count += 1
    video.release()
    cv2.destroyAllWindows()



(2) feature_extractor.py的修改:

这里有4种推理情况:ckpt.t7是ReID( Re-identification利用算法),在图像库中找到要搜索的目标的技术,所以它是属于图像检索的一个子问题。

        (1) 动态的batch_size推理:由于检测到的目标是多个object,在本项目的代码REID推理中,会将目标通过torch.cat连接起来,变成(n, 64, 128)的形状,所以需要用动态的onnx模型

        (2)那我就想要静态的怎么办,安排!!!,思路就是将cat的拆分开就行了,shape变成(1, 64 , 128),单个推理后将结果cat起来就行了,easy的。

重要!!!!ckpt文件转onnx的代码

import os
import cv2
import time
import argparse
import torch
import numpy as np
from deep_sort import build_tracker
from utils.draw import draw_boxes
from utils.parser import get_config
from tqdm import tqdm


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("--config_deepsort", type=str, default="./configs/deep_sort.yaml", help='Configure tracker')
    parser.add_argument("--cpu", dest="use_cuda", action="store_false", default=True, help='Run in CPU')
    args = parser.parse_args()

    cfg = get_config()
    cfg.merge_from_file(args.config_deepsort)
    use_cuda = args.use_cuda and torch.cuda.is_available()
    torch.set_grad_enabled(False)
    model = build_tracker(cfg, use_cuda=False)

    model.reid = True
    model.extractor.net.eval()

    device = 'cpu'
    output_onnx = 'deepsort.onnx'
    # ------------------------ export -----------------------------
    print("==> Exporting model to ONNX format at '{}'".format(output_onnx))
    input_names = ['input']
    output_names = ['output']

    input_tensor = torch.randn(1, 3, 128, 64, device=device)

    torch.onnx.export(model.extractor.net, input_tensor, output_onnx, export_params=True, verbose=False,
                      input_names=input_names, output_names=output_names, opset_version=13,
                      do_constant_folding=True)

        (3)但是要转rknn怎么办,ckpt.t7转onnx后,有一个ReduceL2,不支持量化,我就转的fp16(在RK3588上是可以的,rk1808不知道行不行),不过我尝试了将最后两个节点删除,对结果好像没有什么影响(用的是cut后的onnx推理),有懂的朋友可以解释一下!!!

        (4) 就是rknn的推理,这里就不展示了,需要的私聊我吧

import torch
import torchvision.transforms as transforms
import numpy as np
import cv2
# import onnxruntime as rt
# from rknnlite.api import RKNNLite


class Extractor(object):
    def __init__(self, model_path):
        self.model_path = model_path
        self.device = "cpu"
        self.size = (64, 128)
        self.norm = transforms.Compose([
            transforms.ToTensor(),
            transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
        ])
    
    def _preprocess(self, im_crops):
        """
        TODO:
            1. to float with scale from 0 to 1
            2. resize to (64, 128) as Market1501 dataset did
            3. concatenate to a numpy array
            3. to torch Tensor
            4. normalize
        """
        
        def _resize(im, size):
            return cv2.resize(im.astype(np.float32) / 255., size)
        
        im_batch = torch.cat([self.norm(_resize(im, self.size)).unsqueeze(0) for im in im_crops], dim=0).float()
        
        return im_batch
    
    def __call__(self, im_crops):
        im_batch = self._preprocess(im_crops)

        # sess = rt.InferenceSession(self.model_path)
        # 模型的输入和输出节点名,可以通过netron查看
        # input_name = 'input'
        # outputs_name = ['output']
        
        # (1)动态输出
        # features = sess.run(outputs_name, {input_name: im_batch.numpy()})
        # print('features:', np.array(features)[0, :, :].shape)
        # return np.array(features)[0, :, :]

        
        # (2)静态态输出
        # sort_results = []
        # n = im_batch.numpy().shape[0]
        # for i in range(n):
        #     img = im_batch.numpy()[i, :, :].reshape(1, 3, 128, 64)
        #     feature = sess.run(outputs_name, {input_name: img})
        #     feature = np.array(feature)
        #     sort_results.append(feature)
        # features = np.concatenate(sort_results, axis=1)[0, :, :]
        # print(features.shape)
        # return np.array(features)


        # (3)去掉onnx的最后两个节点的静态模型输出
        # input_name = 'input'
        # outputs_name = ['204']
        # sort_results = []
        # n = im_batch.numpy().shape[0]
        # for i in range(n):
        #     img = im_batch.numpy()[i, :, :].reshape(1, 3, 128, 64)
        #     feature = sess.run(outputs_name, {input_name: img})
        #     feature = np.array(feature)
        #     sort_results.append(feature)
        # features = np.concatenate(sort_results, axis=1)[0, :, :]
        # print(features.shape)
        # return np.array(features)
        
        # (4 )rk模型修改
        # rknn_lite = RKNNLite()
        # rknn_lite.load_rknn('./weights/ckpt_fp16.rknn')
        # ret = rknn_lite.init_runtime(core_mask=RKNNLite.NPU_CORE_0_1_2)
        # if ret != 0:
        #     print('Init runtime environment failed')
        #     exit(ret)
        # print('done')
        
        # sort_results = []
        # n = im_batch.numpy().shape[0]
        # for i in range(n):
        #    img = im_batch.numpy()[i, :, :].reshape(1, 3, 128, 64)
        #    feature = self.model_path.inference(inputs=[img])
        #   feature = np.array(feature)
        #    sort_results.append(feature)
        # features = np.concatenate(sort_results, axis=1)[0, :, :]
        # print(features.shape)
        # return np.array(features)


5.结果展示

        onnx的转换结果(测试视频地址)

 

检测结果

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

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

相关文章

linux--链表动态创建

头插法&#xff1a; 核心代码&#xff1a; s->next head->next; head->next s; 尾插法 核心代码&#xff1a; tail head; s->next NULL; tail->next s; tail s; 当用头插法依次插入值分别为1,2,3,4,5的结点后&#xff0c; 单链表顺序为&#xff1a; he…

第一章 Java反射机制(韩顺平老师Java基础学习记录)

文章目录 前言一、没有反射机制前的java代码存在什么问题&#xff1f;二、使用反射机制解决问题1.加载类2.读入数据 总结 前言 每一项新技术以及新概念的提出都是源于存在着新“问题”&#xff0c;放在代码领域可以说是存在着新需求&#xff0c;那么为了解决这个需求&#xff…

谈谈无线充电技术

目录 1.无线充电的概念 2.无线充电的原理 3.无线充电技术的发展过程 4.无线充电的优势 5.无线充电的潜在危害 1.无线充电的概念 无线充电是一种无需通过物理连接&#xff0c;通过电磁感应或者共振等技术&#xff0c;实现设备充电的方式。它消除了传统有线充电中需要插拔电…

等保案例 7

用户简介 廊坊市审计局主管全市审计工作&#xff0c;负责对全市财政收支和法律法规规定属于审计监督范围的财务收支的真实、合法和效益进行审计监督&#xff1b;对审计、专项审计调查和核查社会审计机构相关审计报告的结果承担责任&#xff0c;并负有督促被审计单位整改的责任…

docker oracle linux命令执行sql

docker 安装参照 https://blog.csdn.net/arcsin_/article/details/123707618 docker container ls -a命令查看容器名 打开容器 docker exec -it orcl19c_03 /bin/bashsys 用户登录容器 sqlplus / as sysdbashow pdbs;什么是pdb数据库&#xff1f;什么是CDB&#xff1f; 参…

推进深度融合 打造智慧媒体

以下内容来自于易知微官网&#xff0c;点击一下&#xff0c;即可进入官网了解详情。 注意&#xff1a;案例数据均为虚拟数据 数字改革是一场波及经济社会发展全局、涵盖生产力到生产关系的全方位变革。在数字化时代&#xff0c;以数字改革赋能媒体深度融合已然成为时代所向、…

github以及上传代码处理

最近在github上传代码的时候出现了&#xff1a; /video_parser# git push -u origin main Username for https://github.com: gtnyxxx Password for https://gtny2010github.com: remote: Support for password authentication was removed on August 13, 2021. remote: Plea…

LeetCode450. 删除二叉搜索树中的节点

450. 删除二叉搜索树中的节点 文章目录 [450. 删除二叉搜索树中的节点](https://leetcode.cn/problems/delete-node-in-a-bst/)一、题目二、题解方法一&#xff1a;递归&#xff08;一种麻烦的方法&#xff09;方法二&#xff1a;优化后的递归 一、题目 给定一个二叉搜索树的根…

AJ-Captcha行为验证在vue中的使用

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 项目场景&#xff1a;由原先的验证码校验升级为行为验证校验 使用方法 提示&#xff1a;参考文档&#xff1a; 参考文档&#xff1a;vue使用AJ-Captcha文档 gitee地址&#xff1a;AJ-Captcha &…

【Apollo】Apollo版本变迁里程碑

特点与改进 概述里程碑6.0版本特点及改进7.0版本特点及改进8.0版本特点及改进代码差异 主页传送门&#xff1a;&#x1f4c0; 传送 概述 Apollo (阿波罗)是一个开放的、完整的、安全的平台&#xff0c;将帮助汽车行业及自动驾驶领域的合作伙伴结合车辆和硬件系统&#xff0c;快…

python3ide手机安卓版下载,python3下载手机安卓版

本篇文章给大家谈谈python3ide手机安卓版下载&#xff0c;以及python3下载手机安卓版&#xff0c;希望对各位有所帮助&#xff0c;不要忘了收藏本站喔。 python3是一个在Android上运行Python3脚本引擎&#xff0c;python3整合了Python3解释器、Console、编辑器和SL4A库PHP与PYT…

智慧城市能实现嘛?数字孪生又在其中扮演什么角色?

数字孪生智慧城市是将数字孪生技术与城市智能化相结合的新兴概念&#xff0c;旨在通过实时数字模拟城市运行&#xff0c;优化城市管理与服务&#xff0c;创造更智能、高效、可持续的城市环境。 在智慧城市中&#xff0c;数字孪生技术可以实时收集、分析城市各个方面的数据&…

如何安装合适的显卡驱动,如何安装合适的驱动

大家好&#xff0c;小编为大家解答如何安装合适的松紧裤腰大房子呢的问题。很多人还不知道如何安装合适的显卡驱动版本&#xff0c;现在让我们一起来看看吧&#xff01; 1.准备好安装包 1&#xff09;上python官网下载python运行环境&#xff08;Download Python | Python.org&…

seaborn color palette 调色板颜色图

Here is a list of the Color Brewer palettes, with their names for easy reference: sns.lineplot(datanormal_df, palettesns.color_palette(paletteSet1, n_colors1))

KaiwuDB CTO 魏可伟:回归用户本位,打造“小而全”的数据库

8月16日&#xff0c;KaiwuDB 受邀亮相第十四届中国数据库技术大会 DTCC 2023。KaiwuDB CTO 魏可伟接受大会主办方的采访&#xff0c;双方共同围绕“数据库架构演进、内核引擎设计以及不同技术路线”展开深度探讨。 以下是采访的部分实录 ↓↓↓ 40 多年前&#xff0c;企业的数…

[mars3d 打包]vue3+vite,打包后mars3d找不到

前提 &#xff1a; vue3vite开发框架&#xff1b;使用 官网 方式3获取sdk,引入mars3d; 问题&#xff1a;开发时一切正常&#xff0c;打包之后&#xff0c;页面白屏&#xff0c;没有渲染&#xff1b; 相关的mars3d的相关方法会报错&#xff1b;但是mars3d的打印日志是有的&…

飞凌嵌入式邀您共聚2023深圳国际电子展(elexcon 2023)

8月23~25日&#xff0c;Elexcon 2023深圳国际电子展将在深圳会展中心&#xff08;福田&#xff09;举行&#xff0c;届时飞凌嵌入式将携多款重量级产品及热门行业解决方案亮相&#xff0c;展位号1Z55。飞凌嵌入式将聚焦5G、人工智能、智慧交通、智慧医疗、智慧电力、工业物联网…

PDF怎么转换成PPT?这个工具太好用了

pdf和ppt是常用的文档格式&#xff0c;只是功能不同&#xff0c;应用场景略有不同。pdf安全稳妥&#xff0c;更加适合文件阅读、传输和保存&#xff0c;ppt则多用于工作总结、产品宣传&#xff0c;更加生动形象&#xff0c;容易理解。有时候我们需要把pdf转换成ppt&#xff0c;…

PSP - 基于扩散生成模型预测蛋白质结构 EigenFold 算法与环境配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132357976 Paper: EigenFold: Generative Protein Structure Prediction with Diffusion Models EigenFold 是用于蛋白质结构预测的扩散生成模型…

Windows系统提权(二)

Windows系统服务漏洞 Always Install Elevated-总是以高权限安装 AlwaysInstallElevated是一个策略设置&#xff0c;当在系统中使用Windows Installer安装任何程序时&#xff0c;该参数允许非特权用户以system权限运行MSI文件。如果目标系统上启用了这一设置&#xff0c;我们…