DAMO-YOLO代码实例:OpenCV-Python图像预处理与后处理结果渲染详解
DAMO-YOLO代码实例OpenCV-Python图像预处理与后处理结果渲染详解1. 引言从炫酷界面到核心引擎当你打开DAMO-YOLO的赛博朋克界面看到霓虹绿的识别框在图片上闪烁时有没有想过这背后发生了什么那个漂亮的界面只是冰山一角真正让系统工作的是一套严谨的图像处理流程。今天我们不谈界面设计也不讲模型架构就聚焦在一个核心问题上一张原始图片是怎么变成屏幕上那些带框的检测结果的这个过程就像一条生产线预处理把五花八门的图片标准化让模型能看懂推理模型识别目标这部分我们今天不深入后处理把模型的输出翻译成我们能理解的框和标签渲染把结果画到图片上展示给用户如果你正在学习目标检测或者想在自己的项目中集成DAMO-YOLO这篇文章就是为你准备的。我会用最直白的代码带你走完从原始图片到最终渲染的完整流程。2. 环境准备与核心工具在开始写代码之前我们先看看需要哪些工具。别担心都是很常见的东西。2.1 需要安装的库打开你的终端运行这几条命令# 安装核心库 pip install opencv-python pillow numpy torch # 如果你需要从ModelScope加载模型 pip install modelscope2.2 导入必要的模块创建一个Python文件比如叫damoyolo_pipeline.py然后在开头导入这些模块import cv2 # OpenCV图像处理的瑞士军刀 import numpy as np # 数值计算处理数组 from PIL import Image, ImageDraw, ImageFont # Pillow另一个图像处理库 import torch # PyTorch深度学习框架 import os import time为什么用两个图像库OpenCVcv2速度快适合预处理和渲染PillowPIL字体支持好适合画中文标签各取所长配合使用3. 图像预处理让模型看得懂图片模型就像个挑剔的食客只吃特定格式的食物。预处理就是把各种图片都做成它爱吃的标准餐。3.1 第一步读取图片不管用户上传的是JPG、PNG还是其他格式我们都要先读进来def read_image(image_path): 读取图片支持多种格式 # 方法1用OpenCV读取BGR格式 img_cv cv2.imread(image_path) if img_cv is None: # 方法2用PIL读取RGB格式 img_pil Image.open(image_path) img_cv cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR) return img_cv # 使用示例 original_img read_image(test.jpg) print(f图片尺寸{original_img.shape}) # 输出(高度, 宽度, 通道数)注意OpenCV默认用BGR格式蓝绿红而大多数模型需要RGB格式红绿蓝。这个转换很重要3.2 第二步调整尺寸ResizeDAMO-YOLO模型有固定的输入尺寸比如640x640。我们需要把图片缩放到这个尺寸def resize_image(img, target_size640): 把图片缩放到目标尺寸保持宽高比 h, w img.shape[:2] # 获取原始高度和宽度 # 计算缩放比例 scale min(target_size / h, target_size / w) # 计算新的尺寸 new_h, new_w int(h * scale), int(w * scale) # 缩放图片 resized_img cv2.resize(img, (new_w, new_h), interpolationcv2.INTER_LINEAR) # 创建目标尺寸的画布灰色背景 canvas np.full((target_size, target_size, 3), 114, dtypenp.uint8) # 把缩放后的图片放到画布左上角 canvas[:new_h, :new_w] resized_img return canvas, scale, (new_w, new_h) # 使用示例 resized_img, scale, (new_w, new_h) resize_image(original_img, 640) print(f缩放比例{scale:.3f}新尺寸{new_w}x{new_h})为什么要保持宽高比如果直接拉伸图片会变形。保持宽高比缩放然后在周围填充灰色这样图片内容不会失真。3.3 第三步格式转换与归一化模型需要的是特定格式的数据def prepare_for_model(img): 准备模型输入数据 # 1. BGR转RGB img_rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 2. 调整维度顺序HWC - CHW (高度宽度通道 - 通道高度宽度) img_chw img_rgb.transpose(2, 0, 1) # 3. 添加批次维度CHW - BCHW img_batch np.expand_dims(img_chw, axis0) # 4. 转换为浮点数并归一化0-255 - 0-1 img_float img_batch.astype(np.float32) / 255.0 # 5. 转换为PyTorch张量 img_tensor torch.from_numpy(img_float) return img_tensor # 使用示例 model_input prepare_for_model(resized_img) print(f模型输入形状{model_input.shape}) # 应该是 torch.Size([1, 3, 640, 640])归一化为什么重要图片像素值原来是0-255的整数归一化到0-1之间可以让模型训练更稳定收敛更快。4. 模型推理与后处理预处理完成后图片就可以喂给模型了。模型会输出一堆原始数据我们需要把这些数据翻译成我们能理解的结果。4.1 加载DAMO-YOLO模型这里有两种方式加载模型def load_damoyolo_model(model_pathNone): 加载DAMO-YOLO模型 if model_path and os.path.exists(model_path): # 方式1从本地文件加载 model torch.load(model_path, map_locationcpu) else: # 方式2从ModelScope加载需要安装modelscope try: from modelscope.pipelines import pipeline from modelscope.utils.constant import Tasks # 创建目标检测pipeline damoyolo_pipeline pipeline( Tasks.domain_specific_object_detection, modeldamo/cv_tinynas_object-detection_damoyolo ) model damoyolo_pipeline.model except ImportError: print(请安装modelscopepip install modelscope) return None # 设置为评估模式 model.eval() return model # 使用示例 model load_damoyolo_model() if model is not None: print(模型加载成功)4.2 执行推理有了模型和预处理好的数据就可以进行推理了def run_inference(model, input_tensor): 运行模型推理 # 确保没有梯度计算推理阶段不需要 with torch.no_grad(): # 前向传播 outputs model(input_tensor) return outputs # 使用示例 if model is not None: raw_outputs run_inference(model, model_input) print(f原始输出类型{type(raw_outputs)})4.3 后处理从原始输出到检测框这是最关键的一步模型的原始输出是一堆数字我们需要提取出有用的信息def process_detections(raw_outputs, confidence_threshold0.5, iou_threshold0.5): 处理模型输出提取检测框 # 这里简化处理实际DAMO-YOLO的输出格式可能不同 # 通常包含边界框坐标、置信度、类别 detections [] # 假设raw_outputs是一个列表每个元素对应一个检测 for detection in raw_outputs[0]: # 取第一个批次 # detection格式可能是[x1, y1, x2, y2, confidence, class_id] if len(detection) 6: x1, y1, x2, y2, conf, cls_id detection[:6] # 过滤低置信度的检测 if conf confidence_threshold: detections.append({ bbox: [float(x1), float(y1), float(x2), float(y2)], confidence: float(conf), class_id: int(cls_id) }) # 非极大值抑制NMS去除重叠框 if detections: detections apply_nms(detections, iou_threshold) return detections def apply_nms(detections, iou_threshold): 非极大值抑制去除重叠的检测框 if not detections: return [] # 按置信度排序 detections.sort(keylambda x: x[confidence], reverseTrue) keep [] while detections: # 取置信度最高的 best detections.pop(0) keep.append(best) # 计算与剩余框的IoU交并比 to_remove [] for i, det in enumerate(detections): iou calculate_iou(best[bbox], det[bbox]) if iou iou_threshold: to_remove.append(i) # 移除重叠框 for idx in reversed(to_remove): detections.pop(idx) return keep def calculate_iou(box1, box2): 计算两个框的交并比 x1_min, y1_min, x1_max, y1_max box1 x2_min, y2_min, x2_max, y2_max box2 # 计算交集区域 inter_xmin max(x1_min, x2_min) inter_ymin max(y1_min, y2_min) inter_xmax min(x1_max, x2_max) inter_ymax min(y1_max, y2_max) # 检查是否有交集 if inter_xmax inter_xmin or inter_ymax inter_ymin: return 0.0 # 计算交集面积 inter_area (inter_xmax - inter_xmin) * (inter_ymax - inter_ymin) # 计算各自面积 area1 (x1_max - x1_min) * (y1_max - y1_min) area2 (x2_max - x2_min) * (y2_max - y2_min) # 计算并集面积 union_area area1 area2 - inter_area # 计算IoU iou inter_area / union_area if union_area 0 else 0.0 return iou # 使用示例这里用模拟数据演示 # 实际使用时raw_outputs来自模型输出 simulated_output [[ [100, 100, 200, 200, 0.9, 0], # 人高置信度 [110, 110, 210, 210, 0.8, 0], # 人与第一个重叠 [300, 300, 400, 400, 0.7, 2], # 车不重叠 ]] detections process_detections(simulated_output, confidence_threshold0.5) print(f检测到 {len(detections)} 个目标) for i, det in enumerate(detections): print(f 目标{i1}: 类别{det[class_id]}, 置信度{det[confidence]:.2f})NMS为什么重要同一个目标可能被检测出多个框NMS只保留最好的那个让结果更干净。5. 结果渲染把框画到图片上检测结果出来了现在要把它们可视化。这就是DAMO-YOLO界面上那些霓虹绿框的由来。5.1 坐标转换从模型空间到原始图片空间还记得预处理时的缩放吗现在要反向操作def convert_coordinates(detections, scale, padding, original_size): 将检测框坐标转换回原始图片尺寸 original_h, original_w original_size for det in detections: x1, y1, x2, y2 det[bbox] # 1. 去除填充如果有 # 2. 除以缩放比例 # 3. 确保不超出原始图片边界 x1 max(0, min(original_w, x1 / scale)) y1 max(0, min(original_h, y1 / scale)) x2 max(0, min(original_w, x2 / scale)) y2 max(0, min(original_h, y2 / scale)) det[bbox_original] [x1, y1, x2, y2] return detections # 使用示例 original_size original_img.shape[:2] # (高度, 宽度) detections convert_coordinates(detections, scale, (0, 0), original_size)5.2 绘制检测框和标签现在是视觉效果的部分def draw_detections(image, detections, class_namesNone): 在图片上绘制检测结果 # 创建副本避免修改原图 img_with_boxes image.copy() # 如果没有类别名称使用默认的 if class_names is None: class_names [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] # DAMO-YOLO的霓虹绿颜色 neon_green (0, 255, 127) # BGR格式 for det in detections: x1, y1, x2, y2 [int(coord) for coord in det[bbox_original]] conf det[confidence] cls_id det[class_id] # 确保坐标有效 if x2 x1 or y2 y1: continue # 1. 绘制边界框 box_thickness 2 cv2.rectangle(img_with_boxes, (x1, y1), (x2, y2), neon_green, box_thickness) # 2. 准备标签文本 class_name class_names[cls_id] if cls_id len(class_names) else fclass_{cls_id} label f{class_name} {conf:.2f} # 3. 计算标签背景大小 font cv2.FONT_HERSHEY_SIMPLEX font_scale 0.5 font_thickness 1 (label_width, label_height), baseline cv2.getTextSize( label, font, font_scale, font_thickness ) # 4. 绘制标签背景 label_bg_top_left (x1, y1 - label_height - 5) label_bg_bottom_right (x1 label_width, y1) cv2.rectangle( img_with_boxes, label_bg_top_left, label_bg_bottom_right, neon_green, -1 # 填充矩形 ) # 5. 绘制标签文字 label_position (x1, y1 - 5) cv2.putText( img_with_boxes, label, label_position, font, font_scale, (0, 0, 0), # 黑色文字 font_thickness, cv2.LINE_AA ) return img_with_boxes # 使用示例 result_image draw_detections(original_img, detections) # 保存结果 cv2.imwrite(result_with_boxes.jpg, result_image) print(结果已保存到 result_with_boxes.jpg)5.3 添加中文标签支持如果你需要显示中文标签Pillow比OpenCV更方便def draw_detections_chinese(image, detections, class_names_chinese): 使用Pillow绘制中文标签 # 转换OpenCV图片到Pillow格式 img_rgb cv2.cvtColor(image, cv2.COLOR_BGR2RGB) img_pil Image.fromarray(img_rgb) draw ImageDraw.Draw(img_pil) # 加载中文字体需要系统有中文字体 try: font ImageFont.truetype(msyh.ttc, 14) # 微软雅黑 except: font ImageFont.load_default() neon_green_rgb (0, 255, 127) # RGB格式 for det in detections: x1, y1, x2, y2 [int(coord) for coord in det[bbox_original]] conf det[confidence] cls_id det[class_id] # 绘制边界框 draw.rectangle([x1, y1, x2, y2], outlineneon_green_rgb, width2) # 准备中文标签 if cls_id len(class_names_chinese): class_name class_names_chinese[cls_id] else: class_name f类别{cls_id} label f{class_name} {conf:.2f} # 绘制标签背景和文字 bbox draw.textbbox((x1, y1), label, fontfont) draw.rectangle(bbox, fillneon_green_rgb) draw.text((x1, y1), label, fill(0, 0, 0), fontfont) # 转换回OpenCV格式 result cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR) return result # 中文类别名称示例前20个 chinese_names [ 人, 自行车, 汽车, 摩托车, 飞机, 公交车, 火车, 卡车, 船, 交通灯, 消防栓, 停止标志, 停车计时器, 长椅, 鸟, 猫, 狗, 马, 羊, 牛 ] # 使用示例 result_chinese draw_detections_chinese(original_img, detections, chinese_names) cv2.imwrite(result_chinese.jpg, result_chinese)6. 完整流程整合现在我们把所有步骤整合成一个完整的函数def damoyolo_full_pipeline(image_path, confidence_threshold0.5): DAMO-YOLO完整处理流程 print( * 50) print(开始DAMO-YOLO处理流程) print( * 50) # 记录开始时间 start_time time.time() # 1. 读取图片 print(1. 读取图片...) original_img read_image(image_path) print(f 原始尺寸{original_img.shape[1]}x{original_img.shape[0]}) # 2. 预处理 print(2. 预处理图片...) resized_img, scale, new_size resize_image(original_img, 640) model_input prepare_for_model(resized_img) print(f 缩放比例{scale:.3f}) # 3. 加载模型这里简化实际应该提前加载 print(3. 准备模型...) # 注意实际使用中模型应该提前加载避免每次推理都加载 # 4. 推理这里用模拟数据 print(4. 执行推理...) # 实际应该调用raw_outputs run_inference(model, model_input) # 这里用模拟数据演示 simulated_output [[ [100, 100, 200, 200, 0.92, 0], [300, 300, 400, 400, 0.87, 2], [150, 150, 250, 250, 0.45, 0], # 低置信度会被过滤 ]] # 5. 后处理 print(5. 后处理...) detections process_detections(simulated_output, confidence_threshold) print(f 检测到 {len(detections)} 个目标) # 6. 坐标转换 print(6. 坐标转换...) original_size original_img.shape[:2] detections convert_coordinates(detections, scale, (0, 0), original_size) # 7. 渲染结果 print(7. 渲染结果...) result_img draw_detections(original_img, detections) # 8. 保存结果 output_path final_result.jpg cv2.imwrite(output_path, result_img) # 计算总耗时 total_time time.time() - start_time print(f\n✅ 处理完成) print(f 总耗时{total_time:.2f}秒) print(f 结果保存到{output_path}) # 显示检测结果详情 print(\n检测结果详情) for i, det in enumerate(detections): x1, y1, x2, y2 [int(coord) for coord in det[bbox_original]] print(f 目标{i1}: 位置({x1},{y1})-({x2},{y2}), f类别{det[class_id]}, 置信度{det[confidence]:.2f}) return result_img, detections # 运行完整流程 result, detections damoyolo_full_pipeline(test.jpg, confidence_threshold0.5)7. 总结通过这篇文章我们完整走了一遍DAMO-YOLO的图像处理流程。从读取图片到最终渲染每个步骤都有具体的代码实现。7.1 关键要点回顾预处理是基础模型对输入格式很挑剔正确的预处理直接影响检测效果后处理决定质量NMS和置信度过滤让结果更干净、更准确坐标转换要精确模型输出的是缩放后的坐标要正确转换回原始尺寸渲染可以个性化框的颜色、标签的样式都可以按需定制7.2 实际应用建议如果你要在自己的项目中使用DAMO-YOLO批量处理优化上面的代码是单张图片处理实际应用中可以考虑批量处理提高效率异步处理对于Web应用预处理、推理、后处理可以放在不同的线程或进程中缓存模型模型加载比较耗时应该只加载一次然后重复使用错误处理添加适当的异常处理比如图片读取失败、模型加载失败等情况7.3 进一步学习方向了解不同的NMS变体Soft-NMS、DIoU-NMS等可能在某些场景下效果更好学习模型量化把模型从FP32量化到INT8可以大幅提升推理速度探索多尺度检测有些目标检测模型支持多尺度输入可以检测不同大小的目标研究自定义训练用你自己的数据训练DAMO-YOLO检测特定类型的物体目标检测是一个既有深度又有广度的领域DAMO-YOLO提供了一个很好的起点。从理解预处理和后处理开始逐步深入你就能掌握这个强大的工具。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2491267.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!