0

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.

stateMachine
  • 5,227
  • 4
  • 13
  • 29
rain 183
  • 11
  • 3
  • Have you tried with `cv::COLOR_BGR2HSV_FULL`? And are you sure you don't need `cv::COLOR_RGB2HSV_FULL` instead? You can find the full list of color conversion codes [here](https://docs.opencv.org/3.4/d8/d01/group__imgproc__color__conversions.html). – 303 Dec 27 '21 at 01:57
  • 1
    It depends on what HSV range you are working on. OpenCV defines the `Hue` range in `[0,180)` to store the Hue values in a `uint8`. However, the "theoretical" Hue range is defined as `[0, 360]`. The `HSV` you are printing lies in OpenCV's "reduced" range. By using the color code `BGR2HSV_FULL` you are using the full range. So, both values should map the same color, it just depends on what range you are using. Additional tip: You are processing a `jpeg `. This image format is lossy and will modify the values of your pixels due to compression. Use `png` to create lossless images. – stateMachine Dec 27 '21 at 03:36
  • So you re expecting hsv output similar to bgr output ? – Yunus Temurlenk Dec 27 '21 at 06:45

1 Answers1

0

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.

Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36