使用cvtColor转换单个BGR颜色并使用结果从图像中提取该颜色 [英] Converting a single BGR color with cvtColor and using the result to extract that color from image

查看:107
本文介绍了使用cvtColor转换单个BGR颜色并使用结果从图像中提取该颜色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm using c++ but answers in python are fine too.

我需要将一种已知的BGR颜色转换为HSV,才能使用cv :: inRange方法,该方法允许您提取图像的特定部分.我已经有代码来估算我需要的BGR颜色,因此我认为我应该能够猜测它的范围.

I need to convert a known BGR color to HSV in order to use the cv::inRange method which allows you to extract a certain part of an image. I already have code that estimates the BGR color I need well enough so I thought I should be able to just guess around it's range.

所以我引用了此链接:使用cvtColor转换单一颜色似乎可以将BGR转换为HSV,尽管我仍然会得到一些奇怪的输出,如我将在后面解释的那样.

So I refereed to this link: Convert a single color with cvtColor which seems to work for converting an BGR to HSV, though I still got some weird output as I will explain later.

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

Anyways here is my code:

//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似乎是不正确的(我认为hue是0-179),所以我进行了2次转换以获得[112,56,126]应该是正确的吗?

So here is quick example: my code determines the approximate BGR color I want has values [126, 105, 98]. Converting to HSV intially gives [225, 0.22, 126] which seems to oddly be incorrect with how opencv stores hsv (like hue is 0-179 I think) so I do 2 conversions to get [112, 56, 126] which I think should be correct?

无论如何,当我尝试修改inRange函数中的值时,我并不能真正获得任何良好的提取效果,我倾向于得到黑屏(我测试了我的面罩是否可以正常工作,所以问题应该出在提供的代码).

Anyways when I try to tinker with values in my inRange function I can't really get any good extraction, I tend to just get a black screen (I tested that my mask works and it does so the issue should be in the code provided).

是否有更好的方法来执行此任务?

Is there a better way of going about this task?

推荐答案

您的第二次转换是正确的(嗯,如果您将其截断为int而不是四舍五入).

Your second conversion is correct (well, if you truncate to int instead of rounding).

您总是可以按照这是用Python编写的精确公式链接.抱歉,它不是C ++,但我写的是尽可能基本的代码,因此对于其他任何语言的人来说,它都是可以遵循的:

This is the exact formula linked written in Python. Sorry it's not C++ but I wrote it as basic as possible so it was followable for someone in any other language:

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

113 57 126

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

There are a few different methods you can employ to get good automatic values for color filtering. One method I like is to select an area that is the color you want, and finding the standard deviation and mean of those color values. That way you can easily set the lower and upper bounds of the inRange() function as mean-stddev and mean+stddev respectively. Or you can be less restrictive and multiply your standard deviation by some scalar, and you could choose which direction to be more or less choosy in. E.g., lowerb = mean - 3*stddev and upperb = mean + 1.5*stddev.

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

This can be super useful when say you have multiple ROIs with an object in the middle that you care about. You can filter out the colors that are in the border of each ROI separately using the mean and standard deviation of the border pixels!

这篇关于使用cvtColor转换单个BGR颜色并使用结果从图像中提取该颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆