前言
在海思AI芯片(Hi3519A/3559A)方案学习(十四)JPEG图片转换成bgr文件 中,有提到如何将jpeg文件转换为bgr格式数据,然后再输入到NNIE模型进行目标识别。但是在jpeg图片转换中,是先将原始图像直接resize成模型网络size,如下红框所示。
问题
加入说待识别的输入图片size是1200x800,而我们的模型网络size是600x600,那么如果长、宽按都按2:1比例缩小的话,图片应该resize成600x400。但事实上,高度缩小比是800/600=4/3 < 2。 这种不等比例的缩放会导致图像变形。就这个例子而言,因为高度方向缩小比小些,会使得图像上的目标被拉长了。 这里大家脑补一下吧,我就不画图了。
另外, 当输入图片size为800x1200,类似的,直接resize成600x600后,图像上目标会显得拉宽了。
解决办法
以图像较大的边为基准,宽高方向上 等比例缩放到网络size,并对小边方向上进行适当填充,以保证方放缩后的图像size和网络size相等。代码实现如下。
Mat img = imread("D:/work/xxxx.jpg");
if (img.empty())
{
printf("reading image file fails \n");
return 1;
}
int net_w, net_h;
net_w = 416;
net_h = 416;
#if 0
Mat box;
resize(img, box, Size(net_w, net_h));
#else
//resize
int new_w, new_h;
if (((float)net_w / img.cols) < ((float)net_h / img.rows)) {
new_w = net_w;
new_h = (img.rows * new_w) / img.cols;
}
else {
new_h = net_h;
new_w = (img.cols * net_h) / img.rows;
}
Mat resized;
cv::resize(img, resized, Size(new_w, new_h));
Mat box = Mat(Size(net_w, net_h), CV_MAKETYPE(CV_8U, img.channels()), Scalar::all(127));
Mat roi(box, Rect((net_w - new_w) >> 1, (net_h - new_h) >> 1, new_w, new_h));
resized.copyTo(roi);
识别结果比较
以两种放缩方式在3519A上进行仿真推理,其结果示意图如下。左图(仔细看,狗被拉长了)是直接resize的识别结果;右图是等比例缩放,由于小边高度缩的比较多,所以上下进行了填充。显然,右边的结果要好一些。