Search code examples
c++opencvopencv3.0hsv

Accidental quantization in BGR to HSV conversion


I am trying to convert a BGR image to HSV. When I write out the H channel of the conversion, it has a strange blocky structure that I'm guessing means something got accidentally quantized along the way. I tried converting my BGR unsigned char image to float first, but the result is the same. Here is my code:

// STL
#include <iostream>

// OpenCV
#include <opencv2/opencv.hpp>

void Float(const std::string& inputFilename)
{
    cv::Mat image = cv::imread(inputFilename, CV_LOAD_IMAGE_COLOR); // Loads as BGR

    cv::Mat floatImage;
    image.convertTo(floatImage, CV_32FC3);

    cv::Mat hsvImage;
    cv::cvtColor(floatImage, hsvImage, CV_BGR2HSV);

    std::vector<cv::Mat> hsvChannels;
    cv::split(hsvImage, hsvChannels);

    cv::imwrite("h_float.png", hsvChannels[0]);

}

void Original(const std::string& inputFilename)
{
    cv::Mat image = cv::imread(inputFilename, CV_LOAD_IMAGE_COLOR); // Loads as BGR

    cv::Mat hsvImage;
    cv::cvtColor(image, hsvImage, CV_BGR2HSV);

    std::vector<cv::Mat> hsvChannels;
    cv::split(hsvImage, hsvChannels);

    cv::imwrite("h_original.png", hsvChannels[0]);

}

int main(int argc, char* argv[])
{
    std::string inputFilename = argv[1];

    Original(inputFilename);
    Float(inputFilename);

    return EXIT_SUCCESS;
}

and here is the input: enter image description here

and the output (h_original.png): enter image description here

and the output (h_float.png): enter image description here

Any suggestion as to what I'm doing wrong here?


Solution

  • You are doing everything in the right way. I tried your image on my machine and got the same results. I think this result is due to the low color range of your image. This the result of the 3 channels of HSV. H and S suffer from this problem. However, V is smooth because it is about the light condition not the color.

    H-channel

    S-channel

    V-channel

    EDIT:

    To make my point clearer, see this image and the output using the same code:

    Original RGB

    H-channel

    S-channel

    V-channel

    Another EDIT (Black problem):

    In HSV: if V=0 then it is black whatever the rest S and H are. So to check if the color is black you have just to check the V component and there is no meaning if checking the other.

    Math proof:

    C = V × S
    X = C × (1 - |(H / 60º) mod 2 - 1|)
    m = V - C
    

    HSV-RGB

    It is clear that when V=0 and whatever H,S are, we will have: C=0 , X=0 which leads to R,G,B=(0,0,0)