【问题标题】:OpenCV image conversion goes wrongOpenCV 图像转换出错
【发布时间】:2020-06-08 22:06:57
【问题描述】:

我有一个算法可以做一些事情。其中,如果我正在处理CV_8UC3 图像,则转换工作正常,但如果文件类型为C_16UC3,则会出错。 这是一些代码:

//new image is created
Mat3w img(100,100,Vec3w(1000,0,0));
//Image Conversion - ERROR!
cv::Mat inputSource;
//saving the image here will work
img.convertTo(inputSource, CV_64FC3);
//saving the image here will not work -> black image

问题在于CV_16UC3 图像的处理结果是正确尺寸但全黑的图像。 问题在于转换,因为在之前保存图像会得到一个合法的图像,而在之后保存它会得到一个几乎完全白色的图像。

编辑:

我做了一些改动:删掉了一些无用的代码,添加了 inputSource 声明。 现在,当我尝试一些东西时,我得出的结论是,要么我不了解 CV 类型,要么发生了一些奇怪的事情。 我一直认为类型中的数字表示每个通道的位数。所以,在我看来,CV_16UC3 是一个 3 通道,每个通道 16 位。我在测试期间保存的图像(在 img.convertTo 之前)实际上每个通道号都有匹配的位,这一事实加强了这个想法。奇怪的是,保存的inputSource(类型CV_64FC3)是8bpc图片。

我错过了什么?

【问题讨论】:

  • 好的,我做了一些修改!由于复制/粘贴错误,CV_MAKTYPE 在那里。在代码中它属于旧的转换线。相关代码几乎就是上面的代码。我创建了 Mat,它作为参数传递给声明 inputSource 并在这个新 Mat 中转换图像的函数。
  • @pedro 你得到什么样的错误信息?
  • 如果没有错误但只是 imwrite 写入了错误的图像,请参阅 docs.opencv.org/modules/highgui/doc/… 不希望您保存浮点图像。而是尝试使用 imshow 显示垫子(每个通道中的值介于 0 = 黑色和 1 = 白色之间)或将值打印到终端。
  • 好的,我想我已经成功了 :) 问题可能是算法设置了 255 位像素上限,但没有强制转换为 8 位。因此,加载 16 位图像会搞砸一切。现在它适用于 16 位 :) 它不会显示 32 位的图像,但这并不是一个真正的问题。我稍后会尝试,但我并不介意。再次感谢你! :D

标签: c++ opencv


【解决方案1】:

您对 imwriteimread 在 OpenCV 中的工作方式感到困惑。来自OpenCV documentation

改写

函数imwrite 将图像保存到指定文件。图像格式是根据文件扩展名选择的(有关扩展名列表,请参阅imread())。使用此功能只能保存 8 位(或 16 位无符号 (CV_16U) 在 PNG、JPEG 2000 和 TIFF 的情况下)单通道或 3 通道(具有“BGR”通道顺序)图像。如果格式、深度或通道顺序不同,请使用Mat::convertTo()cvtColor() 转换后再保存。或者,使用通用的FileStorage I/O 函数将图像保存为 XML 或 YAML 格式。

已读

函数 imread 从指定文件加载图像并返回。可能的标志是:

  • IMREAD_UNCHANGED :如果设置,则按原样返回加载的图像(使用 alpha 通道,否则会被裁剪)。
  • IMREAD_GRAYSCALE :如果设置,则始终将图像转换为单通道灰度图像。
  • IMREAD_COLOR : 如果设置,则始终将图像转换为 3 通道 BGR 彩色图像。
  • IMREAD_ANYDEPTH : 如果设置,则在输入具有相应深度时返回 16 位/32 位图像,否则将其转换为 8 位。
  • IMREAD_ANYCOLOR :如果设置,则以任何可能的颜色格式读取图像。

因此,对于您的情况,CV_16U 无需转换即可保存,而CV_64F 已转换并保存为CV_8U。如果要存储double 数据,则应使用FileStorage。 您还应该注意使用带有适当标志的imread 图像。

这个例子应该澄清:

#include <opencv2\opencv.hpp>
using namespace cv;

int main()
{
    // Create a 16-bit 3 channel image
    Mat3w img16UC3(100, 200, Vec3w(1000, 0, 0));
    img16UC3(Rect(0, 0, 20, 50)) = Vec3w(0, 2000, 0);

    // Convert to 64-bit (double) 3 channel image
    Mat3d img64FC3;
    img16UC3.convertTo(img64FC3, CV_64FC3);

    // Save to disk
    imwrite("16UC3.png", img16UC3); // No conversion
    imwrite("64FC3.png", img64FC3); // Converted to CV_8UC3

    FileStorage fout("64FC3.yml", FileStorage::WRITE);
    fout << "img" << img64FC3; // No conversion
    fout.release();


    Mat img_maybe16UC3_a = imread("16UC3.png" /*, IMREAD_COLOR*/);  // Will be CV_8UC3
    Mat img_maybe16UC3_b = imread("16UC3.png", IMREAD_ANYDEPTH);    // Will be CV_16UC1
    Mat img_maybe16UC3_c = imread("16UC3.png", IMREAD_UNCHANGED);   // Will be CV_16UC3 

    Mat img_maybe64FC3_a = imread("64FC3.png" /*, IMREAD_COLOR*/);  // Will be CV_8UC3
    Mat img_maybe64FC3_b = imread("64FC3.png", IMREAD_ANYDEPTH);    // Will be CV_8UC1
    Mat img_maybe64FC3_c = imread("64FC3.png", IMREAD_UNCHANGED);   // Will be CV_8UC3

    Mat img_mustbe64FC3;
    FileStorage fin("64FC3.yml", FileStorage::READ);
    fin["img"] >> img_mustbe64FC3; // Will be CV_64FC3
    fin.release();

    return 0;
}

【讨论】:

  • 好吧,如果我做对了,那么在使用 imwrite 转换后立即保存图像来跟踪程序的运行是没有意义的,因为它总是会被存储坏?对于 imread 的问题,原始代码使用它(以 CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR 作为标志),但我不得不使用 FreeImage,因为我也需要加载 hdr/pfm/pbf/tiff 图像..
  • 无论如何,该算法将始终保存 8 位/通道图像,因为它是这样工作的;所以在我实现加载我想要过滤的图像之后(我做到了)它应该可以工作..对吗?
  • @pedro imwrite 将图像保存为 RGB,这没有错。您可以使用您喜欢的任何类型,请记住,如果将结果保存为图像,则图像将为 RGB。如果要存储实际值,请使用FileStorage
猜你喜欢
  • 2018-06-29
  • 1970-01-01
  • 2012-05-09
  • 2014-05-24
  • 1970-01-01
  • 2021-05-29
  • 1970-01-01
  • 2011-02-21
  • 2011-11-29
相关资源
最近更新 更多