A library API takes an image raw pixel data as std::shared_ptr<uint8_t>
.
The image files I have can be in multiple formats (e.g. .png, .jpg, .bmp), so I use cv::imread
for practicality.
However, this returns the image as a cv::Mat
object, which I still need to convert to std::shared_ptr<uint8_t>
to comply with the library API signature.
I have tried similar solutions on the Internet, such as How to save image data in shared pointer and Creating shared_ptr from raw pointer, as well as std::make_shared
, either directly from the cv::Mat
std::make_shared<uint8_t>(*mat.data);
or from a std::vector
data.assign(mat.data, mat.data + mat.total() * mat.channels());
std::make_shared<uint8_t>(*data.data());
But all attempts resulted in either double deletion exception, corrupted data or compilation error.
The only way I got it to work was to write the raw pixels data to a file then read it to a shared pointer with
std::shared_ptr<uint8_t> data;
std::ofstream output("temp", std::ios::out | std::ios::binary);
output.write(reinterpret_cast<char*>(mat.data), size);
std::ifstream input("temp", std::ios::in | std::ios::binary);
data.reset(new uint8_t[size], std::default_delete<uint8_t[]>());
input.read((char*)data.get(), size);
Although this works, it bothers me to have such terrible solution for this.
What is the proper way to convert cv::Mat
to a shared pointer so that the data complies with the library API signature?
The full example that works, but looks terrible is
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <fstream>
int main(int argc,char* argv[])
{
std::string image_path = cv::samples::findFile("starry_night.jpg");
cv::Mat mat = cv::imread(image_path, cv::IMREAD_COLOR);
size_t size = mat.cols * mat.rows * mat.channels();
std::shared_ptr<uint8_t> data;
std::ofstream output("temp", std::ios::out | std::ios::binary);
output.write(reinterpret_cast<char*>(mat.data), size);
std::ifstream input("temp", std::ios::in | std::ios::binary);
data.reset(new uint8_t[size], std::default_delete<uint8_t[]>());
input.read((char*)data.get(), size);
// function(std::shared_ptr<uint8_t> data);
return 0;
}
I use the following CMakeLists.txt
to compile it (required OpenCV installed)
project(help)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(help help.cpp)
target_link_libraries(help ${OpenCV_LIBS})