赞
踩
接上篇博文:
Yolov3网络的输入默认为416x416,然后待检测的图片不总是416x416,这就产生了如何将待检测图片,在不破坏特征的情况下缩放至416x416,并对应在网络产生预测框后,如何将416x416图中的预测框还原至原图的问题。
对此,Yolov3的方法如下图所示,分为3步:
1.求取缩放比例,将目标416x416,除以输入图像尺寸(width,height),取其中较小的一个比例,将长宽同时按此比例进行缩放。由于是长宽等比缩放,所以图片的特征并不失真。
2.制作rgb为(128,128,128),大小为416*416的底色图片。
3.将两张图片的中心对其,将缩放后的图片粘贴到底色图上。
![在这里插入图片描述](https://img-blog.csdnimg.cn/11ad5cb346b24e568e773a1d2aae869b.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6aKi5biI5YKF,size_20,color_FFFFFF,t_70,g_se,x_16
其实现的pytorch代码如下:
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
将此416x416图片输入网络,即可在该416x416图片上预测出目标框;同时,在输出预测结果时,应将输出的目标框,还原至未处理图像上,由此,对应的pytorch代码为:
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 returnBoxOnOriginImage(OriginimageShape,boxesOnletterbox_image,imageShape):
'''
经过letterbox_image函数缩放过的图片,在其上得到box框坐标后,用此函数返回图片在经letterbox_image函数缩放
前,box在原图上的位置。
:param OriginimageShape:原始图片大小,[[w,h],...] size (n,2)
:param boxesOnletterbox_image: 在最终补齐的图片上的盒大小位置参数:
[[x,y,w,h],...] size (n,4)其值为边长的比例值。注意,其中x,y为网格中心点的坐标
:param imageShape:最终补齐的图片大小,[416,416]
:return:[[x1,y1,x2,y2],...] size (n,4) 比例值,为box左上角及右下角的坐标。
'''
#xy从网格中心点坐标转换为网格左上角的坐标:
boxesOnletterbox_image[:,0:2]=boxesOnletterbox_image[:,0:2]-boxesOnletterbox_image[:,2:4]/2
#imageShape/OriginimageShape,size为(n,2),输出(n,1)最大值数组
# 经过长宽缩放但未补全大小的图片大小
resizedImageShape=OriginimageShape*torch.min(imageShape/OriginimageShape,1,keepdim=True)[0]
#目前box是画在最终图片上,要将box回归到补全前只经过缩放处理的原始图片
#以最终图片为基准的缩放比例:
scales=resizedImageShape/imageShape
#以最终图片为基准的偏移率:
offset=(imageShape-resizedImageShape)/2/imageShape
boxesOnOriginimage=torch.torch.FloatTensor(boxesOnletterbox_image.shape)
'''将以最终图片为基准的值转为以待补全图像为基准的比例值,由于待补全图片和
原图是长宽以相同比例放大转换关系,故结果可视为box在原图上的比例值:
'''
boxesOnOriginimage[:,0:2]=(boxesOnletterbox_image[:,0:2]-offset)/scales
boxesOnOriginimage[:,2:4]=boxesOnletterbox_image[:,2:4]/scales
#从x1,y1,w,h到x1,y1,x2,y2
boxesOnOriginimage[:, 2:4] = boxesOnletterbox_image[:, 0:2] +boxesOnletterbox_image[:, 2:4]
return boxesOnOriginimage
#简单测试
OriginimageShape=torch.FloatTensor([[300,400]])
boxesOnletterbox_image=torch.FloatTensor([[100,200,200,200]])
imageShape=torch.FloatTensor([800,800])
print(returnBoxOnOriginImage(OriginimageShape,boxesOnletterbox_image,imageShape).shape)
测试代码输出结果为:
torch.Size([1, 4])
输出结果为[[x1,y1,x2,y2]],该函数输出值为比例形式。
设原图宽为w,高为h,则目标框左上角实际坐标为(x1w,y1h),目标框右下角实际坐标为(x2w,y2h)。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。