Opencv 使用cvtColor转换单个BGR颜色,并使用结果从图像中提取该颜色
我使用C++,但是Python中的答案也很好。< /P> 我需要将已知的BGR颜色转换为HSV,以便使用cv::inRange方法来提取图像的特定部分。我已经有足够好的代码来估计我需要的BGR颜色,所以我想我应该能够猜测它的范围 所以我参考了这个链接:它似乎可以将BGR转换为HSV,尽管我仍然得到一些奇怪的输出,我将在后面解释 无论如何,这是我的代码:Opencv 使用cvtColor转换单个BGR颜色,并使用结果从图像中提取该颜色,opencv,Opencv,我使用C++,但是Python中的答案也很好。< /P> 我需要将已知的BGR颜色转换为HSV,以便使用cv::inRange方法来提取图像的特定部分。我已经有足够好的代码来估计我需要的BGR颜色,所以我想我应该能够猜测它的范围 所以我参考了这个链接:它似乎可以将BGR转换为HSV,尽管我仍然得到一些奇怪的输出,我将在后面解释 无论如何,这是我的代码: //store BGR values and convert BGR to HSV cv::Mat3f hairColor(cv::Vec3f(
//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值并将BGR转换为HSV
cv::Mat3f发色(cv::Vec3f(平均蓝色、平均绿色、平均色));
cv::Mat3f finalHSV;
cv::CVT颜色(发色、最终色、cv_BGR2HSV);
//使用cv::inRange函数将值更改为有效值(此部分为奇数)
最终值ptr(0)[0]/=2;
finalHSV.ptr(0)[1]*=255;
//将hsv值存储为整数
int averageHue=finalHSV.ptr(0)[0];
int averageSat=finalHSV.ptr(0)[1];
int averageValue=finalHSV.ptr(0)[2];
//尽量接近范围。我试图弄乱这些值,但无法校准它
int hueMin=平均色调-20;int hueMax=平均色调+100;
int saturationMin=平均值Sat-20;int saturationMax=平均Sat+20;
int valueMin=平均值-50;int valueMax=平均值+50;
//bw是我的掩码的输出数组。
cv::inRange(hsv,cv::Scalar(hueMin,saturationMin,valueMin),cv::Scalar(hueMax,saturationMax,valueMax),bw);
下面是一个简单的例子:我的代码确定了我想要的大致BGR颜色的值[12610598]。转换为HSV最初会得到[225,0.22,126],这似乎奇怪地与opencv存储HSV的方式不符(我认为色调是0-179),所以我做了两次转换以得到[112,56,126],我认为这应该是正确的
无论如何,当我尝试修补inRange函数中的值时,我无法真正获得任何好的提取,我倾向于得到一个黑屏(我测试了我的掩码是否工作,它是否工作,因此问题应该在提供的代码中)
有没有更好的方法来完成这项任务 您的第二次转换是正确的(如果您截断为
int
,而不是四舍五入)
您始终可以对中给出的值进行实际计算
这是用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)
b,g,r=12610598
b=b/255
g=g/255
r=r/255
v=最大值([b,g,r])
如果v为0:
s=0
其他:
s=(v-min([b,g,r]))/v
如果v是r:
h=60*(g-b)/(v-min([b,g,r]))
elif v是g:
h=120+60*(b-r)/(v-min([b,g,r]))
如果五是b:
h=240+60*(r-g)/(v-min([b,g,r]))
如果h<0:
h=h+360
v=np.round(255*v).aType(int)
s=np.round(255*s).aType(int)
h=np.round(h/2).aType(int)
打印(h、s、v)
113 57 126
有几种不同的方法可以用来为颜色过滤获得良好的自动值。我喜欢的一种方法是选择一个你想要的颜色区域,然后找到这些颜色值的标准偏差和平均值。这样,您可以轻松地将inRange()
函数的下限和上限分别设置为mean stddev
和mean+stddev
。或者你可以减少限制,用标准差乘以一些标量,你可以选择在哪个方向上更挑剔。例如,lowerb=mean-3*stddev
和upperb=mean+1.5*stddev
<>这可能是非常有用的,当你有多个ROI,中间有一个你关心的对象。您可以使用边界像素的平均值和标准偏差分别过滤出每个ROI边界中的颜色好的,我已经转换了这个部分,用C++来工作,但是看起来我没有得到我想要的颜色。使用cvInRange真的是提取特定颜色的唯一方法吗?如果是的话,提供良好范围的最佳方法是什么?是的,对于提取颜色,它正是您想要使用的。如果您希望一致地提取颜色,这取决于您的应用程序是什么以及一致性的含义。例如,对于许多应用程序来说,一种非常稳健的方法是在图像中找到具有该颜色的区域,找到该区域中颜色的平均值和标准偏差,然后使用
inRange()进行过滤
使用下限mean-n*stddev
和上限mean+n*stddev
wheren
让我们来选择要偏离特定颜色的标准偏差。Awesome只使用了一个区域的标准偏差提示,似乎在我的图像上改进了很多。谢谢你的帮助:)太好了!这是一种直观而得体的方法。一些直觉来自于对色彩空间的更好理解。例如,在HSV中,H通道表示原色,而S表示饱和度,V表示亮度,因此如果您试图获得相同的颜色,但在不同的着色条件下,你可能对S或V更宽容,但对H仍然有点严格。标准偏差技巧通过知道每个通道中预期的偏差量来为你解决这个问题。