OpenCV 保存 CV_32FC1 图像

Posted

技术标签:

【中文标题】OpenCV 保存 CV_32FC1 图像【英文标题】:OpenCV save CV_32FC1 images 【发布时间】:2013-07-18 23:45:40 【问题描述】:

我正在使用的程序正在读取一些位图,并且需要 32FC1 图像。

我正在尝试创建这些图像

cv::Mat M1(255, 255, CV_32FC1, cv::Scalar(0,0,0));
cv::imwrite( "my_bitmap.bmp", M1 );

但是当我检查深度时 - 它总是 CV_8U

如何创建文件以便它们包含正确的信息?

更新:如果我使用不同的文件扩展名 - 例如tif 或 png

我正在阅读它 - 使用已经实现的代码 - 使用 cvLoadImage

我正在尝试创建现有代码(检查图像类型)可以使用的文件。

我无法转换现有代码中的文件。现有代码不会尝试读取随机图像类型并将其转换为所需类型,而是检查文件是否为所需类型。

我发现 - 感谢您的回答 - cv::imwrite 只写入整数类型的图像。

是否有另一种方法(使用 OpenCV 或其他方式)来编写图像,以便我最终得到 CV_32F 类型?

再次更新: 读取图像的代码...如果进入 cv::Mat:

cv::Mat x = cv::imread(x_files, CV_LOAD_IMAGE_ANYDEPTH|CV_LOAD_IMAGE_ANYCOLOR);

现有代码:

IplImage *I = cvLoadImage(x_files.c_str(), CV_LOAD_IMAGE_ANYDEPTH|CV_LOAD_IMAGE_ANYCOLOR);

【问题讨论】:

你给你的外部程序什么?文件的路径还是cv::Mat 对象? 我们能看到使用cvLoadImage读取文件的代码吗? 我给它文件路径 【参考方案1】:

cv::imwrite().bmp 编码器采用 8 位通道。

如果您只需要使用 OpenCV 编写 .bmp 文件,您可以将您的 32FC1 图像转换为 8UC4,然后使用cv::imwrite() 编写它,您将得到一个每像素 32 位的 .bmp 文件。 我猜您读取文件的程序会将 32 位像素解释为 32FC1。 .bmp format 没有明确的通道结构,只有每个像素的位数。因此,您应该能够在 OpenCV 中将 32 位像素写入 4 个 8 位通道,并在另一个程序中将它们读取为单通道 32 位像素 - 如果您这样做,您需要了解读者的字节顺序假设。像下面这样应该工作:

cv::Mat m1(rows, cols, CV_32FC1);
...  // fill m1
cv::Mat m2(rows, cols, CV_8UC4, m1.data); // provide different view of m1 data
// depending on endianess of reader, you may need to swap byte order of m2 pixels
cv::imwrite("my_bitmap.bmp", m2);

您将无法正确读取您在 OpenCV 中创建的文件,因为 OpenCV 中的 .bmp 解码器假定文件是 1 或 3 通道 8 位数据(即无法读取 32 位像素)。


编辑

可能更好的选择是使用OpenEXR 格式,OpenCV 有一个编解码器。我假设您只需要使用 .exr 扩展名保存文件。

【讨论】:

谢谢,我不知道imwrite总是创建CV_8U。请看更新。即使我在写作之前进行了转换,我仍然会得到 CV_8U(根据文档)。所以……我的情况没有希望了吗?或者有什么方法可以创建这些图像? 你有读取.bmp文件的程序的源代码吗?我想知道它对像素格式做了什么假设。【参考方案2】:

您的问题是位图在内部将数据存储为整数而不是浮点数。如果您的问题是保存时的舍入错误,您将需要使用不同的文件格式或在保存前放大数据,然后在保存后缩小。如果您只想将读取文件后获得的矩阵转换为浮点数,您可以使用 cv::convertto

【讨论】:

不幸的是,我无法在阅读后转换类型,图像必须是正确的类型。我在写入之前尝试了文件格式和缩放...然后我从文档中发现 imwrite 只写入 CV_8U。有替代品吗? 出于好奇,为什么阅读后不能转换类型?根据您需要的精度,如果您有一组已知的值,您可以将图像乘以某个常数(例如 100),将其保存为 16 位 png,然后当您将其读回时除以 100。即使这也需要更改虽然类型。【参考方案3】:

我也在为同样的问题而苦苦挣扎。最后,我决定编写一个可以编写和加载任意 CV Mat 的自定义函数会更容易。

bool writeRawImage(const cv::Mat& image, const std::string& filename)

    ofstream file;
    file.open (filename, ios::out|ios::binary);
    if (!file.is_open())
        return false;
    file.write(reinterpret_cast<const char *>(&image.rows), sizeof(int));
    file.write(reinterpret_cast<const char *>(&image.cols), sizeof(int));
    const int depth = image.depth();
    const int type  = image.type();
    const int channels = image.channels();
    file.write(reinterpret_cast<const char *>(&depth), sizeof(depth));
    file.write(reinterpret_cast<const char *>(&type), sizeof(type));
    file.write(reinterpret_cast<const char *>(&channels), sizeof(channels));
    int sizeInBytes = image.step[0] * image.rows;
    file.write(reinterpret_cast<const char *>(&sizeInBytes), sizeof(int));
    file.write(reinterpret_cast<const char *>(image.data), sizeInBytes);
    file.close();
    return true;


bool readRawImage(cv::Mat& image, const std::string& filename)

    int rows, cols, data, depth, type, channels;
    ifstream file (filename, ios::in|ios::binary);
    if (!file.is_open())
        return false;
    try 
        file.read(reinterpret_cast<char *>(&rows), sizeof(rows));
        file.read(reinterpret_cast<char *>(&cols), sizeof(cols));
        file.read(reinterpret_cast<char *>(&depth), sizeof(depth));
        file.read(reinterpret_cast<char *>(&type), sizeof(type));
        file.read(reinterpret_cast<char *>(&channels), sizeof(channels));
        file.read(reinterpret_cast<char *>(&data), sizeof(data));
        image = cv::Mat(rows, cols, type);
        file.read(reinterpret_cast<char *>(image.data), data);
     catch (...) 
        file.close();
        return false;
    

    file.close();
    return true;

【讨论】:

以上是关于OpenCV 保存 CV_32FC1 图像的主要内容,如果未能解决你的问题,请参考以下文章

opencv mat的数据类型CV_32FC1变成CV_8UC1

OpenCV 中的 CV_8UC1 到 CV_32FC1 的转换

OpenCV:如何读取浮点图像

如何在OpenCV中使用双重类型的地图重新映射

使用 OpenCV 保存整数 CV_32S 图像

【OpenCV】用cvCalibrateCamera2函数做标定出错,大家帮忙看下吧