Save the whole CV_32S image with OpenCV

I work with TIF images containing signed integer data. After successfully inputting one and processing it, I need to output the image in the same format (input and output of both * .tif files).

For input, I know that OpenCV does not know whether the data is signed or not, so it accepts unsigned. Using this trick solves this problem (by manually switching the cv::Mat type).

However, when I output the image and load it again, I do not get the expected result. The file contains several segments (groups of pixels), and the format is as follows ( I have to use this format ):

  • all pixels that do not belong to any segment have a value of -9999
  • all pixels belonging to the same segment have the same positive integer value
  • (for example, all pixels of the 1st segment have the value 1 , the second 2 , etc.)

And here is a sample code:

 void ImageProcessor::saveSegments(const std::string &filename){ cv::Mat segmentation = cv::Mat(workingImage.size().height, workingImage.size().width, CV_32S, cv::Scalar(-9999)); for (int i=0, szi = segmentsInput.size(); i < szi; ++i){ for (int j=0, szj = segmentsInput[i].size(); j < szj; ++j){ segmentation.at<int>(segmentsInput[i][j].Y, ssegmentsInput[i][j].X) = i+1; } } cv::imwrite(filename, segmentation); } 

You can assume that all variables (e.g. workingImage , segmentsInput ) exist as global variables.

Using this code, when I enter an image and look at the values, most of the values ​​are set to 0 , and those that are set take the full range of integer values ​​(in my example, I had 20 segments).

+7
c ++ image opencv
source share
2 answers

You cannot save whole matrices directly with imwrite. As the documentation says: "Only 8-bit (or 16-bit unsigned (CV_16U) in the case of PNG, JPEG 2000 and TIFF) single-channel or 3-channel (with BGR channel order) can be saved using this function."

However, what could you do to convert the CV_32S matrix to CV_8UC4 and save it as PNG without compression. Of course, this is a little unsafe, since endianness comes into play and can change your values ​​between different systems or compilers (especially since we are talking about signed integers here). If you always use the same system and compiler, you can use this:

 cv::Mat segmentation = cv::Mat(workingImage.size().height, workingImage.size().width, CV_32S, cv::Scalar(-9999)); cv::Mat pngSegmentation(segmentation.rows, segmentation.cols, CV_8UC4, (cv::Vec4b*)segmentation.data); std::vector<int> params; params.push_back(CV_IMWRITE_PNG_COMPRESSION); params.push_back(0); cv::imwrite("segmentation.png", pngSegmentation, params); 
+1
source share

I also save opencv mats as tifs, but I do not use opencv tif. I enable libtiff lib myself (I think libtiff is also used in opencv) and you can use the following code to save as tiff

 TIFF* tif = TIFFOpen("file.tif", "w"); if (tif != NULL) { for (int i = 0; i < pages; i++) { TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, TIFF_UINT64_T(x)); // set the width of the image TIFFSetField(tif, TIFFTAG_IMAGELENGTH, TIFF_UINT64_T(y)); // set the height of the image TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); // set number of channels per pixel TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32); // set the size of the channels 32 for CV_32F TIFFSetField(tif, TIFFTAG_PAGENUMBER, i, pages); TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); // for CV32_F for (uint32 row = 0; row < y; row++) { TIFFWriteScanline(tif, &imageDataStack[i].data[row*x*32/ 8], row, 0); } TIFFWriteDirectory(tif); } } 

imageDataStack is a vector of cv :: Mat objects. This code works for me to save tiff stacks.

0
source share

All Articles