坑0 cv::Mat对象内存问题

image-20230601123926445

同时 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,在内存中的typeCV_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()); 
}

标签: none

添加新评论