7

如何在不进行任何压缩的情况下保存 16 位图像(PNG 或 TIFF)?语法是什么?

4

5 回答 5

4

2 年后,OpenCV 可以通过压缩 (LZW) 保存 16 位 TIFF(2.4.x 版本)。但它也支持函数中未记录的参数 TIFFTAG_COMPRESSION

bool imwrite(const string& filename, InputArray img, const vector<int>& params=vector<int>() )

例如,它可以设置为 COMPRESSION_LZMA(并且工作正常)。

您可以使用 COMPRESSION_NONE 作为此参数的值(您还必须将 TIFFTAG_ROWSPERSTRIP 参数设置为图像高度)。

但是即使在 2.4.9 版本中,OpenCV 在这种情况下仍然会生成不正确的 TIFF(尝试将 TIFFTAG_COMPRESSION 设置为 COMPRESSION_NONE)。

在查看 OpenCV 源代码后,我发现了两种克服此限制的方法:

  1. 使用“opencv/modules/imgcodecs/src/grfmt_tiff.cpp”中的更改重新编译 OpenCV——来自 OpenCV 的人添加了压缩参数,但忘记了如果我们不想要压缩,libtiff 无法在 TIFF 句柄中设置预测器这一事实。你应该找到这个代码

    if ( !TIFFSetField(pTiffHandle, TIFFTAG_IMAGEWIDTH, width) || !TIFFSetField(pTiffHandle, TIFFTAG_IMAGELENGTH, height) || !TIFFSetField(pTiffHandle, TIFFTAG_BITSPERSAMPLE, bitsPerChannel) || !TIFFSetField(pTiffHandle, TIFFTAG_COMPRESSION, compression) || !TIFFSetField(pTiffHandle, TIFFTAG_PHOTOMETRIC, colorspace) || !TIFFSetField(pTiffHandle, TIFFTAG_SAMPLESPERPIXEL, channels) || !TIFFSetField(pTiffHandle, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG) || !TIFFSetField(pTiffHandle, TIFFTAG_ROWSPERSTRIP, rowsPerStrip) || !TIFFSetField(pTiffHandle, TIFFTAG_PREDICTOR, predictor) ) { TIFFClose(pTiffHandle); return false; }

    并将其更改为

    if ( !TIFFSetField(pTiffHandle, TIFFTAG_IMAGEWIDTH, width) || !TIFFSetField(pTiffHandle, TIFFTAG_IMAGELENGTH, height) || !TIFFSetField(pTiffHandle, TIFFTAG_BITSPERSAMPLE, bitsPerChannel) || !TIFFSetField(pTiffHandle, TIFFTAG_COMPRESSION, compression) || !TIFFSetField(pTiffHandle, TIFFTAG_PHOTOMETRIC, colorspace) || !TIFFSetField(pTiffHandle, TIFFTAG_SAMPLESPERPIXEL, channels) || !TIFFSetField(pTiffHandle, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG) || !TIFFSetField(pTiffHandle, TIFFTAG_ROWSPERSTRIP, rowsPerStrip) ) { TIFFClose(pTiffHandle); return false; } if (compression != COMPRESSION_NONE && !TIFFSetField(pTiffHandle, TIFFTAG_PREDICTOR, predictor) ) { TIFFClose(pTiffHandle); return false; }

    在此之后 OpenCV 可以保存压缩和未压缩的 TIFF(取决于参数imwrite)。

  2. 另一种方法是在您的应用程序中直接使用 libtiff 来保存 TIFF。当然在这种情况下你需要实现写功能。对于 Windows,您应该编译 libtiff,但这是一项相当简单的任务(libtiff 包含许多编译器的生成文件,并且可以在 32 位和 64 位的 MinGW 和 MSVC 中完美编译)。

于 2014-10-24T17:57:20.210 回答
2

At least from 2.1 (haven't used older versions) cvSaveImage saves a single channel 16b depth image without problems. I usualy use .png for this.

This would get you a 16b image with "somedata":

IplImage* image = cvCreateImage(cvSize(100,100),16,1);
memset(image->imageData,someData,image->width*image->height*2);
cvSaveImage("image.png",image);
于 2012-08-22T13:32:51.827 回答
2

根据 OpenCV 文档,cvSaveImage 仅支持 8bit 单通道或 BGR 图像。请参阅 2.0 文档。

您应该使用 libpng、libMagick++ 或其他一些库以其他位深度和格式保存。

libpng 文档包含有关如何编写 PNG 图像的教程。要指定每通道数据为 16 位的 RGB,请使用 bit_depth = 16 和 color_type = PNG_COLOR_TYPE_RGB。

为了让你的生活(可能)更轻松一些,还有png++

编辑: OpenCV 似乎支持在较新版本中编写 16bpc 图像。请参阅 p.streef 的答案。这是相关文档的链接。

于 2012-08-22T12:53:56.680 回答
2

万一其他人遇到这个 avtomaton 的解决方案似乎是通过拉请求https://github.com/opencv/opencv/pull/3744添加的,

允许您执行以下操作(适用于 3.2):

cv::Mat shorts(1024*cv::Mat::ones(100, 100, CV_16UC1));
vector<int> tags = {TIFFTAG_COMPRESSION, COMPRESSION_NONE};

bool success = cv::imwrite("uncompressed.tif", shorts, tags);
于 2017-06-02T18:31:42.483 回答
0

我的经验是 OpenCV 将图像保存为 16 位(没有尝试使用 3 个通道)。pgm 格式绝对有效,它是一种真正的原始格式(没有运行长度压缩)。

于 2012-08-22T13:23:34.193 回答