使用OpenCV编写16位未压缩图像

8

如何保存没有任何压缩的16位图像(PNG或TIFF)?语法是什么?


4
为什么有人给这个问题点踩? - onitake
@onitake 我没有这样做,但我只能假设是因为 OP 似乎在没有做功课的情况下提出了一个基本问题。根据 FAQ 中的 "如何提问" 条目,用户在在此提问之前需要彻底研究问题并在问题中分享他们的研究结果。不这样做可能会引起这个问题所受到的负评和关闭投票。我不能说我完全不同意他们的看法。 - Bart
你应该检查OpenCV源代码。许多这样的高级功能可用,但没有记录。也许一些imwrite的额外参数可以帮助你实现目标。 - Sam
2
也许原帖作者没有搜索,但这绝非一个简单的问题。 - Sam
5个回答

4

经过2年的发展,OpenCV现在可以保存带有压缩(LZW)的16位TIFF文件(2.4.x版本)。但是,在函数

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

中,它还支持一个未公开的参数TIFFTAG_COMPRESSION。

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

您可以将此参数的值设置为COMPRESSION_NONE(同时必须将TIFFTAG_ROWSPERSTRIP参数设置为图像高度)。

但是,在这种情况下(试图将TIFFTAG_COMPRESSION设置为COMPRESSION_NONE),即使在2.4.9版本中,OpenCV仍会生成错误的TIFF文件。

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

  1. 重新编译OpenCV并更改"opencv/modules/imgcodecs/src/grfmt_tiff.cpp"文件 - 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包含许多编译器的makefile,并且在MinGW和MSVC、32位和64位上完美地编译)。


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);

2

至少从2.1版开始(未使用旧版本),cvSaveImage可以轻松保存单通道16位深度图像。我通常使用.png格式。

这将为您提供带有“somedata”的16位图像:

IplImage* image = cvCreateImage(cvSize(100,100),16,1);
memset(image->imageData,someData,image->width*image->height*2);
cvSaveImage("image.png",image);

非常好的发现!谷歌似乎对更新的文档视而不见?这是相关的文档页面 - onitake

2
根据OpenCV文档,cvSaveImage仅支持8位单通道或BGR图像。请参阅2.0文档
您应该使用libpng、libMagick++或其他库保存其他位深度和格式的图像。 libpng文档包含有关如何编写PNG图像的教程。要使用每个通道具有16位数据的RGB,请使用bit_depth = 16和color_type = PNG_COLOR_TYPE_RGB。
为了让您的生活(可能)变得更容易,还有png++
编辑:OpenCV似乎在较新的版本中支持写入16位深度的图像。请参考p.streef的答案。这里是相关文档的链接

0

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接