检查颜色是不是接近
Posted
技术标签:
【中文标题】检查颜色是不是接近【英文标题】:Check if colors are close检查颜色是否接近 【发布时间】:2018-03-12 15:50:44 【问题描述】:-
我得到了一张这样的图片,我想将一些特殊类型的滤镜应用到:
-
我为深绿色区域(最大的区域)设置了 RGB 颜色 (
49, 76, 14
)。
所以我想获得某种阈值属性用于过滤目的:我想过滤每个图像像素以检查它的颜色是否接近给定的 RGB 值 (49, 76, 14
)。阈值表示偏移率。
Threshold small :
--> `(49, 76, 14) close to (48, 75, 13)`
--> `(49, 76, 14) "not" close to (50, 75, 13)`
Threshold big :
--> `(49, 76, 14) close to (48, 75, 13)`
--> `(49, 76, 14) "also" close to (50, 75, 13)`
过滤具有最小阈值的图像,只过滤给定的 rgb 颜色:
更大的阈值也会过滤给定 rgb 颜色附近的颜色:
如何实现编码一个能够检查一种颜色是否接近另一种颜色(+阈值属性)(+使用 rgb 值)的函数?
注意:
这是我在上面首先考虑的代码,但对其进行了测试 - 它并没有真正导致成功(通过过滤给定的值,左上角的小区域首先应该被过滤,因为它的颜色几乎看起来像给定的一。但是这段代码首先匹配的是灰色的,显然与给定的颜色不匹配!)
var offset = (threshold/100.0) * 255.0
var color = [r,g,b]
var r = redvalue, g = greenvalue, b = bluevalue
if !(
(r >= color[0]-offset) &&
(r <= color[0]+offset) &&
(g >= color[1]-offset) &&
(g <= color[1]+offset) &&
(b >= color[2]-offset) &&
(b <= color[2]+offset)
) // apply filter
任何帮助将不胜感激。一些用 Swift 或 JavaScript 甚至一些 PseudoCode 编写的源代码也可以。
编辑: 一个自发的想法是将 rgb-colors int lab-colors 转换为随后计算 欧几里得距离 来自两种颜色。但我不确定这个解决方案是否有效,也不确定它是否是最有效的解决方案:)
【问题讨论】:
有一些有趣的想法here 我编写了一个应用程序,通过将颜色的“距离”与命名颜色的规范 RGB 十六进制进行比较来命名图像中的颜色(ISTR 我使用了 X11 列表) - 我最终不得不这样做它在 HSL(色相饱和度亮度)而不是 RGB 中,色相的权重为 10 - 任意,但这似乎工作得很好。 能分享一些sn-ps的代码吗?:)
@Grimxn
我认为您将浮点值与整数混合,这会导致舍入错误,因为您在示例中显示的两种颜色与您比较的绿色具有相同的距离......48
和 @987654336 @ 与49
的距离相同...尝试使用offset = round((threshold/100.0) * 255.0);
或floor
或ceil
....我通常使用距离。您可以将颜色处理为 3D 向量,因此减去它们并计算距离...不需要 sqrt 您可以将距离^2 与阈值^2 进行比较...请参阅Detectings small circles on game minimap 我正是这样做的。
如果您需要更好的颜色检测,您可以使用 HSV,它处理颜色的方式更像人类感知。
【参考方案1】:
这不是一个完整的答案,而是对我在评论中提出的建议的详细说明,OP 要求我提供一些代码。
我有一个应用程序,它通过计算与 X11 三元组列表中的规范命名颜色的欧几里德距离来命名颜色(类似于 OP 试图做的事情,但目的不同)。正如他所做的那样,我发现使用 RGB 空间并不能给出直观的答案,因此我将每种颜色转换为色调饱和度亮度 (HSL) 维度,然后赋予色调维度比其他两个更高的权重。这是实际的“距离”代码,以及转换维度的支持函数:
private let oneThird = 1.0 / 3.0
private let twoThirds = 2.0 / 3.0
func hsl(red: Double, green: Double, blue: Double) -> (hue: Double, saturation: Double, lightness: Double)
let minv = min(red, green, blue)
let maxv = max(red, green, blue)
let diff = maxv - minv
let sum = maxv + minv
let l = sum * 0.5
var s = 0.0
var h = 0.0
if (diff > 0.0)
if (l < 0.5)
s = diff / sum
else
s = diff / (2.0 - sum)
let dr = (((maxv - red) / 6.0) + (diff / 2.0)) / diff
let dg = (((maxv - green) / 6.0) + (diff / 2.0)) / diff
let db = (((maxv - blue) / 6.0) + (diff / 2.0)) / diff
if red == maxv
h = db - dg
else if green == maxv
h = oneThird + dr - db
else if blue == maxv
h = twoThirds + dg - dr
return (modp(h, denominator: 1.0), s, l)
func modp<T: BinaryFloatingPoint>(_ numerator : T, denominator : T) -> T
// acts as fmod, but assures the result is positive between 0 and fabs(denominator)
let myDenominator = abs(denominator)
var myNumerator = numerator.remainder(dividingBy: myDenominator)
//var myNumerator = fmod(numerator, myDenominator)
while (myNumerator < 0) myNumerator += myDenominator
return myNumerator
let (h1, s1, l1) = hsl(red: r1, green: g1, blue: b1) // The reference colour
let (h2, s2, l2) = hsl(red: r2, green: g2, blue: b2) // The colour to be tested
let (dh, ds, dl) = (h1 - h2, s1 - s2, l1 - l2)
let hueWeight = 10 // Arbitrary, but works.
let distance = sqrt(hueWeight * dh * dh + ds * ds + dl * dl)
然后,您可以将您的 distance
值与您的阈值进行比较...
我认为 HSL 公式的原始来源是 here...
附言这些值我使用了Double
——那是因为我使用了我自己的颜色类型——如果你用UIColor
实现它,你最好使用CGFloat
s...
【讨论】:
【参考方案2】:您的“接近某个阈值”的概念与 色彩空间的color model 有关。
颜色模型具有三个或四个维度。 RGB
在 3 个维度(或组件)中运行。
以目标颜色为中心的半径为“阈值”的球体的想法还不错。如果您设置该球体的边界,请注意负坐标。
如果RGB
color 模型没有给您足够的“精度”,那么您可以更改为 CIELAB 或 HSL 模型;但是由于这些色彩空间中每个“维度”的含义不同,因此您需要同时使用多个阈值。
【讨论】:
如果您使用 HSL 而不是三个不同的阈值,则更多的是尺寸的 权重 的情况 - 权重可以固定 - 请参阅我对 OP 的评论。跨度>以上是关于检查颜色是不是接近的主要内容,如果未能解决你的问题,请参考以下文章
使用 shapely 和 geopandas 检查点列表是不是接近 python 中的线串列表的快速方法
当播放器与接近提示交互时,它会检查播放器是不是有工具,如果没有,则执行功能 -ROBLOX STUDIO