pth转onnx,同时使用onnx进行部署

像我一样的菜鸡在使用开源的深度学习代码时,对于输出的pth模型文件,在预测时使用开源的predict.py文件进行部署,但是使用pth文件有一个问题,就是每次他都要重新加载一次模型,而且不方便移植,所以,想使用onnx进行部署,特此记录

pth2onnx

import torch
from ptsemseg.models import get_model

# 设置device
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
# torch.onnx.export的两个参数input和output
input=["input"]
output=['output']

# 加载模型model
model = get_model('pspnet', 150, version = 'ade20k')
model = model.eval().to(device)

# 构造一个输入图像Tensor为x
x = torch.randn(1, 3, 256, 256).to(device)
# 导出为onnx
torch.onnx.export(model, x, "pspnet.onnx256", verbose=True, input_names=input, output_names=output, opset_version=11)

 preonnx

参照使用pth文件进行预测的predict.py,这里我新建了一个preonnx.py来使用onnx文件来进行预测

两个文件的核心是tensor和numpy数据类型的转换以及维度变换

使用pth进行预测

import numpy as np

from skimage.transform import resize
import cv2

import torch
import time
import onnx
import onnxruntime as ort
from ptsemseg.models import get_model
from ptsemseg.utils import convert_state_dict


device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
weight_path = "../../pspnet_50_ade20k.pth"



def color_map(N=256, normalized=False):
    """
    Return Color Map in PASCAL VOC format (rgb)
    \param N (int) number of classes
    \param normalized (bool) whether colors are normalized (float 0-1)
    \return (Nx3 numpy array) a color map
    """
    def bitget(byteval, idx):
        return ((byteval & (1 << idx)) != 0)
    dtype = 'float32' if normalized else 'uint8'
    cmap = np.zeros((N, 3), dtype=dtype)
    for i in range(N):
        r = g = b = 0
        c = i
        for j in range(8):
            r = r | (bitget(c, 0) << 7-j)
            g = g | (bitget(c, 1) << 7-j)
            b = b | (bitget(c, 2) << 7-j)
            c = c >> 3
        cmap[i] = np.array([r, g, b])
    cmap = cmap/255.0 if normalized else cmap
    return cmap

def decode_segmap(temp, n_classes, cmap):
    """
    Given an image of class predictions, produce an bgr8 image with class colors
    \param temp (2d numpy int array) input image with semantic classes (as integer)
    \param n_classes (int) number of classes
    \cmap (Nx3 numpy array) input color map
    \return (numpy array bgr8) the decoded image with class colors
    """
    r = temp.copy()
    g = temp.copy()
    b = temp.copy()
    for l in range(0, n_classes):
        r[temp == l] = cmap[l,0]
        g[temp == l] = cmap[l,1]
        b[temp == l] = cmap[l,2]
    bgr = np.zeros((temp.shape[0], temp.shape[1], 3))
    bgr[:, :, 0] = b
    bgr[:, :, 1] = g
    bgr[:, :, 2] = r
    return bgr.astype(np.uint8)

def predict_max(img):
        """
        Do semantic prediction for max fusion
        \param img (numpy array rgb8)
        """
        class_probs = predict(img)
        # Take best prediction and confidence
        pred_confidence, pred_label = class_probs.max(1)
        pred_confidence = pred_confidence.squeeze(0).cpu().numpy()
        pred_label = pred_label.squeeze(0).cpu().numpy()
        pred_label = resize(pred_label, (375, 500), order = 0, mode = 'reflect', anti_aliasing=False, preserve_range = True) # order = 0, nearest neighbour
        pred_label = pred_label.astype(np.int64)
        # Add semantic color
        semantic_color = decode_segmap(pred_label, 150, cmap)
        pred_confidence = resize(pred_confidence, (375, 500),  mode = 'reflect', anti_aliasing=True, preserve_range = True)
        return (semantic_color, pred_confidence)

def predict(img):
        """
        Do semantic segmantation
        \param img: (numpy array bgr8) The input cv image
        """
        img = img.copy() # Make a copy of image because the method will modify the image
        #orig_size = (img.shape[0], img.shape[1]) # Original image size
        # Prepare image: first resize to CNN input size then extract the mean value of SUNRGBD dataset. No normalization
        img = resize(img, cnn_input_size, mode = 'reflect', anti_aliasing=True, preserve_range = True) # Give float64
        img = img.astype(np.float32)
        img -= mean
        # Convert HWC -> CHW
        img = img.transpose(2, 0, 1)
        # Convert to tensor
        img = torch.tensor(img, dtype = torch.float32)
        img = img.unsqueeze(0) # Add batch dimension required by CNN
        with torch.no_grad():
            img = img.to(device)
            # Do inference
            since = time.time()
            outputs = model(img) #N,C,W,H
            # Apply softmax to obtain normalized probabilities
            outputs = torch.nn.functional.softmax(outputs, 1)
            return outputs

if __name__ == '__main__':
    cmap = color_map(N = 150, normalized = False)
    color_img = cv2.imread("./include/2007_000661.jpg")
    weight_dict = torch.load(weight_path, map_location={'cuda:0':'cpu'})

    cnn_input_size = (473, 473)
    mean = np.array([104.00699, 116.66877, 122.67892]) # Mean value of dataset

    model = get_model("pspnet",150, version = 'ade20k')
    state = torch.load(weight_path, map_location={'cuda:0':'cpu'})
    model.load_state_dict(convert_state_dict(state['model_state'])) # Remove 'module' from dictionary keys
    
    model = model.to(device)
    model.eval().to(device)
    
    semantic_color, pred_confidence = predict_max(color_img)
    while(1):
        cv2.imshow("semantic_color", semantic_color)
        if cv2.waitKey(0) & 0xFF == ord('q'):
            break

使用onnx进行预测

import numpy as np
from skimage.transform import resize
import cv2
import onnxruntime as ort
import torch
import time

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

# Load the ONNX model
onnx_model_path = "./pspnet473.onnx"
ort_session = ort.InferenceSession(onnx_model_path)

def color_map(N=256, normalized=False):
    """
    Return Color Map in PASCAL VOC format (rgb)
    \param N (int) number of classes
    \param normalized (bool) whether colors are normalized (float 0-1)
    \return (Nx3 numpy array) a color map
    """
    def bitget(byteval, idx):
        return ((byteval & (1 << idx)) != 0)
    dtype = 'float32' if normalized else 'uint8'
    cmap = np.zeros((N, 3), dtype=dtype)
    for i in range(N):
        r = g = b = 0
        c = i
        for j in range(8):
            r = r | (bitget(c, 0) << 7-j)
            g = g | (bitget(c, 1) << 7-j)
            b = b | (bitget(c, 2) << 7-j)
            c = c >> 3
        cmap[i] = np.array([r, g, b])
    cmap = cmap/255.0 if normalized else cmap
    return cmap

def decode_segmap(temp, n_classes, cmap):
    """
    Given an image of class predictions, produce an bgr8 image with class colors
    \param temp (2d numpy int array) input image with semantic classes (as integer)
    \param n_classes (int) number of classes
    \cmap (Nx3 numpy array) input color map
    \return (numpy array bgr8) the decoded image with class colors
    """
    r = temp.copy()
    g = temp.copy()
    b = temp.copy()
    for l in range(0, n_classes):
        r[temp == l] = cmap[l,0]
        g[temp == l] = cmap[l,1]
        b[temp == l] = cmap[l,2]
    bgr = np.zeros((temp.shape[0], temp.shape[1], 3))
    bgr[:, :, 0] = b
    bgr[:, :, 1] = g
    bgr[:, :, 2] = r
    return bgr.astype(np.uint8)

if __name__ == '__main__':
    cmap = color_map(N=150, normalized=False)
    color_img = cv2.imread("./2007_000661.jpg")

    # Resize image to match the model's input size
    input_size = (473, 473)  #473 256
    color_img_resized = cv2.resize(color_img, input_size)

    # Preprocess the image
    img = color_img_resized.astype(np.float32)
    img -= np.array([104.00699, 116.66877, 122.67892])  # Mean value of dataset
    img = img.transpose(2, 0, 1)
    img = np.expand_dims(img, axis=0)

    # Perform inference
    outputs = ort_session.run(None, {'input': img})
    class_probs = outputs[0]

    # Process the output to get semantic color and confidence
    pred_confidence, pred_label = np.max(class_probs, axis=1), np.argmax(class_probs, axis=1)
    pred_label = pred_label.squeeze(0)
    pred_label = resize(pred_label, (375, 500), order=0, mode='reflect', anti_aliasing=False, preserve_range=True)
    pred_label = pred_label.astype(np.int64)
    semantic_color = decode_segmap(pred_label, 150, cmap)
    pred_confidence = resize(pred_confidence, (375, 500), mode='reflect', anti_aliasing=True, preserve_range=True)

    # Display the result
    while(1):
        cv2.imshow("semantic_color", semantic_color)
        if cv2.waitKey(0) & 0xFF == ord('q'):
            break

成功案例

使用pth进行预测(不重要)

相关代码为(主要关注tensor维度变化和处理方式)

    def detect_image(self, image, count=False, name_classes=None):
        #   在这里将图像转换成RGB图像,防止灰度图在预测时报错。
        #   代码仅仅支持RGB图像的预测,所有其它类型的图像都会转化成RGB
        image       = cvtColor(image)
        #   对输入图像进行一个备份,后面用于绘图
        old_img     = copy.deepcopy(image)
        orininal_h  = np.array(image).shape[0]
        orininal_w  = np.array(image).shape[1]
        #   给图像增加灰条,实现不失真的resize
        #   也可以直接resize进行识别
        image_data, nw, nh  = resize_image(image, (self.input_shape[1],self.input_shape[0]))
        #   添加上batch_size维度
        image_data  = np.expand_dims(np.transpose(preprocess_input(np.array(image_data, np.float32)), (2, 0, 1)), 0)

        with torch.no_grad():
            images = torch.from_numpy(image_data)
            if self.cuda:
                images = images.cuda()
                
            #   图片传入网络进行预测
            pr = self.net(images)[0]                                    # tensor:[21,512,512]
            #   取出每一个像素点的种类,使用pr.permute(1,2,0)进行维度转换,并转为numpy
            pr = F.softmax(pr.permute(1,2,0),dim = -1).cpu().numpy()    # numpy:[512,512,21]
            #   将灰条部分截取掉
            pr = pr[int((self.input_shape[0] - nh) // 2) : int((self.input_shape[0] - nh) // 2 + nh), \
                    int((self.input_shape[1] - nw) // 2) : int((self.input_shape[1] - nw) // 2 + nw)]
            #   进行图片的resize
            pr = cv2.resize(pr, (orininal_w, orininal_h), interpolation = cv2.INTER_LINEAR)
            #   取出每一个像素点的种类
            pr = pr.argmax(axis=-1)                                     # numpy:[512,512]
            seg_img = np.reshape(np.array(self.colors, np.uint8)[np.reshape(pr, [-1])], [orininal_h, orininal_w, -1])
            #   将新图片转换成Image的形式
            image   = Image.fromarray(np.uint8(seg_img))
            #   将新图与原图及进行混合
            image   = Image.blend(old_img, image, 0.7)
            return image

推理时间 

使用onnx进行预测(完整)

 相关代码为(主要看操作的数据类型和操作方法)

import time
import copy
import colorsys
import onnx
import onnxruntime as ort

import cv2
import numpy as np
from PIL import Image
from utils.utils import cvtColor, preprocess_input, resize_image, show_config

import torch
from torch import nn
import torch.nn.functional as F

name_classes = ["background", "aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow",
                "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train",
                "tvmonitor"]

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

# Load the ONNX model
onnx_model_path = "./model_data/models.onnx"
ort_session = ort.InferenceSession(onnx_model_path)

mix_type = 0
colors = [(0, 0, 0), (128, 0, 0), (0, 128, 0), (128, 128, 0), (0, 0, 128), (128, 0, 128), (0, 128, 128),
          (128, 128, 128), (64, 0, 0), (192, 0, 0), (64, 128, 0), (192, 128, 0), (64, 0, 128), (192, 0, 128),
          (64, 128, 128), (192, 128, 128), (0, 64, 0), (128, 64, 0), (0, 192, 0), (128, 192, 0), (0, 64, 128),
          (128, 64, 12)]


def onnx_detect(image):
    image = cvtColor(image)
    old_img = copy.deepcopy(image)
    orininal_h = np.array(image).shape[0]
    orininal_w = np.array(image).shape[1]
    image_data, nw, nh = resize_image(image, (512, 512))
    image_data = np.expand_dims(np.transpose(preprocess_input(np.array(image_data, np.float32)), (2, 0, 1)), 0)

    outputs = ort_session.run(None, {'images': image_data})
    # 获取想要的信息
    pr = outputs[0]                # numpy:[1,21,512,512]
    # 将由tensor转换成的numpy的多余维度去掉,使用np.squeeze方法
    pr = np.squeeze(pr, axis=0)    # numpy:[21,512,512]
    # 改变numpy维度顺序,将类别信息放在最后一维
    pr = np.transpose(pr,(1,2,0))  # numpy:[512,512,21]
    pr = np.exp(pr) / np.sum(np.exp(pr), axis=-1, keepdims=True)
    pr = pr[int((512 - nh) // 2): int((512 - nh) // 2 + nh), \
         int((512 - nw) // 2): int((512 - nw) // 2 + nw)]
    # 进行图片的resize
    pr = cv2.resize(pr, (orininal_w, orininal_h), interpolation=cv2.INTER_LINEAR)
    # 取出每一个像素点的种类
    pr = pr.argmax(axis=-1)  # numpy:[512,512]

    seg_img = np.reshape(np.array(colors, np.uint8)[np.reshape(pr, [-1])], [orininal_h, orininal_w, -1])
    # ------------------------------------------------#
    #   将新图片转换成Image的形式
    # ------------------------------------------------#
    image = Image.fromarray(np.uint8(seg_img))
    # ------------------------------------------------#
    #   将新图与原图及进行混合
    # ------------------------------------------------#
    image = Image.blend(old_img, image, 0.7)

    return image


while True:
    frame = cv2.imread("/home/pc/文档/deeplabv3-plus-pytorch-main/img/street.jpg")

    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    # 转变成Image
    frame = Image.fromarray(np.uint8(frame))
    # 进行检测
    frame = np.array(onnx_detect(frame))
    # RGBtoBGR满足opencv显示格式
    frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)

    cv2.imshow("video", frame)
    if cv2.waitKey(1) & 0xff == ord('q'):
        break













思路解释 

1.首先将输入的待处理图片resize为模型要求的尺寸(512,512) 

image_data, nw, nh = resize_image(image, (512, 512))

2.对图像数据进行预处理,并将其转换为适合模型输入的格式。

  • np.transpose(..., (2, 0, 1)):将预处理后的图像数据的维度进行转置。原始图像数据的维度可能是(高度,宽度,通道数),而模型通常要求输入数据的维度为(通道数,高度,宽度)。通过转置操作,可以将数据维度调整为符合模型要求的格式。
  • np.expand_dims(..., 0):在转置后的图像数据的第一个维度上增加一个新的维度。这样做是为了将单张图像扩展为一个批次(batch)的形式,因为模型通常接受批量的输入数据。
image_data = np.expand_dims(np.transpose(preprocess_input(np.array(image_data, np.float32)), (2, 0, 1))

3.onnx推理,得到的outputs为list,再使用pr=outputs[0]得到信息数据,pr为numpy数据

outputs = ort_session.run(None, {'images': image_data})
pr = outputs[0]

4. 对pr维度进行调整,去掉多余的第一维(batch),此时pr为[21,512,512],对应[类别数,宽,高]

pr = np.squeeze(pr, axis=0)

5. 进行维度变换,把[类别数,宽,高]改为[宽,高,类别数]

pr = np.transpose(pr,(1,2,0))

6. 归一化

pr = np.exp(pr) / np.sum(np.exp(pr), axis=-1, keepdims=True)

7.这段代码的作用是对图像数据进行裁剪,以适应模型的输入要求。

  • int((512 - nh) // 2):计算裁剪后的图像高度的起始位置。假设原始图像的高度为nh,而模型要求的输入高度为512,那么需要将图像在高度方向上居中裁剪,使得裁剪后的图像高度为512。这里使用整除运算符//来确保结果为整数。
  • int((512 - nh) // 2 + nh):计算裁剪后的图像高度的结束位置。通过起始位置加上原始图像的高度nh,可以得到裁剪后的图像高度的结束位置。
  • int((512 - nw) // 2):计算裁剪后的图像宽度的起始位置。同样地,假设原始图像的宽度为nw,而模型要求的输入宽度为512,那么需要将图像在宽度方向上居中裁剪,使得裁剪后的图像宽度为512。
  • int((512 - nw) // 2 + nw):计算裁剪后的图像宽度的结束位置。通过起始位置加上原始图像的宽度nw,可以得到裁剪后的图像宽度的结束位置。
pr = pr[int((512 - nh) // 2): int((512 - nh) // 2 + nh), int((512 - nw) // 2): int((512 - nw) // 2 + nw)]

8.将图片resize成原尺寸

pr = cv2.resize(pr, (orininal_w, orininal_h), interpolation=cv2.INTER_LINEAR)

9. 取出每一个像素的类别,因为axis=-1代表最后一维,也就是类别这一维,然后对每一个像素取argmax,得到对应的置信度最大的类别作为这个像素的类别

pr = pr.argmax(axis=-1)

 

10.这段代码的作用是将预测结果(pr)转换为彩色图像(seg_img)。具体解释如下:

  • np.reshape(pr, [-1]):将预测结果(pr)展平为一维数组。[-1]表示自动计算展平后的维度大小,即原始数组的元素总数。
  • np.array(colors, np.uint8):将颜色列表(colors)转换为NumPy数组,并将数据类型设置为uint8。
  • np.array(colors, np.uint8)[np.reshape(pr, [-1])]:使用展平后的预测结果作为索引,从颜色数组中获取对应的颜色值。这样可以得到与预测结果相同大小的彩色值数组。
  • np.reshape(..., [orininal_h, orininal_w, -1]):将彩色值数组重新调整为原始图像的高度和宽度,以及通道数(这里使用-1表示自动计算通道数)。
  • 综上所述,这段代码的目的是将预测结果转换为彩色图像,以便可视化分割结果
seg_img = np.reshape(np.array(colors, np.uint8)[np.reshape(pr, [-1])], [orininal_h, orininal_w, -1])

11.这段代码的作用是将彩色图像(seg_img)转换为PIL.Image对象(image)。具体解释如下:

  • np.uint8(seg_img):将彩色图像数组的数据类型转换为uint8,以确保像素值在0到255的范围内。
  • Image.fromarray(...):使用NumPy数组作为输入,创建一个PIL.Image对象。这个对象可以用于显示、保存或进一步处理图像。
image = Image.fromarray(np.uint8(seg_img))

12将原图和新图混合

image = Image.blend(old_img, image, 0.7)

 如果没有这一行,则是这样

推理时间

 

使用openvino进行推理加速(好像有问题,推理速度没怎么加速) 

代码

import time
import copy
import colorsys
import numpy as np
from PIL import Image
from utils.utils import cvtColor, preprocess_input, resize_image, show_config

import torch
from torch import nn
import torch.nn.functional as F
import openvino

from openvino.inference_engine import IECore
import cv2
from openvino.inference_engine import IECore

name_classes = ["background", "aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow",
                "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train",
                "tvmonitor"]

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

# Load the OpenVINO IR model
ir_model_path = "./model_data/models.xml"
ie = IECore()
net = ie.read_network(model=ir_model_path)
exec_net = ie.load_network(network=net, device_name="CPU")

mix_type = 0
colors = [(0, 0, 0), (128, 0, 0), (0, 128, 0), (128, 128, 0), (0, 0, 128), (128, 0, 128), (0, 128, 128),
          (128, 128, 128), (64, 0, 0), (192, 0, 0), (64, 128, 0), (192, 128, 0), (64, 0, 128), (192, 0, 128),
          (64, 128, 128), (192, 128, 128), (0, 64, 0), (128, 64, 0), (0, 192, 0), (128, 192, 0), (0, 64, 128),
          (128, 64, 12)]

def openvino_detect(image):
    image = cvtColor(image)
    old_img = copy.deepcopy(image)
    orininal_h = np.array(image).shape[0]
    orininal_w = np.array(image).shape[1]
    image_data, nw, nh = resize_image(image, (512, 512))
    image_data = np.expand_dims(np.transpose(preprocess_input(np.array(image_data, np.float32)), (2, 0, 1)), 0)

    input_blob = next(iter(net.input_info))
    output_blob = next(iter(net.outputs))
    res = exec_net.infer(inputs={input_blob: image_data})
    pr = res[output_blob]
    pr = np.squeeze(pr, axis=0)    # numpy:[21,512,512]
    # 改变numpy维度顺序,将类别信息放在最后一维
    pr = np.transpose(pr,(1,2,0))  # numpy:[512,512,21]
    pr = np.exp(pr) / np.sum(np.exp(pr), axis=-1, keepdims=True)

    pr = pr[int((512 - nh) // 2): int((512 - nh) // 2 + nh), int((512 - nw) // 2): int((512 - nw) // 2 + nw)]
    pr = cv2.resize(pr, (orininal_w, orininal_h), interpolation=cv2.INTER_LINEAR)
    pr = pr.argmax(axis=-1)

    seg_img = np.reshape(np.array(colors, np.uint8)[np.reshape(pr, [-1])], [orininal_h, orininal_w, -1])
    image = Image.fromarray(np.uint8(seg_img))

    # image = Image.blend(old_img, image, 0.7)

    return image
if __name__ == "__main__":
    while True:
        frame = cv2.imread("/home/pc/文档/deeplabv3-plus-pytorch-main/img/street.jpg")

        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        frame = Image.fromarray(np.uint8(frame))
        start_time = time.time()
        frame = np.array(openvino_detect(frame))
        end_time = time.time()
        print(f"推理耗时:{end_time - start_time} 秒")
        frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)

        cv2.imshow("video", frame)
        if cv2.waitKey(1) & 0xff == ord('q'):
            break

 输出

推理时间

 

总结

在使用 pth进行预测时,他的操作方法主要是通过torch自带的预测推理函数得出输出为tensor,转换维度后进行softmax,再转为numpy,再得出输出;而在使用onnx进行预测时,他的操作方法主要是通过onnxruntime的函数outputs = ort_session.run(None, {'images': image_data}),这里images'为转换为onnx时使用的input_name,image_data为输入图片,得到outputs后,pr = outputs[0]得到想要的信息,这里此时的pr为numpy,再根据pth预测时的操作,使用numpy的相关函数即可。

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

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

相关文章

Java 面向对象(基础)

1、面向对象的概述及两大要素&#xff1a;类与对象 1. 面向对象内容的三条主线&#xff1a; - Java类及类的成员&#xff1a;&#xff08;重点&#xff09;属性、方法、构造器&#xff1b;&#xff08;熟悉&#xff09;代码块、内部类 - 面向对象的特征&#xff1a;封装、继承…

31-数据流:通过iam-authz-server设计,看数据流服务的设计

IAM数据流服务iam-authz-server的设计和实现。 iam-authz-server的功能介绍 iam-authz-server目前的唯一功能&#xff0c;是通过提供 /v1/authz RESTful API接口完成资源授权。 /v1/authz 接口是通过github.com/ory/ladon来完成资源授权的。 因为iam-authz-server承载了数据流…

ES6展开运算符

1.展开可迭代对象&#xff08;简单理解为数组和伪数组&#xff09;&#xff0c;如数组、 NodeList 、arguments。 可以通过展开运算符把一个伪数组转换为数组 const a [...document.body.children]; console.log(a); console.log(Array.isArray(a));2.实现数组的浅拷贝 cons…

51单片机入门之独立按键

目录 1.按键简介 2.独立按键控制LED亮灭 3.独立按键控制LED移位 1.按键简介 在生活中&#xff0c;我们常常会见到各种按键&#xff0c;我们的开发板上也有按键&#xff0c;就在左下角有四个按键&#xff0c;我们把它们叫做独立按键。 独立按键的原理比较简单&…

【三十三】【算法分析与设计】回溯(1),46. 全排列,78. 子集,没有树结构,但是依旧模拟树结构,回溯,利用全局变量+递归函数模拟树结构

46. 全排列 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1&#xff0c;2&#xff0c;3] 输出&#xff1a;[[1&#xff0c;2&#xff0c;3]&#xff0c;[1&#xff0c;3&a…

WPF中通过自定义Panel实现控件拖动

背景 看到趋时软件的公众号文章&#xff08;WPF自定义Panel&#xff1a;让拖拽变得更简单&#xff09;&#xff0c;发现可以不通过Drag的方法来实现ListBox控件的拖动&#xff0c;而是通过对控件的坐标相加减去实现控件的位移等判断&#xff0c;因此根据文章里面的代码,边理解边…

考题抄错会做也白搭--模版方法模式

1.1 选择题不会做&#xff0c;蒙呗&#xff01; "题目抄错了&#xff0c;那就不是考试题目了&#xff0c;而考试试卷最大的好处就是&#xff0c;大家都是一样的题目&#xff0c;特别是标准化的考试&#xff0c;比如全是选择或判断的题目&#xff0c;那就最大化地限制了答题…

整合Mybatis(Spring学习笔记十二)

一、导入相关的包 junit 包 Mybatis包 mysql数据库包 Spring相关的包 Aop相关的包 Mybatis-Spring包&#xff08;现在就来学这个&#xff09; 提示jdk版本不一致的朋友记得 jdk8只支持spring到5.x 所以如果导入的spring(spring-we…

Linux:进程终止和等待

一、进程终止 main函数的返回值也叫做进程的退出码&#xff0c;一般0表示成功&#xff0c;非零表示失败。我们也可以用不同的数字来表示不同失败的原因。 echo $?//打印最近一次进程执行的退出码 而作为程序猿&#xff0c;我们更需要知道的是错误码所代表的错误信息&#x…

【智能算法】磷虾群算法(KHA)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2012年&#xff0c;Gandomi等人受到自然界中磷虾生存行为启发&#xff0c;提出了磷虾群算法&#xff08;Krill Herd Algorithm, KHA&#xff09;。 2.算法原理 2.1算法思想 KHA受南极鳞虾群觅食行…

Java | Leetcode Java题解之第8题字符串转换整数atoi

题目&#xff1a; 题解&#xff1a; class Solution {public int myAtoi(String str) {Automaton automaton new Automaton();int length str.length();for (int i 0; i < length; i) {automaton.get(str.charAt(i));}return (int) (automaton.sign * automaton.ans);} …

Matlab|储能辅助电力系统调峰的容量需求研究

目录 1 主要内容 目标函数 约束条件 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序参考文献《储能辅助电力系统调峰的容量需求研究》&#xff0c;主要是对火电、风电和储能等电力设备主体进行优化调度&#xff0c;在调峰能力达不到时采用弃负荷&#xff0c;程序以…

无人售货奶柜:开启便捷生活的新篇章

无人售货奶柜&#xff1a;开启便捷生活的新篇章 在这个快节奏的现代生活中&#xff0c;科技的革新不仅为我们带来了前所未有的便利&#xff0c;更在不经意间改变着我们的日常。其中&#xff0c;无人售货技术的出现&#xff0c;尤其是无人售货奶柜&#xff0c;已经成为我们生活…

012:vue3使用vue-i18n实现国际化

文章目录 1. 安装 vue-i18n2. 创建文件存储翻译的语言3. 注册i18n实例4. 在main.ts中引入vue-i18n实例5. 在组件模板中使用6. 在js中使用7. locale.value 实现国际化语言切换8. vue3 中ref里面的国际化值没生效问题 1. 安装 vue-i18n cnpm i --save vue-i18n2. 创建文件存储翻…

树状数组-数据结构

树状数组 t[x] 节点的父节点为 t[x lowbit(x)] 整棵树的深度为 log2n 1 1 . add(x,k) 给指定的节点x加上k — 动态的维护前缀和 需要从x开始&#xff0c;向上找到所有父节点&#xff0c;值都加上k 2. ask(x) 求取节点x之前的前缀和 求取单点之前的前缀和只需要累加即可 …

【算法】单单单单单调栈,接接接接接雨水

【算法】单单单单单调栈&#xff0c;接接接接接雨水 今天没有小故事。 参考以及题单来源&#xff1a; 代码随想录 (programmercarl.com) Part 1 啥是单调栈&#xff1f; 1.啥啥啥是单调栈&#xff1f; 栈的特性想必各位再熟悉不过了&#xff1a;先进后出。栈仅仅有一个出口&a…

算法 day29 回溯5

491 非递减子序列 给你一个整数数组 nums &#xff0c;找出并返回所有该数组中不同的递增子序列&#xff0c;递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。 数组中可能含有重复元素&#xff0c;如出现两个整数相等&#xff0c;也可以视作递增序列的一种特殊情…

检测头篇 | 利用RT-DETR模型的检测头去替换YOLOv8中的检测头

前言:Hello大家好,我是小哥谈。RT-DETR号称是打败YOLO的检测模型,其作为一种基于Transformer的检测方法,相较于传统的基于卷积的检测方法,提供了更为全面和深入的特征理解,将RT-DETR检测头融入YOLOv8,我们可以结合YOLO的实时检测能力和RT-DETR的深度特征理解能力,打造出…

业务网关的设计与实践

在过去的两年里&#xff0c;主要在做业务网关的开发。今年春节后选择转岗去做更偏近业务的开发。公司的业务是金融相关&#xff0c;一直觉得金融相关的业务是有一定门槛并且是对职业生涯有帮助的&#xff0c;所以趁这个机会来深入了解这块业务。 仔细回想&#xff0c;在做业务…

【数据处理包Pandas】数据载入与预处理

目录 一、数据载入二、数据清洗&#xff08;一&#xff09;Pandas中缺失值的表示&#xff08;二&#xff09;与缺失值判断和处理相关的方法 三、连续特征离散化四、哑变量处理 准备工作 导入 NumPy 库和 Pandas 库。 import numpy as np import pandas as pd一、数据载入 对…