Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Save integer CV_32S image with OpenCV

Tags:

c++

image

opencv

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

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

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

  • all pixels not belonging to any segment have the value -9999
  • all the pixels belonging to a single segment have the same positive integer value
  • (e.g. all pixels of 1st segment have value 1, second 2 etc)

And here is the example 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 the variables (e.g. workingImage, segmentsInput) exist as global variables.

Using this code, when I input the image and examine the values, most of the values are set to 0 while the ones that are set take a full range of integer values (in my example I had 20 segments).

like image 430
penelope Avatar asked Jul 28 '16 14:07

penelope


1 Answers

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

However, what you could do it to convert your CV_32S matrix to a CV_8UC4 and save it as a PNG with no compression. Of course, this is a bit unsafe since endianness comes into play and may change your values between different systems or compilers (especially since we're talking about signed integers here). If you use always 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);
like image 79
Sunreef Avatar answered Sep 20 '22 12:09

Sunreef