【发布时间】:2020-11-23 06:32:10
【问题描述】:
我有一个基线UIColor(见下文)。我怎么知道另一个UIColor 与我的基线UIColor 有多接近,在这个例子中假设.red 或.blue。
让我们忽略 alpha 通道。
最好我希望返回一个百分比,这样我就可以打印类似“.red color is a 40% match to your baseline color”之类的内容。
【问题讨论】:
我有一个基线UIColor(见下文)。我怎么知道另一个UIColor 与我的基线UIColor 有多接近,在这个例子中假设.red 或.blue。
让我们忽略 alpha 通道。
最好我希望返回一个百分比,这样我就可以打印类似“.red color is a 40% match to your baseline color”之类的内容。
【问题讨论】:
我将在这里回答我自己的问题...
根据这个How to compare two colors for similarity/difference,为了得到正确的人类感知色差值,我们需要将UIColor的RGB转换为Lab。然后使用 Lab,我们可以使用最新的 CIEDE2000 公式得到 deltaE(即两种颜色之间的差异)值。
这里是基于 awesome UIColor 扩展设置的 Swift 代码:https://github.com/jathu/sweetercolor/blob/master/Sweetercolor/Sweetercolor.swift
这将获得两种颜色之间的 deltaE:
/**
Detemine the distance between two colors based on the way humans perceive them.
Uses the Sharma 2004 alteration of the CIEDE2000 algorithm.
- parameter compare color: A UIColor to compare.
- returns: A CGFloat representing the deltaE
*/
func CIEDE2000(compare color: UIColor) -> CGFloat {
// CIEDE2000, Sharma 2004 -> http://www.ece.rochester.edu/~gsharma/ciede2000/ciede2000noteCRNA.pdf
func rad2deg(r: CGFloat) -> CGFloat {
return r * CGFloat(180/Double.pi)
}
func deg2rad(d: CGFloat) -> CGFloat {
return d * CGFloat(Double.pi/180)
}
let k_l = CGFloat(1), k_c = CGFloat(1), k_h = CGFloat(1)
let LAB1 = self.LAB
let L_1 = LAB1[0], a_1 = LAB1[1], b_1 = LAB1[2]
let LAB2 = color.LAB
let L_2 = LAB2[0], a_2 = LAB2[1], b_2 = LAB2[2]
let C_1ab = sqrt(pow(a_1, 2) + pow(b_1, 2))
let C_2ab = sqrt(pow(a_2, 2) + pow(b_2, 2))
let C_ab = (C_1ab + C_2ab)/2
let G = 0.5 * (1 - sqrt(pow(C_ab, 7)/(pow(C_ab, 7) + pow(25, 7))))
let a_1_p = (1 + G) * a_1
let a_2_p = (1 + G) * a_2
let C_1_p = sqrt(pow(a_1_p, 2) + pow(b_1, 2))
let C_2_p = sqrt(pow(a_2_p, 2) + pow(b_2, 2))
// Read note 1 (page 23) for clarification on radians to hue degrees
let h_1_p = (b_1 == 0 && a_1_p == 0) ? 0 : (atan2(b_1, a_1_p) + CGFloat(2 * Double.pi)) * CGFloat(180/Double.pi)
let h_2_p = (b_2 == 0 && a_2_p == 0) ? 0 : (atan2(b_2, a_2_p) + CGFloat(2 * Double.pi)) * CGFloat(180/Double.pi)
let deltaL_p = L_2 - L_1
let deltaC_p = C_2_p - C_1_p
var h_p: CGFloat = 0
if (C_1_p * C_2_p) == 0 {
h_p = 0
} else if fabs(h_2_p - h_1_p) <= 180 {
h_p = h_2_p - h_1_p
} else if (h_2_p - h_1_p) > 180 {
h_p = h_2_p - h_1_p - 360
} else if (h_2_p - h_1_p) < -180 {
h_p = h_2_p - h_1_p + 360
}
let deltaH_p = 2 * sqrt(C_1_p * C_2_p) * sin(deg2rad(d: h_p/2))
let L_p = (L_1 + L_2)/2
let C_p = (C_1_p + C_2_p)/2
var h_p_bar: CGFloat = 0
if (h_1_p * h_2_p) == 0 {
h_p_bar = h_1_p + h_2_p
} else if fabs(h_1_p - h_2_p) <= 180 {
h_p_bar = (h_1_p + h_2_p)/2
} else if fabs(h_1_p - h_2_p) > 180 && (h_1_p + h_2_p) < 360 {
h_p_bar = (h_1_p + h_2_p + 360)/2
} else if fabs(h_1_p - h_2_p) > 180 && (h_1_p + h_2_p) >= 360 {
h_p_bar = (h_1_p + h_2_p - 360)/2
}
let T1 = cos(deg2rad(d: h_p_bar - 30))
let T2 = cos(deg2rad(d: 2 * h_p_bar))
let T3 = cos(deg2rad(d: (3 * h_p_bar) + 6))
let T4 = cos(deg2rad(d: (4 * h_p_bar) - 63))
let T = 1 - rad2deg(r: 0.17 * T1) + rad2deg(r: 0.24 * T2) - rad2deg(r: 0.32 * T3) + rad2deg(r: 0.20 * T4)
let deltaTheta = 30 * exp(-pow((h_p_bar - 275)/25, 2))
let R_c = 2 * sqrt(pow(C_p, 7)/(pow(C_p, 7) + pow(25, 7)))
let S_l = 1 + ((0.015 * pow(L_p - 50, 2))/sqrt(20 + pow(L_p - 50, 2)))
let S_c = 1 + (0.045 * C_p)
let S_h = 1 + (0.015 * C_p * T)
let R_t = -sin(deg2rad(d: 2 * deltaTheta)) * R_c
// Calculate total
let P1 = deltaL_p/(k_l * S_l)
let P2 = deltaC_p/(k_c * S_c)
let P3 = deltaH_p/(k_h * S_h)
let deltaE = sqrt(pow(P1, 2) + pow(P2, 2) + pow(P3, 2) + (R_t * P2 * P3))
return deltaE
}
在上述函数 (func CIEDE2000) 中调用此函数以从 UIColor 中获取 Lab 颜色:
/**
Get the CIE L*ab values.
- returns: An array of three CGFloat numbers representing LAB respectively.
*/
var LAB: [CGFloat] {
// http://www.easyrgb.com/index.php?X=MATH&H=07#text7
let XYZ = self.XYZ
func LAB_helper(c: CGFloat) -> CGFloat {
return 0.008856 < c ? pow(c, 1/3) : ((7.787 * c) + (16/116))
}
let X: CGFloat = LAB_helper(c: XYZ[0]/95.047)
let Y: CGFloat = LAB_helper(c: XYZ[1]/100.0)
let Z: CGFloat = LAB_helper(c: XYZ[2]/108.883)
let L: CGFloat = (116 * Y) - 16
let A: CGFloat = 500 * (X - Y)
let B: CGFloat = 200 * (Y - Z)
return [L, A, B]
}
【讨论】:
您可以找到计算两种颜色之间距离的公式。
由于大多数色差定义是颜色空间内的距离,因此确定距离的标准方法是欧几里得距离。如果目前有一个 RGB(红、绿、蓝)元组并希望找到颜色差异,计算上最简单的方法之一是考虑定义颜色空间的 R、G、B 线性维度。
当结果在计算上也应该很简单时,通常可以接受去除平方根并简单地使用:
【讨论】:
deltaE 方法,但以获得更人类感知的准确结果。
试试这个:-
func testing(setColor: UIColor, myColor: UIColor)-> String{
var finalSum : Float = 0.0
for i in 0...2{
var sum = setColor.cgColor.components![i] - myColor.cgColor.components![i]
if sum < 0{
sum = -sum
finalSum = finalSum + Float(sum)
}else{
finalSum = finalSum + Float(sum)
}
}
return "Colors match \(Int(finalSum*100/3))%"
}
使用:-
print(testing(setColor: .blue, myColor: .brown))
我希望它对你有用:)
【讨论】: