首先opencv和onnxruntime的配置就不说了,resnet分类网络就只有三个部分,一个是图片等比例放缩letterbox;而是图片归一化等处理成输入PreProcess;三是onnx推理
等比例放缩
只是单纯的reisze太粗暴了,而且之后写yolo的时候要用到等比例,索性先写了,
输入图像mat,放缩后的宽int ,放缩后的高int ;输出为等比例放缩后的图像mat
放缩后的图像居中,我是空白部分填充灰色(114,114,114),copyMakeBorder的参数自己改
Mat letterbox(Mat src, int tar_w, int tar_h)
{
//以下为带边框图像生成
int in_w = src.cols;
int in_h = src.rows;
//哪个缩放比例小选用哪个
float r = min(float(tar_h) / in_h, float(tar_w) / in_w);
int inside_w = round(in_w * r);
int inside_h = round(in_h * r);
int padd_w = tar_w - inside_w;
int padd_h = tar_h - inside_h;
//内层图像resize
Mat resize_img;
resize(src, resize_img, Size(inside_w, inside_h));
//cvtColor(resize_img, resize_img, COLOR_BGR2RGB);
padd_w = padd_w / 2;
padd_h = padd_h / 2;
//外层边框填充灰色
int top = int(round(padd_h - 0.1));
int bottom = int(round(padd_h + 0.1));
int left = int(round(padd_w - 0.1));
int right = int(round(padd_w + 0.1));
copyMakeBorder(resize_img, resize_img, top, bottom, left, right, BORDER_CONSTANT, Scalar(114, 114, 114));
//cout << resize_img.size() << endl;
//imshow("pad", resize_img);
//waitKey(10);
return resize_img;
}
图像预处理
正常图像已经放缩成了3x224x224的uint8形式,这一步是把它处理成卷积的输入(转tensor前),通俗来说就是 bgr转rgb然后归一化。
这个其实可以一句话直接表示,也就是opencv的内置函数cv2.dnn.blobFromImage
Mat new_image= cv::dnn::blobFromImage(image, 1. / 255, Size(resize_w, resize_h), Scalar(0.485, 0.456, 0.406), true, false);
或者
// 这个版本的代码有问题,出来的结果不对,但是我还没弄明白为什么,建议还是直接copy官方的blobFromImage源码
Mat mytryPreProcess(Mat image, int tar_w, int tar_h)
{
// 图像处理 标准化处理
Mat input;
resize(image, input, Size(tar_w, tar_h));
//数据处理 标准化
std::vector<Mat> channels, channel_p;
split(input, channels);
Mat R, G, B;
B = channels.at(0);
G = channels.at