Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
525 views
in Technique[技术] by (71.8m points)

c++ - Saving an image with imwrite in opencv writes all black but imshow shows correctly

Original Question

This example code will display the image created correctly, but will save a png with only black pixels. The Mat is in CV_32FC3 format, so 3 channels of floats.

The answered questions I've found deal with image manipulation issues or converting incorrectly or saving in jpeg with various compression.

#include "opencv2/highgui/highgui.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    int i = 0;
    int j = 0;

    Vec3f intensity;
     cv::Mat imageF;
    imageF= cv::Mat::zeros(36,36,CV_32FC3);

    for(j=0;j<imageF.cols;++j){
    for(i=0;i<imageF.rows;++i){
        intensity = imageF.at<Vec3f>(j, i);
        intensity.val[2] = 0.789347;
        intensity.val[1] = 0.772673;
        intensity.val[0] = 0.692689;
        imageF.at<Vec3f>(j, i) = intensity;
    }}
    imshow("Output", imageF);  
    imwrite("test.png", imageF);

    waitKey(0);
    return 0;
}

What changes need to be made to make it save as expected?

Berriel's Solution

#include "opencv2/highgui/highgui.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main() {
    int i = 0;
    int j = 0;

    Vec3f intensity;
    cv::Mat imageF;
    cv::Mat image;
    imageF= cv::Mat::zeros(36,36,CV_32FC3);

    for(j=0; j<imageF.cols; ++j) {
        for(i=0; i<imageF.rows; ++i) {
            intensity = imageF.at<Vec3f>(j, i);
            intensity.val[2] = 0.789347;
            intensity.val[1] = 0.772673;
            intensity.val[0] = 0.692689;
            imageF.at<Vec3f>(j, i) = intensity;
            }
        }

    imshow("Output", imageF);

    Mat3b imageF_8UC3;
    imageF.convertTo(imageF_8UC3, CV_8UC3, 255);
    imwrite("test.png", imageF_8UC3);

    waitKey(0);
    return 0;
    }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As you can read in the documentation:

The function imwrite saves the image to the specified file. The image format is chosen based on the filename extension (see imread() for the list of extensions). 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. If the format, depth or channel order is different, use Mat::convertTo() , and cvtColor() to convert it before saving.

You should use convertTo to convert from CV_32FC3 to CV_8UC3 to get the same result:

Mat3b imageF_8UC3;
imageF.convertTo(imageF_8UC3, CV_8UC3, 255);
imwrite("test.png", imageF_8UC3);

By the way, imshow() displays correctly because...

  • If the image is 8-bit unsigned, it is displayed as is.
  • If the image is 16-bit unsigned or 32-bit integer, the pixels are divided by 256. That is, the value range [0,255*256] is mapped to [0,255].
  • If the image is 32-bit floating-point, the pixel values are multiplied by 255. That is, the value range [0,1] is mapped to [0,255].

Basically, the same trick is what you need to do before writing.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...