检查颜色是否接近

时间:2018-03-12 15:50:44

标签: javascript ios swift algorithm colors

  1. 我有一个这样的图片,我想在其上应用一些特殊类型的过滤器
  2. img0

    1. 我为深绿色区域(最大的区域)获得了RGB颜色(49, 76, 14)。
    2. 所以我想为我的过滤目的获得某种阈值属性:我想过滤每个图像像素以检查它的颜色是否接近给定的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颜色的图像将被过滤:

      img1

      更大的阈值也会过滤给定rgb颜色附近的颜色:

      img2

        

      如何实现编码能够检查一种颜色是否接近另一种颜色(+阈值属性)(+使用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 转换为以后计算欧氏距离< / strong>来自两种颜色。但是我不确定这个解决方案是否有效,而且如果它是最有效的解决方案,那也不行:)

2 个答案:

答案 0 :(得分:0)

您的“接近某个阈值”的概念与色彩空间color model有关。

颜色模型有三维或四维。 RGB以3维(或组件)运作。

让半径为“阈值”的球体以目标颜色为中心的想法并不错。如果设置该球体的边界,请注意负坐标。

如果RGB颜色模型没有给你足够的“精度”,那么你可以改为CIELAB或HSL模型;但是,由于这些颜色空间中每个“维度”的含义不同,您需要同时使用多个阈值。

答案 1 :(得分:0)

这不是一个完整的答案,而是详细说明我在评论中提出的建议,即OP要求我提供一些代码。

我有一个应用程序,通过计算X11三元组列表中规范命名颜色的欧几里德距离来命名颜色(类似于OP尝试做但出于不同目的)。我发现,正如他所做的那样,使用RGB空间并没有给出直观的答案,因此我将每种颜色转换为色调饱和度(HSL)尺寸,然后给予Hue尺寸比其他两种颜色更高的权重。这是实际的“距离”代码,以及用于转换尺寸的支持函数:

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...

P.S。我已经将Double用于这些值 - 因为我使用的是自己的颜色类型 - 如果您使用UIColor实现它,那么您最好使用CGFloat ..