简体   繁体   中英

Writing 16 bit uncompressed image using OpenCV

How can I save a 16 bit image (PNG or TIFF) without any compression? What is the syntax?

After 2 years OpenCV can save 16-bit TIFFs (2.4.x versions) with compression (LZW). But it also supports undocumented parameter TIFFTAG_COMPRESSION in function

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

It can be set to COMPRESSION_LZMA, for example (and working correctly).

You can use COMPRESSION_NONE as a value for this parameter (also you have to set TIFFTAG_ROWSPERSTRIP parameter to image height).

But OpenCV still generates incorrect TIFF in that case (trying to set TIFFTAG_COMPRESSION to COMPRESSION_NONE) even in 2.4.9 version.

After looking at OpenCV sources I found 2 ways to overcome this restriction:

  1. Recompile OpenCV with changes in "opencv/modules/imgcodecs/src/grfmt_tiff.cpp" - guys from OpenCV added parameter for compression, but forgot about the fact that libtiff can't set predictor in TIFF handle if we don't want compression. You should find this code

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

    and change it to

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

    after this OpenCV can save compressed and uncompressed TIFFs (depends on parameters to imwrite ).

  2. The other way is direct using libtiff in your application for saving TIFFs. Of course you need implement writing function in such case. For windows you should compile libtiff, but it is rather simple task (libtiff contains makefiles for many compilers and perfectly compiles in MinGW and MSVC, 32 and 64 bit).

According to the OpenCV documentation, cvSaveImage only supports 8bit single channel or BGR images. See 2.0 docs.

You should use libpng, libMagick++ or some other library to save in other bit depths and formats.

The libpng documentation contains a tutorial on how to write PNG images . To specify RGB with 16bit per channel data, use bit_depth = 16 and color_type = PNG_COLOR_TYPE_RGB.

To make your life (probably) a little easier, there is also png++ .

Edit: OpenCV seems to support writing 16bpc images in newer versions. See the answer from p.streef. Here's the link to the relevant documentation again.

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

In case anyone else runs across this avtomaton's solution seems to have been added via pull request https://github.com/opencv/opencv/pull/3744 ,

allowing you to do something like (works with 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);

My experience is that OpenCV saves images as 16 bit (didn't try with 3 channels). The pgm format definitely works and it is a real raw format (no run length compression).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM