same picture 2 different mean colors in opencv

264 views Asked by At

I'm working on an opencv 4.5.2 on windows10, my code is supposed to recognize colors. I met a porblem while scanning a simple picture 20x20 which the colour is defintely red.

enter image description here

when I run the following snippet

#include<opencv2/opencv.hpp>
#include<iostream>
const std::string imgpath = "C:\\Users\\nicola\\Desktop\\c++\\qt\\FaceScanner\\FaceScanner\\images\\";

int main()
{
    cv::Mat origin = cv::imread(imgpath+"square_red.jpg");
    cv::Mat hsv;
    cv::cvtColor(origin, hsv, cv::COLOR_BGR2HSV);
    cv::Scalar color = cv::mean(hsv);
    std::cout << "HSV: " << color[0] << " " << color[1] << " " << color[2] << "\n";
    color = cv::mean(origin);
    std::cout << "BGR: " << color[0] << " " << color[1] << " " << color[2] << "\n";
}

the output I'm getting is

HSV: 88.4 251.532 238.768
BGR: 8.96 3.52 238.768

The problem is that this 2 colors are different because hsv(88, 251, 238) is a kind of green while bgr(8, 3, 238) is the red I'm expecting. To process the color I need it in the hsv color space. Can anybody fiugre this out? thank you in advance.

1

There are 1 answers

0
Christoph Rackwitz On

You can't just ask for the mean of hue angles.

The arithmetic mean doesn't make sense on angles. Not in this case.

Your picture is red. Red has a hue angle of around 0. Add some noise, because JPEG and whatnot. That gets you values around 0, with some small positive and some small negative values... except, the negative ones won't be negative after cvtColor, they'll be around 359! 359 because 360 degrees in a circle. But wait! OpenCV returns hue angles mapped to 0 .. 179 because 359 doesn't fit in an uint8. So you have some values around 0 and some around 179.

Then you're averaging some 0 and some 179... and you get your 88.4, which is close to 90, which makes mathematical sense, but the value (180 degrees, green-blue) is complete nonsense, as you noticed.

Instead, do the averaging in RGB/BGR or YUV space. There it makes sense, i.e. is well defined.

Once you have the mean in a color space where it can be calculated, then you can use cvtColor to convert it. I'm not terribly familiar with the C++ API of OpenCV, so if cvtColor doesn't eat Scalars as is, stick the Scalar into a Mat.