当前位置: 首页 > news >正文

rknn yolo系列之量化前预处理,解决量化精度低以及出现类似未作nms的很多框子的问题

rknn官方代码在处理onnx量化到rknn模型时并未提供脚本进行图像缩放,如果直接简单的将图片路径写入txt文件,然后进行量化输出的话就会导致输出的rknn模型文件推理精度低,或者没有精度的情况。
因此,参考

https://github.com/airockchip/rknn-toolkit2/blob/77b71094e08391c543d9c65fea5f7cf98cc16eee/rknpu2/examples/rknn_yolov5_demo/src/preprocess.cc#L17

里面的:

void letterbox(const cv::Mat &image, cv::Mat &padded_image, BOX_RECT &pads, const float scale, const cv::Size &target_size, const cv::Scalar &pad_color)
{// 调整图像大小cv::Mat resized_image;cv::resize(image, resized_image, cv::Size(), scale, scale);// 计算填充大小int pad_width = target_size.width - resized_image.cols;int pad_height = target_size.height - resized_image.rows;pads.left = pad_width / 2;pads.right = pad_width - pads.left;pads.top = pad_height / 2;pads.bottom = pad_height - pads.top;// 在图像周围添加填充cv::copyMakeBorder(resized_image, padded_image, pads.top, pads.bottom, pads.left, pads.right, cv::BORDER_CONSTANT, pad_color);
}

我改写了一版图像量化预处理的脚本。使用这个脚本执行完毕,会生成一个txt文件,然后把它复制到test.py里面进行替换就可以了。test.py见:

https://github.com/airockchip/rknn-toolkit2/blob/master/rknn-toolkit2/examples/onnx/yolov5/test.py

在这篇博客中,将展示如何使用Python和OpenCV实现图像调整和填充,并将处理后的图像保存到指定目录中。同时,我们将介绍如何使用shutil模块来清理目录内容。

环境准备

在开始之前,确保你已经安装了所需的Python库。你可以使用以下命令进行安装:

pip install opencv-python tqdm numpy

以下是实现图像调整、填充并保存结果的完整代码:

import os
import cv2
import numpy as np
from tqdm import tqdm
import shutilclass BOX_RECT:def __init__(self):self.left = 0self.right = 0self.top = 0self.bottom = 0def letterbox(image, target_size, pad_color=(114, 114, 114)):# 调整图像大小以适应目标尺寸的比例h, w = image.shape[:2]scale = min(target_size[0] / h, target_size[1] / w)new_w, new_h = int(scale * w), int(scale * h)resized_image = cv2.resize(image, (new_w, new_h))# 计算填充大小pad_width = target_size[1] - new_wpad_height = target_size[0] - new_hpads = BOX_RECT()pads.left = pad_width // 2pads.right = pad_width - pads.leftpads.top = pad_height // 2pads.bottom = pad_height - pads.top# 在图像周围添加填充padded_image = cv2.copyMakeBorder(resized_image, pads.top, pads.bottom, pads.left, pads.right, cv2.BORDER_CONSTANT, value=pad_color)return padded_image, pads, scale# 图像路径
images_path = "./train/images"
images_list = os.listdir(images_path)
cali_num = len(images_list)
jump_num = int(len(images_list) / cali_num)
cali_list = images_list[0::jump_num][0:cali_num]input_w = 320
input_h = input_w
target_size = (input_w, input_h)
pad_color = (0, 0, 0)save_txt = "dataset.txt"
save_path = "./calib"
absolute_save_path = os.path.abspath(save_path)# 如果保存路径存在则清空,不存在则创建
if os.path.exists(absolute_save_path):# 使用shutil来删除目录内容for filename in os.listdir(absolute_save_path):file_path = os.path.join(absolute_save_path, filename)try:if os.path.isfile(file_path) or os.path.islink(file_path):os.unlink(file_path)elif os.path.isdir(file_path):shutil.rmtree(file_path)except Exception as e:print(f'Failed to delete {file_path}. Reason: {e}')
else:os.makedirs(absolute_save_path)count = 0
with open(save_txt, "w") as f:for img in tqdm(cali_list):count += 1img_abs_path = os.path.join(images_path, img)img_suffix = os.path.splitext(img_abs_path)[-1]img_ndarry = cv2.imread(img_abs_path)processed_img, pads, scale = letterbox(img_ndarry, target_size, pad_color)cv2.imwrite(os.path.join(absolute_save_path, str(count) + img_suffix), processed_img)img_save_abs_path = os.path.join(absolute_save_path, str(count) + img_suffix)f.write(img_save_abs_path + "\n")

代码解释

1. 引入所需库

import os
import cv2
import numpy as np
from tqdm import tqdm
import shutil

我们使用了OpenCV进行图像处理,tqdm用于显示进度条,numpy用于数值计算,shutil用于文件操作。

2. 定义BOX_RECT类

	class BOX_RECT:def __init__(self):self.left = 0self.right = 0self.top = 0self.bottom = 0

BOX_RECT类用于存储图像填充的尺寸。

3. 定义letterbox函数

	def letterbox(image, target_size, pad_color=(114, 114, 114)):h, w = image.shape[:2]scale = min(target_size[0] / h, target_size[1] / w)new_w, new_h = int(scale * w), int(scale * h)resized_image = cv2.resize(image, (new_w, new_h))pad_width = target_size[1] - new_wpad_height = target_size[0] - new_hpads = BOX_RECT()pads.left = pad_width // 2pads.right = pad_width - pads.leftpads.top = pad_height // 2pads.bottom = pad_height - pads.toppadded_image = cv2.copyMakeBorder(resized_image, pads.top, pads.bottom, pads.left, pads.right, cv2.BORDER_CONSTANT, value=pad_color)return padded_image, pads, scale

letterbox函数用于调整图像大小,并在图像周围添加填充,使其符合目标尺寸。

4. 设置路径和参数

	images_path = "/media/lindsay/data/rockchip_algorithem/algo/zaozi/train/images"images_list = os.listdir(images_path)cali_num = len(images_list)jump_num = int(len(images_list) / cali_num)cali_list = images_list[0::jump_num][0:cali_num]input_w = 320input_h = input_wtarget_size = (input_w, input_h)pad_color = (0, 0, 0)save_txt = "datasettxt"save_path = "./calib"absolute_save_path = os.path.abspath(save_path)

我们定义了图像路径、目标尺寸和填充颜色,并确定了保存路径。

5. 清理或创建保存目录

	if os.path.exists(absolute_save_path):for filename in os.listdir(absolute_save_path):file_path = os.path.join(absolute_save_path, filename)try:if os.path.isfile(file_path) or os.path.islink(file_path):os.unlink(file_path)elif os.path.isdir(file_path):shutil.rmtree(file_path)except Exception as e:print(f'Failed to delete {file_path}. Reason: {e}')else:os.makedirs(absolute_save_path)

如果保存目录存在,则清空目录内容,否则创建目录。

6. 处理图像并保存

	count = 0with open(save_txt, "w") as f:for img in tqdm(cali_list):count += 1img_abs_path = os.path.join(images_path, img)img_suffix = os.path.splitext(img_abs_path)[-1]img_ndarry = cv2.imread(img_abs_path)processed_img, pads, scale = letterbox(img_ndarry, target_size, pad_color)cv2.imwrite(os.path.join(absolute_save_path, str(count) + img_suffix), processed_img)img_save_abs_path = os.path.join(absolute_save_path, str(count) + img_suffix)f.write(img_save_abs_path + "\n")

我们遍历图像列表,调整图像大小并填充,最后将处理后的图像保存到指定目录,并将路径写入文本文件。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 在js中实现两个对象合并,若重复以第一个对象中的数据为准
  • 【机器学习】卷积神经网络简介
  • Android控件(示例)
  • 生成iOS LaunchImage脚本
  • “服务之巅:Spring Cloud中SLA监控与管理的艺术“
  • 【JavaEE】初步认识多线程
  • 【论文泛读】ZKML: An Optimizing System for ML Inference in Zero-Knowledge Proofs
  • springboot自定义starter
  • 【漏洞复现】某赛通数据泄露防护(DLP)系统 NetSecConfigAjax SQL注入漏洞
  • docker docker-compose创建容器并运行时发现redis.conf: Is a directory
  • springboot+neo4j的demo
  • 【论文分享】基于非参数方法和无所不在的兴趣点数据的子中心识别——以284个中国
  • tianai-captcha SpringBoot 行为验证码 支持滑动、旋转、文字点选等
  • 线程池概述
  • 在 FastAPI 项目中使用 Python 注解类型实现通用返回结构
  • $translatePartialLoader加载失败及解决方式
  • 【5+】跨webview多页面 触发事件(二)
  • 【腾讯Bugly干货分享】从0到1打造直播 App
  • 【跃迁之路】【585天】程序员高效学习方法论探索系列(实验阶段342-2018.09.13)...
  • 002-读书笔记-JavaScript高级程序设计 在HTML中使用JavaScript
  • github指令
  • Git学习与使用心得(1)—— 初始化
  • Hexo+码云+git快速搭建免费的静态Blog
  • HTTP那些事
  • Javascripit类型转换比较那点事儿,双等号(==)
  • jdbc就是这么简单
  • Js基础知识(四) - js运行原理与机制
  • miaov-React 最佳入门
  • pdf文件如何在线转换为jpg图片
  • Vue源码解析(二)Vue的双向绑定讲解及实现
  • 从重复到重用
  • 构造函数(constructor)与原型链(prototype)关系
  • 快速体验 Sentinel 集群限流功能,只需简单几步
  • 如何设计一个微型分布式架构?
  • 微信开源mars源码分析1—上层samples分析
  • 微信小程序--------语音识别(前端自己也能玩)
  • 我的面试准备过程--容器(更新中)
  • 详解NodeJs流之一
  • 自动记录MySQL慢查询快照脚本
  • 关于Kubernetes Dashboard漏洞CVE-2018-18264的修复公告
  • 摩拜创始人胡玮炜也彻底离开了,共享单车行业还有未来吗? ...
  • ​iOS安全加固方法及实现
  • ​secrets --- 生成管理密码的安全随机数​
  • #php的pecl工具#
  • #进阶:轻量级ORM框架Dapper的使用教程与原理详解
  • (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (9)STL算法之逆转旋转
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第2节(共同的基类)
  • (env: Windows,mp,1.06.2308310; lib: 3.2.4) uniapp微信小程序
  • (js)循环条件满足时终止循环
  • (JS基础)String 类型
  • (rabbitmq的高级特性)消息可靠性
  • (二)正点原子I.MX6ULL u-boot移植
  • (附源码)计算机毕业设计SSM在线影视购票系统
  • (十八)Flink CEP 详解