1.0-Opencv preprocess for yolov5
坑0 cv::Mat
对象内存问题
同时 OpenCV使用引用计数机制来管理cv::Mat
对象的内存,这意味着当复制一个cv::Mat
对象时,实际上只会增加引用计数,而不会复制底层数据。
坑1 cv::imwrite()
保存问题
cv::imwrite()
函数用于将图像保存到文件中。默认情况下,它期望输入图像的像素类型是8位无符号整数(CV_8U
)。如果使用
convertTo(normalized_image, CV_32FC3, 1.0 / 255.0);
转成了fp32格式,将无法使用cv::imwrite()
保存。
坑2 “通道转换”和“convertTo”归一化的先后顺序问题
由于读取cv::imread("inference/car.jpg")
读取的cv::Mat
,在内存中的type
是CV_8UC3
,使用resized_image.convertTo(normalized_image, CV_32FC3, 1.0 / 255.0);
会将其转换成fp32,在内存中占用内存空间不同,之后使用cv::cvtColor(image, converted_image, cv::COLOR_BGR2RGB);
会造成一些奇奇怪怪的错误.......
坑3 opencv读取的格式和yolov5推理格式的区别
这里说的格式,代表opencv 读取的数据通道顺序为(高,宽,BGR),而yolov5需要的是(RGB,高,宽),顺序不同,且色彩通道顺序也不同。在数据处理时需要额外注意!!!
结论
cv::Mat convertBGRtoRGB(const cv::Mat& image)
{
cv::Mat converted_image;
cv::cvtColor(image, converted_image, cv::COLOR_BGR2RGB);
return converted_image;
}
cv::Mat padToSquare(const cv::Mat& image, const cv::Scalar& color)
{
int max_dim = std::max(image.rows, image.cols);
int top = 0, bottom = 0, left = 0, right = 0;
if (image.rows < max_dim) {
int diff = max_dim - image.rows;
top = diff / 2;
bottom = diff - top;
}
else if (image.cols < max_dim) {
int diff = max_dim - image.cols;
left = diff / 2;
right = diff - left;
}
cv::Mat padded_image;
cv::copyMakeBorder(image, padded_image, top, bottom, left, right, cv::BORDER_CONSTANT, color);
return padded_image;
}
void preprocess(cv::Mat &src,cv::Mat &dst){
cv::Mat coner_img = convertBGRtoRGB(src); # 先bgr转rgb
cv::Scalar fill_color(116, 116, 116);
cv::Mat squared_image = padToSquare(coner_img, fill_color); # 补灰色到图片成为方形
cv::Mat resized_image;
cv::Size target_size(640, 640);
cv::resize(squared_image, resized_image, target_size); # resize 640 不会变形
src = resized_image;
cv::Mat normalized_image;
resized_image.convertTo(normalized_image, CV_32FC3, 1.0 / 255.0); # 归一化/255
dst = normalized_image;
}
在copy内存前做 (高,宽, RGB)=>>>>(RGB,高,宽)
struct Image {
const float *rgbprt = nullptr; // 32fp指针
int width = 0, height = 0, size = 0; // 多少个float
Image() = default;
Image(const float *rgbprt, int width, int height,int size) : rgbprt(rgbprt), width(width), height(height),size(size){}
};
yolo::Image cvimg(const cv::Mat &image) {
std::shared_ptr<std::vector<float>> inputData = std::make_shared<std::vector<float>>();
inputData->reserve(image.cols * image.rows * 3);
for (int c = 0; c < 3; ++c) {
for (int i = 0; i < image.rows; ++i) {
for (int j = 0; j < image.cols; ++j) {
float tmp = image.at<cv::Vec3f>(i, j)[c];
inputData->push_back(tmp);
}
}
}
return yolo::Image(inputData->data(), image.cols, image.rows,image.cols*image.rows*image.channels());
}