使用 OpenCV 写入 16 位未压缩图像
Posted
技术标签:
【中文标题】使用 OpenCV 写入 16 位未压缩图像【英文标题】:Writing 16 bit uncompressed image using OpenCV 【发布时间】:2012-08-22 12:34:33 【问题描述】:如何在不进行任何压缩的情况下保存 16 位图像(PNG 或 TIFF)?语法是什么?
【问题讨论】:
为什么人们不赞成这个问题? @onitake 我没有,但我只能假设,因为 OP 似乎在问一个基本问题而没有做功课。根据常见问题解答中的"How to Ask" 条目,用户必须在此处提问之前彻底研究问题并在问题中分享他们的结果。不这样做可能会导致该问题收到的反对票和接近票。我不能说我完全不同意他们。 您应该检查 OpenCV 源代码。许多此类高级功能可用,但未记录在案。也许一些额外的 imwrite 参数会让你到达那里 也许 OP 没有搜索,但这不是一个微不足道的问题。 【参考方案1】: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 源代码后,我发现了两种方法来克服这个限制:
使用“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
的参数)。
另一种方法是在应用程序中直接使用 libtiff 来保存 TIFF。当然在这种情况下你需要实现写功能。对于 Windows,您应该编译 libtiff,但这是一个相当简单的任务(libtiff 包含许多编译器的 makefile,并且可以在 32 位和 64 位的 MinGW 和 MSVC 中完美编译)。
【讨论】:
【参考方案2】:至少从 2.1(未使用旧版本)开始,cvSaveImage 可以毫无问题地保存单通道 16b 深度图像。我通常为此使用 .png。
这将为您提供带有“somedata”的 16b 图像:
IplImage* image = cvCreateImage(cvSize(100,100),16,1);
memset(image->imageData,someData,image->width*image->height*2);
cvSaveImage("image.png",image);
【讨论】:
很好的发现!谷歌似乎忘记了更新的文档? Here's the relevant docs page【参考方案3】:根据 OpenCV 文档,cvSaveImage 仅支持 8bit 单通道或 BGR 图像。 See 2.0 docs.
您应该使用 libpng、libMagick++ 或其他库以其他位深度和格式保存。
libpng 文档包含关于how to write PNG images 的教程。要指定每通道 16 位数据的 RGB,请使用 bit_depth = 16 和 color_type = PNG_COLOR_TYPE_RGB。
为了让你的生活(可能)更轻松一点,还有png++。
编辑: OpenCV 似乎支持在较新版本中写入 16bpc 图像。请参阅 p.streef 的答案。这里是the link to the relevant documentation again.
【讨论】:
【参考方案4】:如果其他人遇到这个 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);
【讨论】:
【参考方案5】:我的经验是 OpenCV 将图像保存为 16 位(没有尝试使用 3 通道)。 pgm 格式确实有效,它是一种真正的原始格式(没有运行长度压缩)。
【讨论】:
以上是关于使用 OpenCV 写入 16 位未压缩图像的主要内容,如果未能解决你的问题,请参考以下文章