Search code examples
opencvhsv

OpenCV cvtColor CV_BGR2HSV CV_32FC3 Saturation Range


I'm trying to build histograms for materials in OpenCV 3.2 but am confused by the HSV ranges--they don't seem to match the documentation, or I am approaching it wrong.

// cv::Mat bgrPhoto contains a test image

cv::Mat3f hsvPhoto;
bgrPhoto.convertTo(hsvPhoto, CV_32FC3);
cv::cvtColor(hsvPhoto, hsvPhoto, CV_BGR2HSV, CV_32FC3);
std::vector<cv::Mat1f> hsvChannels;
cv::split(hsvPhoto, hsvChannels);

// Documentation [0.0, 1.0]: measured here Hue to 360.0, Sat to 1.0, Val to 255.0
double minHue, maxHue, minSat, maxSat, minVal, maxVal;
cv::minMaxIdx(hsvChannels[0], &minHue, &maxHue, 0, 0);
cv::minMaxIdx(hsvChannels[1], &minSat, &maxSat, 0, 0);
cv::minMaxIdx(hsvChannels[2], &minVal, &maxVal, 0, 0);

Solution

  • When you converted your image from 8-bit to 32-bit, you haven't scaled your values from [0, 255] to [0, 1]. convertTo() simply converts the types; it doesn't rescale the values by default. This is affecting your output since, from the docs for color conversion from BGR to HSV, V simply gets set to max(B, G, R) (which will be a max of numbers going up to 255). You'll notice that in the docs for cvtColor() it says for 8-bit and 16-bit images, they are scaled to fit the [0, 1] range; but not for float images. However, the H channels and S channels still get scaled to the correct ranges because they use V to scale the image.

    When you do bgrPhoto.convertTo(hsvPhoto, CV_32FC3) you need to divide by 255 to set the values into [0, 1]. If you check out the docs for convertTo() you'll notice a third positional argument can be set which is a scale factor. Simply using bgrPhoto.convertTo(hsvPhoto, CV_32FC3, 1.0/255.0) will, as the documentation states, scale every pixel value by that factor.

    Also, Miki's point in the comment on the OP totally slipped by me but it was a great catch; check the docs for cvtColor(); the fourth argument is an argument for number of destination channels, not dtype, so cv::cvtColor(hsvPhoto, hsvPhoto, CV_BGR2HSV) is what you want.