• 计算机图形学与计算几何经典必备书单整理,下载链接可参考:https://www.stubbornhuang.com/1256/

  • 本站由于前段时间遭受到大量临时和国外邮箱注册,所以对可注册的邮箱类型进行了限制!

  • 本站会放置Google广告用于维持域名以及网站服务器费用。

  • 感谢大家访问本站,希望本站的内容可以帮助到大家!

  • 在本站开通年度VIP,无限制下载本站资源和阅读本站文章

  • 问题反馈可发送邮件到stubbornhuang@qq.com

  • 欢迎大家交换友链,可在https://www.stubbornhuang.com/申请友情链接进行友链交换申请!

  • 工资「喂饱肚子」,副业「养活灵魂」!

  • 如果觉得本站的内容有帮助,可以考虑打赏博主哦!

C++ – Yolo的letterbox图片预处理方法,缩放图片不失真

C++ 发布于2023-07-17 阅读 5,239次 0次评论 1次点赞 本文共2506个字,阅读需要7分钟。

1 letter box预处理方法

yolo家族的一系列目标检测模型或者其他与视觉相关的深度学习模型的部署过程中,一般来说,如果导出的是静态shape的模型,那么我们先要将输入的图片resize到给定的图片大小,如果使用常规的resize方法,比如将一张1920x1080的图片resize到640x640的大小,那么resize后的图片必然是无法保持纵横比从而导致图片出现失真的现象,而模型在处理这种失真的图片时会造成模型准确度下降的问题。

现在主流是使用一种letter box的图片预处理方法,该方法在resize图片到目标大小的同时,又可以不造成图片失真并且不影响模型的推理精度。

比如下面是一张1920x1080的图片

C++ - Yolo的letterbox图片预处理方法,缩放图片不失真-第0张图片

通过letter box方法resize到640x640,resize后的图片如下

C++ - Yolo的letterbox图片预处理方法,缩放图片不失真-第1张图片

其做法非常易懂,先根据比例保持纵横比缩放图片,然后再对需要padding的维度进行padding,其C++实现代码如下

#include <iostream>
#include "opencv2/opencv.hpp"

static float LetterBoxImage(
    const cv::Mat& image,
    cv::Mat& out_image,
    const cv::Size& new_shape = cv::Size(640, 640),
    const cv::Scalar& color = cv::Scalar(114, 114, 114)
)
{
    cv::Size shape = image.size();
    float r = std::min((float)new_shape.height / (float)shape.height, (float)new_shape.width / (float)shape.width);

    int newUnpad[2]{(int)std::round((float)shape.width * r), (int)std::round((float)shape.height * r) };

    cv::Mat tmp;
    if (shape.width != newUnpad[0] || shape.height != newUnpad[1]) {
        cv::resize(image, tmp, cv::Size(newUnpad[0], newUnpad[1]));
    }
    else {
        tmp = image.clone();
    }

    float dw = new_shape.width - newUnpad[0];
    float dh = new_shape.height - newUnpad[1];

    dw /= 2.0f;
    dh /= 2.0f;

    int top = int(std::round(dh - 0.1f));
    int bottom = int(std::round(dh + 0.1f));
    int left = int(std::round(dw - 0.1f));
    int right = int(std::round(dw + 0.1f));

    cv::copyMakeBorder(tmp, out_image, top, bottom, left, right, cv::BORDER_CONSTANT, color);

    return 1.0f / r;
}

int main()
{
    std::string image_path = "C:\\Users\\HuangWang\\Desktop\\do1.mp4_20230704_102040.312.jpg";
    cv::Mat input_image = cv::imread(image_path);

    cv::Mat out_image;
    float scale = LetterBoxImage(input_image, out_image, cv::Size(640, 640), cv::Scalar(128, 128, 128));

    cv::imwrite("./out.jpg", out_image);
}

我的博文Python – 使用letter box方法缩放图片,防止图片缩放时失真中也实现了Python版本的letter box方法,有兴趣的可以看看。

在我们将输入图片通过letterbox方法进行resize后,并将resize的图片输入到模型中进行推理,预测的结果是基于resize的图片的,那么如何还原到最初的原始图片上呢?

这个也很简单,上述代码中的LetterBoxImage函数会返回一个图片的缩放因子,我们可以通过这个缩放因子计算x和y方向的offset,如下

int x_offset = (input_w * scale - image.cols) / 2;
int y_offset = (input_h * scale - image.rows) / 2;

上面的input_winput_h为resize图片的宽和高,image.colsimage.rows为原始图片的宽和高,scale为LetterBoxImage函数返回的缩放因子。在得到了scalex_offsety_offset之后我们可以将resize图片上的结果还原到原始图片上,这里以yolo的检测框结果为例,

Detection& detection = result.back();
detection.box.x = detection_boxes[4 * i] * scale - x_offset;
detection.box.y = detection_boxes[4 * i + 1] * scale - y_offset;
detection.box.width = detection_boxes[4 * i + 2] * scale - x_offset - detection.box.x;
detection.box.height = detection_boxes[4 * i + 3] * scale - y_offset - detection.box.y;

就是将基于resize图片的结果先乘以缩放因子scale,然后在分别减去offset即可

参考链接

欢迎扫码关注我的微信公众号,及时获取文章更新

微信公众号二维码

本文作者:StubbornHuang

版权声明:本文为站长原创文章,如果转载请注明原文链接!

原文标题:C++ – Yolo的letterbox图片预处理方法,缩放图片不失真

原文链接:https://www.stubbornhuang.com/2728/

发布于:2023年07月17日 16:27:00

修改于:2023年07月17日 17:40:39

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

文章末尾
上一篇
WordPress - 网站加载自定义字体的最佳方式
WordPress
下一篇
WordPress - 网站性能优化,设置浏览器缓存静态资源
WordPress
当前分类随机文章推荐

发表评论

您必须 [ 登录 ] 才能发表留言!

关注我们的公众号

微信公众号