YOLO11 目标检测 | 导出ONNX模型 | ONNX模型推理
本文分享YOLO11中,从xxx.pt权重文件转为.onnx文件,然后使用.onnx文件,进行目标检测任务的模型推理。
用ONNX模型推理,便于算法到开发板或芯片的部署。
备注:本文是使用Python,编写ONNX模型推理代码的
目录
1、导出ONNX模型
2、目标检测——ONNX模型推理
2.1、ONNX模型推理-整体流程
2.2、预处理函数
2.3、后处理函数
2.4、检测效果可视化函数
2.5、YOLO11目标检测——ONNX模型推理完整代码
1、导出ONNX模型
首先我们训练好的模型,生成xxx.pt权重文件;
然后用下面代码,导出ONNX模型(简洁版)
from ultralytics import YOLO# 加载一个模型,路径为 YOLO 模型的 .pt 文件
model = YOLO("runs/detect/train/weights/best.pt")# 导出模型,格式为 ONNX
model.export(format="onnx")
运行代码后,会在上面路径中生成best.onnx文件的
- 比如,填写的路径是:"runs/detect/train/weights/best.pt"
- 那么在runs/detect/train/weights/目录中,会生成与best.pt同名的onnx文件,即best.onnx
上面代码示例是简单版,如果需要更专业设置ONNX,用下面版本的
YOLO11导出ONNX模型(专业版)
from ultralytics import YOLO# 加载一个模型,路径为 YOLO 模型的 .pt 文件
model = YOLO("runs/detect/train/weights/best.pt")# 导出模型,设置多种参数
model.export(format="onnx", # 导出格式为 ONNXimgsz=(640, 640), # 设置输入图像的尺寸keras=False, # 不导出为 Keras 格式optimize=False, # 不进行优化half=False, # 不启用 FP16 量化int8=False, # 不启用 INT8 量化dynamic=False, # 不启用动态输入尺寸simplify=True, # 简化 ONNX 模型opset=None, # 使用最新的 opset 版本workspace=4.0, # 为 TensorRT 优化设置最大工作区大小(GiB)nms=False, # 不添加 NMS(非极大值抑制)batch=1 # 指定批处理大小
)
对于model.export( )函数中,各种参数说明:
format="onnx":指定导出模型的格式为 onnx。imgsz=(640, 640):输入图像的尺寸设为 640x640。如果需要其他尺寸可以修改这个值。keras=False:不导出为 Keras 格式的模型。optimize=False:不应用 TorchScript 移动设备优化。half=False:不启用 FP16(半精度)量化。int8=False:不启用 INT8 量化。dynamic=False:不启用动态输入尺寸。simplify=True:简化模型以提升 ONNX 模型的性能。opset=None:使用默认的 ONNX opset 版本,如果需要可以手动指定。workspace=4.0:为 TensorRT 优化指定最大工作空间大小为 4 GiB。nms=False:不为 CoreML 导出添加非极大值抑制(NMS)。batch=1:设置批处理大小为 1。
参考官网文档:https://docs.ultralytics.com/modes/export/#arguments
当然了,YOLO11中不仅支持ONNX模型,还支持下面表格中格式
| 支持的导出格式 | format参数值 | 生成的模型示例 | model.export( )函数的参数 |
|---|---|---|---|
| PyTorch | - | yolo11n.pt | - |
| TorchScript | torchscript | yolo11n.torchscript | imgsz, optimize, batch |
| ONNX | onnx | yolo11n.onnx | imgsz, half, dynamic, simplify, opset, batch |
| OpenVINO | openvino | yolo11n_openvino_model/ | imgsz, half, int8, batch |
| TensorRT | engine | yolo11n.engine | imgsz, half, dynamic, simplify, workspace, int8, batch |
| CoreML | coreml | yolo11n.mlpackage | imgsz, half, int8, nms, batch |
| TF SavedModel | saved_model | yolo11n_saved_model/ | imgsz, keras, int8, batch |
| TF GraphDef | pb | yolo11n.pb | imgsz, batch |
| TF Lite | tflite | yolo11n.tflite | imgsz, half, int8, batch |
| TF Edge TPU | edgetpu | yolo11n_edgetpu.tflite | imgsz |
| TF.js | tfjs | yolo11n_web_model/ | imgsz, half, int8, batch |
| PaddlePaddle | paddle | yolo11n_paddle_model/ | imgsz, batch |
| NCNN | ncnn | yolo11n_ncnn_model/ | imgsz, half, batch |
2、目标检测——ONNX模型推理
我们需要编写代码实现了一个使用 ONNXRuntime 执行 YOLOv11 检测模型推理的完整流程,包含图像预处理、推理、后处理和可视化 。
需要编写的代码功能包括:
-
预处理: 读取输入图像,通过 letterbox 填充图像,自动调整图像尺寸,使其符合模型的输入尺寸要求,并归一化并转换为模型输入的格式 。
-
模型推理: 使用 ONNXRuntime 加载YOLO11 模型,并根据系统环境自动选择 CPU 或 GPU 执行推理。预处理后的图像输入到模型中,模型返回预测的边界框、类别和分数等输出结果。
-
后处理: 对模型输出的边界框、类别和分数进行处理,首先根据置信度阈值过滤低置信度的检测结果。然后根据缩放比例将边界框映射回原图的尺寸,应用非极大值抑制(NMS)去除重叠的边界框,最终提取有效的检测结果。
-
可视化: 在输入图像上绘制检测到的边界框、类别名称和置信度,使用不同颜色区分不同类别的对象。可选择将带有检测结果的图像保存到文件中,最终输出检测结果保存的路径。
2.1、ONNX模型推理-整体流程
首先编写一个用于运行YOLO11检测模型的推理类:YOLO11
ONNX推理流程:预处理 -> 推理 -> 后处理
class YOLO11:"""YOLO11 目标检测模型类,用于处理推理和可视化。"""def __init__(self, onnx_model, input_image, confidence_thres, iou_thres):"""初始化 YOLO11 类的实例。参数:onnx_model: ONNX 模型的路径。input_image: 输入图像的路径。confidence_thres: 用于过滤检测结果的置信度阈值。iou_thres: 非极大值抑制(NMS)的 IoU(交并比)阈值。"""self.onnx_model = onnx_modelself.input_image = input_imageself.confidence_thres = confidence_thresself.iou_thres = iou_thres# 加载类别名称self.classes = CLASS_NAMES# 为每个类别生成一个颜色调色板self.color_palette = np.random.uniform(0, 255, size=(len(self.classes), 3))def main(self):# 使用 ONNX 模型创建推理会话,自动选择CPU或GPUsession = ort.InferenceSession(self.onnx_model, providers=["CUDAExecutionProvider", "CPUExecutionProvider"] if ort.get_device() == "GPU" else ["CPUExecutionProvider"],)# 打印模型的输入尺寸print("YOLO11 🚀 目标检测 ONNXRuntime")print("模型名称:", self.onnx_model)# 获取模型的输入形状model_inputs = session.get_inputs()input_shape = model_inputs[0].shape self.input_width = input_shape[2]self.input_height = input_shape[3]print(f"模型输入尺寸:宽度 = {self.input_width}, 高度 = {self.input_height}")# 预处理图像数据,确保使用模型要求的尺寸 (640x640)img_data = self.preprocess()# 使用预处理后的图像数据运行推理outputs = session.run(None, {model_inputs[0].name: img_data})# 对输出进行后处理以获取输出图像return self.postprocess(self.img, outputs) # 输出图像
2.2、预处理函数
然后编写输入图像预处理函数:preprocess
主要功能:对输入的图像进行读取、颜色空间转换、尺寸调整、归一化等预处理操作,并返回适合模型输入的图像数据。
- 使用 OpenCV 读取图像。
- 将图像从 BGR 格式转换为 RGB 格式。
- 使用
letterbox函数保持图像的宽高比并填充图像,使其符合模型要求的输入尺寸。 - 归一化图像数据(像素值除以 255.0)。
- 转换图像通道的维度,符合 PyTorch 模型的输入格式(通道优先)。
- 扩展图像维度以匹配模型输入的 batch 大小。
def preprocess(self):"""对输入图像进行预处理,以便进行推理。返回:image_data: 经过预处理的图像数据,准备进行推理。"""# 使用 OpenCV 读取输入图像self.img = cv2.imread(self.input_image)# 获取输入图像的高度和宽度self.img_height, self.img_width = self.img.shape[:2]# 将图像颜色空间从 BGR 转换为 RGBimg = cv2.cvtColor(self.img, cv2.COLOR_BGR2RGB)# 保持宽高比,进行 letterbox 填充, 使用模型要求的输入尺寸img, self.ratio, (self.dw, self.dh) = self.letterbox(img, new_shape=(self.input_width, self.input_height))# 通过除以 255.0 来归一化图像数据image_data = np.array(img) / 255.0# 将图像的通道维度移到第一维image_data = np.transpose(image_data, (2, 0, 1)) # 通道优先# 扩展图像数据的维度,以匹配模型输入的形状image_data = np.expand_dims(image_data, axis=0).astype(np.float32)# 返回预处理后的图像数据return image_data
预处理函数preprocess,会依赖letterbox函数。
letterbox函数功能:将图像缩放并进行填充,以保持宽高比,最终将图像调整到指定的输入尺寸。
- 计算图像的缩放比例,保证宽高比不变。
- 根据缩放后的图像尺寸,计算需要的填充量(上下左右)。
- 对图像进行缩放和添加边框(填充),确保最终图像尺寸符合目标输入尺寸。
- 返回调整后的图像、缩放比例及填充尺寸。
def letterbox(self, img, new_shape=(640, 640), color=(114, 114, 114), auto=False, scaleFill=False, scaleup=True):"""将图像进行 letterbox 填充,保持纵横比不变,并缩放到指定尺寸。"""shape = img.shape[:2] # 当前图像的宽高print(f"Original image shape: {shape}")if isinstance(new_shape, int):new_shape = (new_shape, new_shape)# 计算缩放比例r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) # 选择宽高中最小的缩放比if not scaleup: # 仅缩小,不放大r = min(r, 1.0)# 缩放后的未填充尺寸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] # 计算填充的尺寸dw /= 2 # padding 均分dh /= 2# 缩放图像if shape[::-1] != new_unpad: # 如果当前图像尺寸不等于 new_unpad,则缩放img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR)# 为图像添加边框以达到目标尺寸top, bottom = int(round(dh)), int(round(dh))left, right = int(round(dw)), int(round(dw))img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)print(f"Final letterboxed image shape: {img.shape}")return img, (r, r), (dw, dh)
2.3、后处理函数
再编写后处理函数:postprocess
该代码的功能是对模型的输出结果进行后处理,主要用于从目标检测模型的输出中提取边界框(bounding boxes)、置信度分数和类别ID,并将这些检测结果绘制在输入图像上。
A、模型输出后处理
- 将模型的输出数据进行转置和压缩,使其符合处理的预期格式。
- 遍历模型的每一个检测结果,提取检测框的坐标(x, y, w, h)、类别得分,并通过阈值过滤掉低置信度的检测结果。
- 计算检测框在原始图像上的实际位置,考虑缩放和填充的影响。
B、缩放和填充调整
- 根据图像的缩放比例和填充量,将检测框的坐标从网络输入尺寸(如640x640)调整回原始图像尺寸。
C、非极大值抑制(NMS)
- 使用非极大值抑制(NMS)算法对检测结果进行过滤,删除重叠的检测框,仅保留最高置信度的框。
D、绘制检测结果
- 使用
draw_detections方法在输入图像上绘制边界框,并标注检测类别和置信度。 - 最终返回包含检测结果的图像,图像上绘制了所有有效的检测框和对应的标签。
def postprocess(self, input_image, output):"""对模型输出进行后处理,以提取边界框、分数和类别 ID。参数:input_image (numpy.ndarray): 输入图像。output (numpy.ndarray): 模型的输出。返回:numpy.ndarray: 包含检测结果的输入图像。"""# 转置并压缩输出,以匹配预期形状outputs = np.transpose(np.squeeze(output[0]))rows = outputs.shape[0]boxes, scores, class_ids = [], [], []# 计算缩放比例和填充ratio = self.img_width / self.input_width, self.img_height / self.input_heightfor i in range(rows):classes_scores = outputs[i][4:]max_score = np.amax(classes_scores)if max_score >= self.confidence_thres:class_id = np.argmax(classes_scores)x, y, w, h = outputs[i][0], outputs[i][1], outputs[i][2], outputs[i][3]# 将框调整到原始图像尺寸,考虑缩放和填充x -= self.dw # 移除填充y -= self.dhx /= self.ratio[0] # 缩放回原图y /= self.ratio[1]w /= self.ratio[0]h /= self.ratio[1]left = int(x - w / 2)top = int(y - h / 2)width = int(w)height = int(h)boxes.append([left, top, width, height])scores.append(max_score)class_ids.append(class_id)indices = cv2.dnn.NMSBoxes(boxes, scores, self.confidence_thres, self.iou_thres)for i in indices:box = boxes[i]score = scores[i]class_id = class_ids[i]self.draw_detections(input_image, box, score, class_id)return input_image
2.4、检测效果可视化函数
该代码的功能是根据检测结果在输入图像上绘制边界框和标签,以可视化目标检测的结果。
def draw_detections(self, img, box, score, class_id):"""在输入图像上绘制检测到的边界框和标签。参数:img: 用于绘制检测结果的输入图像。box: 检测到的边界框。score: 对应的检测分数。class_id: 检测到的目标类别 ID。返回:None"""# 提取边界框的坐标x1, y1, w, h = box# 获取类别对应的颜色color = self.color_palette[class_id]# 在图像上绘制边界框cv2.rectangle(img, (int(x1), int(y1)), (int(x1 + w), int(y1 + h)), color, 2)# 创建包含类别名和分数的标签文本label = f"{self.classes[class_id]}: {score:.2f}"# 计算标签文本的尺寸(label_width, label_height), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)# 计算标签文本的位置label_x = x1label_y = y1 - 10 if y1 - 10 > label_height else y1 + 10# 绘制填充的矩形作为标签文本的背景cv2.rectangle(img, (label_x, label_y - label_height), (label_x + label_width, label_y + label_height), color, cv2.FILLED)# 在图像上绘制标签文本cv2.putText(img, label, (label_x, label_y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv2.LINE_AA)
2.5、YOLO11目标检测——ONNX模型推理完整代码
完整代码,如下所示:
# Ultralytics YOLO 🚀, AGPL-3.0 licenseimport argparse
import cv2
import numpy as np
import onnxruntime as ort# 类外定义类别映射关系,使用字典格式
CLASS_NAMES = {0: 'class_name1', # 类别 0 名称1: 'class_name2', # 类别 1 名称2: 'class_name3' # 类别 1 名称# 可以添加更多类别...
}class YOLO11:"""YOLO11 目标检测模型类,用于处理推理和可视化。"""def __init__(self, onnx_model, input_image, confidence_thres, iou_thres):"""初始化 YOLO11 类的实例。参数:onnx_model: ONNX 模型的路径。input_image: 输入图像的路径。confidence_thres: 用于过滤检测结果的置信度阈值。iou_thres: 非极大值抑制(NMS)的 IoU(交并比)阈值。"""self.onnx_model = onnx_modelself.input_image = input_imageself.confidence_thres = confidence_thresself.iou_thres = iou_thres# 加载类别名称self.classes = CLASS_NAMES# 为每个类别生成一个颜色调色板self.color_palette = np.random.uniform(0, 255, size=(len(self.classes), 3))def preprocess(self):"""对输入图像进行预处理,以便进行推理。返回:image_data: 经过预处理的图像数据,准备进行推理。"""# 使用 OpenCV 读取输入图像self.img = cv2.imread(self.input_image)# 获取输入图像的高度和宽度self.img_height, self.img_width = self.img.shape[:2]# 将图像颜色空间从 BGR 转换为 RGBimg = cv2.cvtColor(self.img, cv2.COLOR_BGR2RGB)# 保持宽高比,进行 letterbox 填充, 使用模型要求的输入尺寸img, self.ratio, (self.dw, self.dh) = self.letterbox(img, new_shape=(self.input_width, self.input_height))# 通过除以 255.0 来归一化图像数据image_data = np.array(img) / 255.0# 将图像的通道维度移到第一维image_data = np.transpose(image_data, (2, 0, 1)) # 通道优先# 扩展图像数据的维度,以匹配模型输入的形状image_data = np.expand_dims(image_data, axis=0).astype(np.float32)# 返回预处理后的图像数据return image_datadef letterbox(self, img, new_shape=(640, 640), color=(114, 114, 114), auto=False, scaleFill=False, scaleup=True):"""将图像进行 letterbox 填充,保持纵横比不变,并缩放到指定尺寸。"""shape = img.shape[:2] # 当前图像的宽高print(f"Original image shape: {shape}")if isinstance(new_shape, int):new_shape = (new_shape, new_shape)# 计算缩放比例r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) # 选择宽高中最小的缩放比if not scaleup: # 仅缩小,不放大r = min(r, 1.0)# 缩放后的未填充尺寸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] # 计算填充的尺寸dw /= 2 # padding 均分dh /= 2# 缩放图像if shape[::-1] != new_unpad: # 如果当前图像尺寸不等于 new_unpad,则缩放img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR)# 为图像添加边框以达到目标尺寸top, bottom = int(round(dh)), int(round(dh))left, right = int(round(dw)), int(round(dw))img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)print(f"Final letterboxed image shape: {img.shape}")return img, (r, r), (dw, dh)def postprocess(self, input_image, output):"""对模型输出进行后处理,以提取边界框、分数和类别 ID。参数:input_image (numpy.ndarray): 输入图像。output (numpy.ndarray): 模型的输出。返回:numpy.ndarray: 包含检测结果的输入图像。"""# 转置并压缩输出,以匹配预期形状outputs = np.transpose(np.squeeze(output[0]))rows = outputs.shape[0]boxes, scores, class_ids = [], [], []# 计算缩放比例和填充ratio = self.img_width / self.input_width, self.img_height / self.input_heightfor i in range(rows):classes_scores = outputs[i][4:]max_score = np.amax(classes_scores)if max_score >= self.confidence_thres:class_id = np.argmax(classes_scores)x, y, w, h = outputs[i][0], outputs[i][1], outputs[i][2], outputs[i][3]# 将框调整到原始图像尺寸,考虑缩放和填充x -= self.dw # 移除填充y -= self.dhx /= self.ratio[0] # 缩放回原图y /= self.ratio[1]w /= self.ratio[0]h /= self.ratio[1]left = int(x - w / 2)top = int(y - h / 2)width = int(w)height = int(h)boxes.append([left, top, width, height])scores.append(max_score)class_ids.append(class_id)indices = cv2.dnn.NMSBoxes(boxes, scores, self.confidence_thres, self.iou_thres)for i in indices:box = boxes[i]score = scores[i]class_id = class_ids[i]self.draw_detections(input_image, box, score, class_id)return input_imagedef draw_detections(self, img, box, score, class_id):"""在输入图像上绘制检测到的边界框和标签。参数:img: 用于绘制检测结果的输入图像。box: 检测到的边界框。score: 对应的检测分数。class_id: 检测到的目标类别 ID。返回:None"""# 提取边界框的坐标x1, y1, w, h = box# 获取类别对应的颜色color = self.color_palette[class_id]# 在图像上绘制边界框cv2.rectangle(img, (int(x1), int(y1)), (int(x1 + w), int(y1 + h)), color, 2)# 创建包含类别名和分数的标签文本label = f"{self.classes[class_id]}: {score:.2f}"# 计算标签文本的尺寸(label_width, label_height), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)# 计算标签文本的位置label_x = x1label_y = y1 - 10 if y1 - 10 > label_height else y1 + 10# 绘制填充的矩形作为标签文本的背景cv2.rectangle(img, (label_x, label_y - label_height), (label_x + label_width, label_y + label_height), color, cv2.FILLED)# 在图像上绘制标签文本cv2.putText(img, label, (label_x, label_y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv2.LINE_AA)def main(self):# 使用 ONNX 模型创建推理会话,自动选择CPU或GPUsession = ort.InferenceSession(self.onnx_model, providers=["CUDAExecutionProvider", "CPUExecutionProvider"] if ort.get_device() == "GPU" else ["CPUExecutionProvider"],)# 打印模型的输入尺寸print("YOLO11 🚀 目标检测 ONNXRuntime")print("模型名称:", self.onnx_model)# 获取模型的输入形状model_inputs = session.get_inputs()input_shape = model_inputs[0].shape self.input_width = input_shape[2]self.input_height = input_shape[3]print(f"模型输入尺寸:宽度 = {self.input_width}, 高度 = {self.input_height}")# 预处理图像数据,确保使用模型要求的尺寸 (640x640)img_data = self.preprocess()# 使用预处理后的图像数据运行推理outputs = session.run(None, {model_inputs[0].name: img_data})# 对输出进行后处理以获取输出图像return self.postprocess(self.img, outputs) # 输出图像if __name__ == "__main__":# 创建参数解析器以处理命令行参数parser = argparse.ArgumentParser()parser.add_argument("--model", type=str, default="runs/detect/train/weights/best.onnx", help="输入你的 ONNX 模型路径。")parser.add_argument("--img", type=str, default=r"datasets/test.jpg", help="输入图像的路径。")parser.add_argument("--conf-thres", type=float, default=0.5, help="置信度阈值")parser.add_argument("--iou-thres", type=float, default=0.45, help="NMS IoU 阈值")args = parser.parse_args()# 使用指定的参数创建 YOLO11 类的实例detection = YOLO11(args.model, args.img, args.conf_thres, args.iou_thres)# 执行目标检测并获取输出图像output_image = detection.main()# 保存输出图像到文件cv2.imwrite("det_result_picture.jpg", output_image)print("图像已保存为 det_result_picture.jpg")
需要修改类别映射关系,以及类别对应的颜色
比如,定义两个类别(car、person), 示例代码:
# 类外定义类别映射关系,使用字典格式
CLASS_NAMES = {0: 'car', # 类别 0 名称1: 'person' # 类别 1 名称# 可以添加更多类别...
}
运行代码,打印信息:
YOLO11 🚀 目标检测 ONNXRuntime
模型名称: runs/detect/train/weights/best.onnx
模型输入尺寸:宽度 = 640, 高度 = 640
Original image shape: (398, 700)
Final letterboxed image shape: (640, 640, 3)
图像已保存为 det_result_picture.jpg
可视化看一下分割效果,保存名称是:det_result_picture.jpg
YOLO11相关文章推荐:
一篇文章快速认识YOLO11 | 关键改进点 | 安装使用 | 模型训练和推理-CSDN博客
一篇文章快速认识 YOLO11 | 实例分割 | 模型训练 | 自定义数据集-CSDN博客
YOLO11模型推理 | 目标检测与跟踪 | 实例分割 | 关键点估计 | OBB旋转目标检测-CSDN博客
YOLO11模型训练 | 目标检测与跟踪 | 实例分割 | 关键点姿态估计-CSDN博客
YOLO11 实例分割 | 自动标注 | 预标注 | 标签格式转换 | 手动校正标签-CSDN博客
YOLO11 实例分割 | 导出ONNX模型 | ONNX模型推理-CSDN博客
分享完成,欢迎大家多多点赞和收藏,谢谢~
相关文章:
YOLO11 目标检测 | 导出ONNX模型 | ONNX模型推理
本文分享YOLO11中,从xxx.pt权重文件转为.onnx文件,然后使用.onnx文件,进行目标检测任务的模型推理。 用ONNX模型推理,便于算法到开发板或芯片的部署。 备注:本文是使用Python,编写ONNX模型推理代码的 目…...
PostgreSQL DBA月度检查列表
为了确保数据库系统能够稳定高效运行,DBA 需要定期对数据库进行检查和维护,这是一项非常具有挑战性的工作。 本文给大家推荐一个 PostgreSQL DBA 月度性能检查列表,遵循以下指导原则可以帮助我们实现一个高可用、高性能、低成本、可扩展的数…...
驱动开发系列12 - Linux 编译内核模块的Makefile解释
一:内核模块Makefile #这一行定义了要编译的内核模块目标文件。obj-m表示目标模块对象文件(.o文件), #并指定了两个模块源文件:helloworld-params.c 和 helloworld.c。最终会生成这 #这两个.c文件的.o对象文件。 obj-m := helloworld-params.o helloworld.o#这行定义了内核…...
用js+css实现圆环型的进度条——js+css基础积累
如果用jscss实现圆环型的进度条: 直接上代码: <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><met…...
TDengine 与北微传感达成合作,解决传统数据库性能瓶颈
在当今物联网(IoT)快速发展的背景下,传感器技术已成为各个行业数字化转型的关键组成部分。随着设备数量的激增和数据生成速度的加快,如何高效地管理和分析这些数据,成为企业实现智能化运营的重要挑战。尤其是在惯性传感…...
通过Python爬虫获取商品销量数据,轻松掌握市场动态
为什么选择Python爬虫? 简洁易用:Python语言具有简洁的语法和丰富的库,使得编写爬虫变得简单高效。强大的库支持:Python拥有强大的爬虫框架(如Scrapy、BeautifulSoup、Requests等),可以快速实现…...
学习虚幻C++开发日志——TSet
TSet 官方文档:虚幻引擎中的Set容器 | 虚幻引擎 5.5 文档 | Epic Developer Community (epicgames.com) TSet 是通过对元素求值的可覆盖函数,使用数据值本身作为键,而不是将数据值与独立的键相关联。 默认情况下,TSet 不支持重…...
面向对象进阶(下)(JAVA笔记第二十二期)
p.s.这是萌新自己自学总结的笔记,如果想学习得更透彻的话还是请去看大佬的讲解 目录 抽象方法和抽象类抽象方法定义格式抽象类定义格式抽象方法和抽象类注意事项 接口接口的定义接口中成员变量的特点接口中没有构造方法接口中成员方法的特点在接口中定义具有方法体…...
通信协议——UART
目录 基础概念串行&并行串行的优缺点 单工&双工 UART基本概念时序图思考:接收方如何确定01和0011 基础概念 串行&并行 串行为8车道,并行为1车道 串行的优缺点 通行速度快浪费资源布线复杂线与线之间存在干扰 单工&双工 单工…...
最优阵列处理技术(七)-谱加权
阵列的加权技术等价于时间序列谱分析中的加窗或锐化技术。在加权过程中,需要考虑的是如何降低旁瓣并使主波束宽度的增长最小。 首先需要明确的是,在 u u u空间下的波束方向图为 B u ( u ) =...
Java | Leetcode Java题解之第486题预测赢家
题目: 题解: class Solution {public boolean PredictTheWinner(int[] nums) {int length nums.length;int[] dp new int[length];for (int i 0; i < length; i) {dp[i] nums[i];}for (int i length - 2; i > 0; i--) {for (int j i 1; j …...
leetcode动态规划(十五)-完全背包
题目 leetcode上没有纯完全背包题目,可以看卡码网上的题目 完全背包 思路 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次)ÿ…...
AI视听新体验!浙大阿里提出视频到音乐生成模型MuVi:可解决语义对齐和节奏同步问题
MuVi旨在解决视频到音乐生成(V2M)中的语义对齐和节奏同步问题。 MuVi通过专门设计的视觉适配器分析视频内容,以提取上下文 和时间相关的特征,这些特征用于生成与视频的情感、主题及其节奏和节拍相匹配的音乐。MuVi在音频质量和时间同步方面表现优于现有基线方法,并展示了其在风…...
对比两个el-table,差异数据突显标记
前言 在数据分析和数据处理的过程中,经常需要对比两个数据集,以便发现其中的差异和变化。本文将介绍如何使用 el-table 组件来对比两个数据集,并通过差异数据的突显标记,帮助用户更直观地理解数据的变化。 cell-style 属性 其实利…...
调研funasr时间戳返回时间坐标效果可用性
# 背景 : 分析funasr识别结果中每个中文字的时间戳偏差情况 1.评价指标: ①偏差公式: A=标注字的时间戳(帧长区间) B=识别字的时间戳(帧长区间) 偏差=(AB的区间并集-AB的区间交际) 偏差百分比=(AB的区间并集-AB的区间交际)/(A的帧长) def calculate_bias(la…...
Tomcat默认配置整理
Connector: 处理请求的具体配置 Tomcat的连接等待队列长度,默认是100 Tomcat的最大连接数,默认是8192 Tomcat的最小工作线程数,默认是10 Tomcat的最大线程数,默认是200 Tomcat的连接超时时间,默认是20s Server port…...
深入理解Rust中的指针:裸指针 智能指针
Rust是一种注重安全性的系统编程语言,它通过所有权、借用和生命周期等机制来保证内存安全。在Rust中,指针的使用是小心翼翼的,因为指针操作是导致内存错误的主要原因之一。然而,指针在处理底层数据和性能优化时又是必不可少的。本…...
物联网实训项目:绿色家居套件
1、基本介绍 绿色家居通过物联网技术将家中的各种设备连接到一起,提供家电控制、照明控制、电话远程控制、室内外遥控、防盗报警、环境监测、暖通控制、红外转发以及可编程定时控制等多种功能和手段。绿色家居提供全方位的信息交互功能,甚至为各种能源费…...
缓存雪崩是什么
背景 Redis的缓存雪崩是指在某一时间段内,大量缓存数据同时失效,导致大量请求直接打到数据库上,造成数据库压力激增,甚至可能导致数据库宕机。这种情况类似于雪崩效应,突然的大量请求涌入数据库,系统无法承…...
【格物刊】龙信刊物已上新
文章关键词:电子数据取证、电子物证、手机取证、介质取证 深藏注册表的秘密:一次揭开金融阴谋的成功取证 一场看似无懈可击的金融操作,背后是否隐藏着阴谋?执法部门接到举报,指控几名金融机构的高层管理人员涉嫌利用…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
