使用cvtColor转换单个BGR颜色并使用结果从图像中提取该颜色

时间:2017-07-04 02:38:58

标签: opencv

我正在使用c ++但是python中的答案也很好。

我需要将已知的BGR颜色转换为HSV才能使用cv :: inRange方法,该方法允许您提取图像的某个部分。我已经有了能够很好地估算出我需要的BGR颜色的代码,所以我想我应该可以猜测它的范围。

所以我对这个链接进行了评价:Convert a single color with cvtColor这似乎可以用于将BGR转换为HSV,但我仍然会得到一些奇怪的输出,我稍后会解释。

无论如何,这是我的代码:

//store BGR values and convert BGR to HSV
cv::Mat3f hairColor(cv::Vec3f(averageBlue, averageGreen, averageRed));
cv::Mat3f finalHSV;
cv::cvtColor(hairColor, finalHSV, CV_BGR2HSV);

//change values to be valid with the cv::inRange function (find this part odd)
finalHSV.ptr<float>(0)[0] /= 2;
finalHSV.ptr<float>(0)[1] *= 255;

//store hsv values as integers
int averageHue = finalHSV.ptr<float>(0)[0];
int averageSat = finalHSV.ptr<float>(0)[1];
int averageValue = finalHSV.ptr<float>(0)[2];

//try to appromimate ranges. I'm trying to mess wtih these values but can't calibrate it whatsoever
int hueMin = averageHue - 20;   int hueMax = averageHue + 100;
int saturationMin = averageSat - 20;    int saturationMax = averageSat + 20;
int valueMin = averageValue - 50;   int valueMax = averageValue + 50;


//bw is the output array for my mask.
cv::inRange(hsv, cv::Scalar(hueMin, saturationMin, valueMin), cv::Scalar(hueMax, saturationMax, valueMax), bw);

所以这是一个简单的例子:我的代码确定了我想要的近似BGR颜色值[126,105,98]。最初转换为HSV给出了[225,0.22,126]这似乎与opencv如何存储hsv(如我认为的色调是0-179)一样奇怪,所以我做了2次转换得到[112,56,126]我认为应该是正确的吗?

无论如何,当我尝试修改我的inRange函数中的值时,我无法真正得到任何好的提取,我倾向于只是得到一个黑屏(我测试我的掩码工作,它确实问题应该在代码提供)。

有没有更好的方法来完成这项任务?

1 个答案:

答案 0 :(得分:0)

您的第二次转换是正确的(如果您截断为int而不是舍入)。

您可以随时对OpenCV docs for cvtColor中给出的值进行实际计算。

这是用Python编写的确切公式链接。对不起,它不是C ++,但是我尽可能地写了它,所以对于任何其他语言的人来说都是可以接受的:

b, g, r = 126, 105, 98

b = b/255
g = g/255
r = r/255

v = max([b, g, r])

if v is 0:
    s = 0
else: 
    s = (v-min([b, g, r]))/v


if v is r:
    h = 60*(g-b)/(v-min([b,g,r]))
elif v is g:
    h = 120 + 60*(b-r)/(v-min([b,g,r]))
elif v is b:
    h = 240 + 60*(r-g)/(v-min([b,g,r]))

if h < 0:
    h = h + 360

v = np.round(255*v).astype(int)
s = np.round(255*s).astype(int)
h = np.round(h/2).astype(int)

print(h,s,v)
  

113 57 126

您可以使用几种不同的方法来获得色彩过滤的良好自动值。我喜欢的一种方法是选择一个你想要的颜色区域,找到这些颜色值的标准偏差和平均值。这样,您可以轻松地将inRange()函数的下限和上限分别设置为mean-stddevmean+stddev。或者你可以减少限制并将你的标准偏差乘以某个标量,你可以选择更多或更少挑选的方向。例如,lowerb = mean - 3*stddevupperb = mean + 1.5*stddev

当您说有多个ROI且中间有您关心的对象时,这可能非常有用。您可以使用边框像素的平均值和标准偏差分别过滤掉每个ROI边框中的颜色!