库API将图像原始像素数据取为std::shared_ptr<uint8_t>
。
我拥有的图像文件可以是多种格式(例如.png、.jpg、.bmp),所以我使用cv::imread
是为了实用。
但是,这将图像作为cv::Mat
对象返回,我仍然需要将其转换为std::shared_ptr<uint8_t>
以符合库API签名。
我在Internet上尝试过类似的解决方案,例如How to save image data in shared pointer和Creating shared_ptr from raw pointer,以及std::make_shared
,或者直接从cv::Mat
std::make_shared<uint8_t>(*mat.data);
或从std::vector
data.assign(mat.data, mat.data + mat.total() * mat.channels());
std::make_shared<uint8_t>(*data.data());
但所有尝试都导致双重删除异常、数据损坏或编译错误。
我让它工作的唯一方法是将原始像素数据写入文件,然后将其读取到共享指针
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);
虽然这很有效,但对此有如此可怕的解决方案让我很困扰。
将cv::Mat
转换为共享指针以使数据符合库API签名的正确方法是什么?
完整的例子是这样的,虽然看起来很糟糕
#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;
}
我使用下面的CMakeLists.txt
来编译它(需要安装OpenCV)
project(help)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(help help.cpp)
target_link_libraries(help ${OpenCV_LIBS})
2条答案
按热度按时间7xllpg7q1#
这是不可能的。复制矩阵或使用
cv::imread
以外的其他库读取图像,以反转所有权语义,如果这是一个性能问题。OpenCV提供了非所有权矩阵(从指针构造函数,例如用stbi_load()
的输出馈送它),您可以将其用作std::span
等简单视图。但是,在矩阵构造之后,您不能手动更改该标志。查看
modules/core/src/matrix.cpp
处的源代码,可以手动添加cv::UMatData::USER_ALLOCATED
标志以防止内存释放。就像这样:
~Mat()
调用release()
,release()
调用deallocate()
,deallocate()
调用u->unmap()
,在几次函数调用之后:fastFree()
),它可能与std::shared_ptr
调用的delete
不兼容。这可能是OpenCV不允许释放矩阵的原因。ukdjmx9f2#
正如评论中建议的那样,我将复制数据,以便在删除
cv::Mat
后保留它这看起来已经比我以前的要好得多,但是更好的解决方案是
cv::Mat
释放它对数据的所有权。