Python 计算距离,许多最优策略问题需要找到满足精度要求的近似解,即不能简单地判断值是否相等,而要采用某种距离测量算法,找到距离目标最近的元素。例如对于文本分析,可以采用Levenshtein距离,即从一段给定文本到目标文本需要做的变换次数的最小值。
下面举例说明,其中会涉及浅显的数学知识。虽然这个例子很简单,但要得到理想的结果仍应避免使用一些过于简单直接的算法。
处理颜色匹配问题通常不做精确的相等测试,因为很难检验像素颜色是否完全相同。我们往往先定义一个最短距离公式,然后计算两个颜色是否足够接近,但不要对像素的R、G和B都取同样的值。常用的距离计算公式包括欧氏距离、曼哈顿距离以及其他基于不同视觉偏好的复合加权计算公式。
欧氏距离和曼哈顿距离的计算公式如下:
import math
def euclidean(pixel: RGB, color: Color) -> float:
return math.sqrt(
sum(map(
lambda x, y: (x-y)**2,
pixel,
color.rgb)
)
)
def manhattan(pixel: RGB, color: Color) -> float:
return sum(map(
lambda x, y: abs(x-y),
pixel,
color.rgb)
)
欧氏距离表示RGB空间中某点与原点构成的直角三角形斜边的长度,曼哈顿距离则是直角三角形各边长度之和。欧氏距离精度高,曼哈顿距离计算速度快。
后续示例的数据结构比较类似,对每个特定的像素,计算其与给定颜色(属于一个由有限颜色组成的集合)的距离,结果如下所示:
(
((0, 0), (92, 139, 195), Color(rgb=(239, 222, 205), name='Almond'), 169.10943202553784),
((0, 0), (92, 139, 195), Color(rgb=(255, 255, 153), name='Canary'), 204.42357985320578),
((0, 0), (92, 139, 195), Color(rgb=(28, 172, 120), name='Green'),
103.97114984456024),
((0, 0), (92, 139, 195), Color(rgb=(48, 186, 143), name='Mountain Meadow'), 82.75868534480233),
((0, 0), (92, 139, 195), Color(rgb=(255, 73, 108), name='Radical Red'), 196.19887869200477),
((0, 0), (92, 139, 195), Color(rgb=(253, 94, 83), name='Sunset Orange'), 201.2212712413874),
((0, 0), (92, 139, 195), Color(rgb=(255, 174, 66), name='Yellow Orange'), 210.7961100210343)
)
计算结果是一个四元组集合,每个元素包含如下内容:
- 像素的坐标,例如
(0, 0)
; - 像素的颜色,例如
(92, 139, 195)
; - 7种颜色集合中的某个
Color
对象,例如Color(rgb=(239, 222, 205),name= 'Almond')
; - 像素颜色与给定
Color
对象间的欧氏距离。
不难发现欧氏距离的最小值就是最接近的匹配颜色,通过在归约中使用min()
函数可以方便地得到这个值。当把上面的颜色元组赋给choices
变量时,像素级的归约实现如下:
min(choices, key=lambda xypcd: xypcd[3])
用xypcd
代表每个四元组,也就是坐标、像素、颜色和距离。距离的最小值表示给定像素的最佳匹配颜色。