【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
View Code

预测框还原到原图

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;
    }
}
View Code

 

问题

如果我检测的图片长宽比不是1:1,或者我的图片大小并不是32的整数倍,如果 resize 会使目标失真,怎么办呢?

通过分析,实际上这些疑问都是没有必要的。yolo v5 设置的 img_size 并不会影响任意尺寸图像的检测,这个数值设置的目的是使输入图像先被 resize 成 640×640,满足检测网络结构,最后再 resize 成原始图像尺寸,进行显示。

 

对于图像尺度问题,(1280, 720)  -----> (416, 234) -----> (416, 416);
所以,最后的bbox检测比例是基于(416, 234),之后等比例放大到(1280, 720),相当于bbox的size扩大了3倍,那么(416, 234)上的小目标resize到3倍大的1280*720的图像上,位置会有偏移吧,可以试试显示到letterbox image上的效果;通过简单计算,发现检测的bbox位置有偏移的问题,应该不是缩放引起的。因为letterbox的缩放是等比例缩放,类似于一个物体的缩小和放大,并不会影响图像中的位置信息的偏移问题。所以,bbox位置偏移应该还是检测效果不好引起的。
 
update20221111
在原代码的基础上添加了卡尔曼跟踪器,计算giou的时候调用函数box_union得到的结果不正确,函数内printf正确,函数外打印结果不一样,经过同事帮忙,原来是box_union在另一个文件使用的时候,没有对函数进行声明,解决方法:
1)在src/box.h中声明使用的函数,并将box.h包含在使用的文件中;
2)在darknet.h中声明box_union函数(box_iou函数已在darknet.h中声明);
注意,调试代码过程中,如果仔细检查之后仍然觉得代码逻辑没有错误,特别是简单的代码,那么可能就是头文件有问题,比如函数声明;
 

参考

1. 【pytorch】自己实现精简版YOLOV3【三】,YOLOV3输入图片预处理:输入图片缩放及将生成预测框还原至原图

2. YOLO V5 测试图像时 img_size 的设置问题

posted on 2022-08-08 18:39  鹅要长大  阅读(12)  评论(0编辑  收藏  举报

导航