【CV项目源码实现】darknet yolov3输入图片预处理及将预测框bbox还原至原图
前言
Yolov3网络的输入默认为416x416,然后待检测的图片不总是416x416,这就产生了如何将待检测图片,在不破坏特征的情况下缩放至416x416,并对应在网络产生预测框后,如何将416x416图中的预测框还原至原图的问题。
预处理过程letterbox_image
letterbox_image是按照原图横纵比不变进行缩放后的图像;
采用保持比例的图像缩放,代替传统的resize方式,对图像加以灰色背景,补全较目标比例相差的边缘部分;
step1. 求取缩放比例,将目标416x416,除以输入图像尺寸(width,height),取其中较小的一个比例,将长宽同时按此比例进行缩放。由于是长宽等比缩放,所以图片的特征并不失真。 step2. 制作rgb为(128,128,128),大小为416*416的底色图片。 step3. 将两张图片的中心对齐,将缩放后的图片粘贴到底色图上。
pytorch code

import os.path from typing import Iterator import numpy as np import torch import cv2 import matplotlib.pyplot as plt from PIL import Image from torch.utils.data import Dataset, DataLoader, Subset, random_split import re from functools import reduce from torch.utils.tensorboard import SummaryWriter as Writer from torchvision import transforms, datasets import torchvision as tv from torch import nn import torch.nn.functional as F import time import math def letterbox_image(image, size): ''' 保持比例的图像缩放用:代替了传统的resize方式 对图片加以灰色背景,补全较目标比例相差的边缘部分。 该函数只能处理单张图片 :param image: 原始图片 :param size: 目标图像宽高的元组 :return: 缩放到size后的目标图像 ''' iw, ih = image.size w, h = size scale = min(w / iw, h / ih) nw = int(iw * scale) nh = int(ih * scale) #此时为按比例缩放,为torch提供的函数 image = image.resize((nw, nh), Image.BICUBIC) #构建新的RGB背景图片 new_image = Image.new('RGB', size, (128, 128, 128)) #缩放后的图片粘贴至背景图片上 '''参数可选4元组及2元组,如果选择2元组,则为新图片相当于背景图片的左上角坐标''' new_image.paste(image, ((w - nw) // 2, (h - nh) // 2)) return new_image
预测框还原到原图
step1. 输入图像在网络size的letterbox中的尺寸;
step2. 网络输出的bbox是相对于net size的比值,计算bbox相对于letterbox size中的offset;
step3. 计算letterbox中的相对坐标;
经坐标换算,得到的坐标还是在输入网络的图片net size坐标系下的绝对坐标,但是此时已经是相对于new size这个区域的坐标了,而不再相对于(0,0)原点。这样保证bbox不会扭曲;
所以,预测之后的bbox是高宽比不变的letterbox image的比值,对于输入图像,只需要scale计算即可;
darknet code(src/yolo_layer.c)

void correct_yolo_boxes(detection *dets, int n, int w, int h, int netw, int neth, int relative) { int i; // 此处new_w表示输入图片经压缩后在网络输入大小的letter_box中的width,new_h表示在letter_box中的height, // 以1280*720的输入图片为例,在进行letter_box的过程中,原图经resize后的width为416, 那么resize后的对应height为720*416/1280, //所以height为234,而超过234的上下空余部分在作为网络输入之前填充了128,new_h=234 int new_w=0; int new_h=0; // 如果w>h说明resize的时候是以width/图像的width为resize比例的,先得到中间图的width,再根据比例得到height if (((float)netw/w) < ((float)neth/h)) { new_w = netw; new_h = (h * netw)/w; } else { new_h = neth; new_w = (w * neth)/h; } for (i = 0; i < n; ++i){ box b = dets[i].bbox; // 此处的公式很不好理解还是接着上面的例子,现有new_w=416,new_h=234,因为resize是以w为长边压缩的 // 所以x相对于width的比例不变,而b.y表示y相对于图像高度的比例,在进行这一步的转化之前,b.y表示 // 的是预测框的y坐标相对于网络height的比值,要转化到相对于letter_box中图像的height的比值时,需要先 // 计算出y在letter_box中的相对坐标,即(b.y - (neth - new_h)/2./neth),再除以比例 b.x = (b.x - (netw - new_w)/2./netw) / ((float)new_w/netw); b.y = (b.y - (neth - new_h)/2./neth) / ((float)new_h/neth); b.w *= (float)netw/new_w; b.h *= (float)neth/new_h; if(!relative){ b.x *= w; b.w *= w; b.y *= h; b.h *= h; } dets[i].bbox = b; } }
问题
如果我检测的图片长宽比不是1:1,或者我的图片大小并不是32的整数倍,如果 resize 会使目标失真,怎么办呢?
通过分析,实际上这些疑问都是没有必要的。yolo v5 设置的 img_size 并不会影响任意尺寸图像的检测,这个数值设置的目的是使输入图像先被 resize 成 640×640,满足检测网络结构,最后再 resize 成原始图像尺寸,进行显示。
参考
1. 【pytorch】自己实现精简版YOLOV3【三】,YOLOV3输入图片预处理:输入图片缩放及将生成预测框还原至原图;
2. YOLO V5 测试图像时 img_size 的设置问题;
心正意诚,做自己该做的事情,做自己喜欢做的事情,安静做一枚有思想的技术媛。
版权声明,转载请注明出处:https://www.cnblogs.com/happyamyhope/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
2021-08-08 【git基础】git error: failed to push some refs to remote