opencvimage-processingfile-iofloating-pointhdrimages

Writing a float image in openCv with pixel values bigger than 1


I am currently working on a program which should take an LDR images and multiply certain pixel in the image, so that their pixel value would exceed the normal 0-255 (0-1) pixel value boundary. The program i have written can do so, but I am not able to write the image file, as the imwrite() in OpenCV clambs the values back in the range of 0-255 (0-1) if they are bigger than 255.

Is there anybody there who knows how to write a floating point image with pixel values bigger than 255 (1)

My code looks like this

Mat ApplySunValue(Mat InputImg)
{
 Mat Image1 = imread("/****/.jpg",CV_LOAD_IMAGE_COLOR);

Mat outPutImage;

Image1.convertTo(Image1, CV_32FC3);

for(int x = 0; x < InputImg.cols; x++){
    for(int y = 0; y < InputImg.rows; y++){

        float blue  = Image1.at<Vec3f>(y,x)[0] /255.0f;
        float green = Image1.at<Vec3f>(y,x)[1] /255.0f;
        float red = Image1.at<Vec3f>(y,x)[2] /255.0f ;

        Image1.at<Vec3f>(y,x)[0] = blue;
        Image1.at<Vec3f>(y,x)[1] = green;
        Image1.at<Vec3f>(y,x)[2] = red;

        int pixelValue = InputImg.at<uchar>(y,x);

        if(pixelValue > 254){


            Image1.at<Vec3f>(y,x)[0] = blue * SunMultiplyer;
            Image1.at<Vec3f>(y,x)[1] = green * SunMultiplyer;
            Image1.at<Vec3f>(y,x)[2] = red * SunMultiplyer;    
        }

    }

}

imwrite("/****/Nice.TIFF", Image1 * 255);

namedWindow("Hej",CV_WINDOW_AUTOSIZE);
imshow("hej", Image1);



return InputImg;
}

Solution

  • For storage purposes, the following is more memory efficient than the XML / YAML alternative (due to the use of a binary format):

    // Save the image data in binary format
    std::ofstream os(<filepath>,std::ios::out|std::ios::trunc|std::ios::binary);
    os << (int)image.rows << " " << (int)image.cols << " " << (int)image.type() << " ";
    os.write((char*)image.data,image.step.p[0]*image.rows);
    os.close();
    

    You can then load the image as follows:

    // Load the image data from binary format
    std::ifstream is(<filepath>,std::ios::in|std::ios::binary);
    if(!is.is_open())
        return false;
    int rows,cols,type;
    is >> rows; is.ignore(1);
    is >> cols; is.ignore(1);
    is >> type; is.ignore(1);
    cv::Mat image;
    image.create(rows,cols,type);
    is.read((char*)image.data,image.step.p[0]*image.rows);
    is.close();
    

    For instance, without compression, a 1920x1200 floating-point three-channel image takes 26 MB when stored in binary format, whereas it takes 129 MB when stored in YML format. This size difference also has an impact on runtime since the number of accesses to the hard drive are very different.

    Now, if what you want is to visualize your HDR image, you have no choice but to convert it to LDR. This is called "tone-mapping" (Wikipedia entry).