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
1.0k views
in Technique[技术] by (71.8m points)

opencv - Change type of Mat object from CV_32F to CV_8U

I tried to display an image of CV_32F type using imshow function but it showed a WHITE image. In the Documentation its given that floating point images will be mapped to 0-255 and displayed but it just showed a white image.I tried to convert it to CV_8U using

Mat A=Mat::ones(300,300,CV_32FC1)*1000;

do some processing - assigning float values to pixels in A

......

Mat B;

A.convertTo(B,CV_8U)

When I imshow 'B' i get a black & white image, there are no shades of gray. Are the float valued pixels in A properly mapped to 0-255 ? Am I doing anything wrong?

Few values in A are 1000 as initialized and rest are some floating point numbers which are assigned during processing.

See Question&Answers more detail:os

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

1 Reply

0 votes
by (71.8m points)

In OpenCV, if the image is of floating point type, then only those pixels can be visualized using imshow, which have value from 0.0 to 1.0, if the value is greater than 1.0, it will be shown as a white pixel and if less than 0.0, it will be shown as black pixel. To visualize a floating point image, scale its values to the range 0.0 - 1.0.

As for the conversion part.... When used with default arguments, the cv::Mat::convertTo function just creates a matrix of the specified type, and then copies the values from the source matrix and then rounds them to the nearest possible value of the destination data type. If the value is out of range, it is clamped to the minimum or maximum values.

In the documentation of imshow, it is written that:

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].

It means that only the values in the range 0.0 to 1.0 will be mapped to 0 to 255. If a value is greater than 1.0, and multiplied by 255, it will become greater than 255. Then it will be clamped to the range of CV_8U and eventually it will also become 255.

In your example, all the values which are 1000, will become 255 in the destination matrix as the destination type is CV_8U and the maximum possible value is 255. All the floating point values will be floored. No automatic mapping is done.

To appropriately map the values to the range of CV_8U use the 3rd and 4th parameters of the function cv::Mat::convertTo, so that the values are scaled before the conversion is done.

Suppose the matrix A has minimum and maximum values Min and Max, where Min!=Max.

To properly scale the values from 0 to 255, you can do the following:

if (Min!=Max){ 
    A -= Min;
    A.convertTo(B,CV_8U,255.0/(Max-Min));
}

You can also do this directly like this:

if (Min!=Max)
    A.convertTo(B,CV_8U,255.0/(Max-Min),-255.0*Min/(Max-Min));

(edited taking into account zhangxaochen's comment)


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

...