Why imread is reallocating data buffer

asked 2020-09-24 07:37:13 -0500

Maxime gravatar image

Hello!

I recently ask an other question similar to this one. Here I don't have any CUDA dependencies :

I create a Mat using a pre-allocated data buffer. Here's a code example :

#include <iostream>
#include <experimental/filesystem>
#include <opencv2/opencv.hpp>
#include <opencv2/imgcodecs.hpp>

namespace fs = std::experimental::filesystem;

int main(int argc, char const *argv[])
{
    // ---- get arguments ----
    if (argc < 2) {
        std::cout << "number of arguments invalid" << std::endl;
        std::cout << "1 - Input Folder" << std::endl;
        std::cout << "2 - Output Folder" << std::endl;
        exit(1);
    }
    std::string input_folder = argv[1];
    std::string output_folder = argv[2];

    int cols = 5344, rows = 4016;    //your image size

    cv::Vec3b *src_ptr = (cv::Vec3b *)malloc(rows*cols*sizeof(cv::Vec3b));
    cv::Mat src(rows, cols, CV_8UC3, src_ptr);

    std::cout << src_ptr << "    " << src.ptr<cv::Vec3b>() << "    " << src.size() << std::endl;

    for (const auto& entry : fs::directory_iterator(input_folder))
    {
        src = cv::imread(entry.path());
        std::cout << src_ptr << "    " << src.ptr<cv::Vec3b>() << "    " << src.size() << std::endl;
    }

    return 0;
}

I have an input folder with a set of images, and I am printing the address of the buffer alongside the current address of the data of Mat src. (Also with the size to prove that it is the same).

When running it, the address of src data change, and if you have more than one image, you can see that imread reallocate data at the same address every two images. Imread is supposed to call Mat::create : it should not reallocate if it is the same size!

I tried another test :

cv::Mat temp;

In the for loop :

    temp = cv::imread(entry.path());
    temp.copyTo(src);

Here the right pre-allocated address is used.

I'm looking to avoid this copy and directly use imread. Why does it behave like this?

Thanks in advance for any answers!!!

edit retag flag offensive close merge delete

Comments

1

When you do

src = cv::imread(entry.path())

you are performing an assignment of the result of imread() to src. As a result you are overwriting what ever was in src. I guess you want a version like the below (which unfortunately doesn't exist)

imread(const string path, Mat &src)

which you can pass src to by reference?

Alternatively you could use cudacodec which allows you to pass the GpuMat in but this will depend on you use case.

cudawarped gravatar imagecudawarped ( 2020-09-24 08:33:33 -0500 )edit

You're right, i didn't even think of the assignment. With the reference that would be wonderful but still it doesn't exist. I searched for a gpu version of imread in the documentation of cudacodecs but didn't find anything relevant. What were you thinking of ? Thanks for your comment

Maxime gravatar imageMaxime ( 2020-09-24 11:08:04 -0500 )edit

There is no GPU version of imread you need to use

bool cv::cudacodec::VideoReader::nextFrame(GpuMat &  frame,Stream &  stream = Stream::Null() )

which is fine if you are already performing processing on the GPU.

cudawarped gravatar imagecudawarped ( 2020-09-24 11:16:20 -0500 )edit

Ok I'm going to look at that! thank you.

Maxime gravatar imageMaxime ( 2020-09-24 11:20:12 -0500 )edit