Python 获得像素和颜色,如何获得包含所有像素和颜色的结构体?方法并不复杂,不过稍后你将看到,这种方法并不是最优解。
将像素映射到颜色的一种方法是使用product()
函数穷举所有像素和颜色。
xy = lambda xyp_c: xyp_c[0][0]
p = lambda xyp_c: xyp_c[0][1]
c = lambda xyp_c: xyp_c[1]
distances = (
(xy(item), p(item), c(item), euclidean(p(item), c(item)))
for item in product(pixel_iter(img), colors)
)
核心部分是使用product(pixel_iter(img), colors)
生成像素和颜色的所有组合,然后重构得到的数据使之扁平化,并使用euclidean()
函数算出像素颜色和Color
对象颜色之间的距离。返回结果是一个四元组序列,元组元素分别为:x-y
坐标、源像素点、给定颜色,以及像素颜色到给定颜色间的距离。
最后使用groupby()
函数和min(choices, ...)
表达式得到颜色结果,如下所示:
for _, choices in groupby(
distances, key=lambda xy_p_c_d: xy_p_c_d[0]):
yield min(choices, key=lambda xypcd: xypcd[3])
像素和颜色做乘积运算得到一个很长的一维可迭代对象,按照其中的坐标值进行分组,将其分解为一组相对较短的可迭代对象,每个对应一个像素,然后选出距离最短的颜色。
在一幅包含133种Crayola色彩的、尺寸为3648×2736的图像中,上面的算法需要迭代计算1 327 463 424次。是的,distances
表达式生成了数十亿计的组合,这个规模还不至于无法计算,Python尚能处理,但足以体现简单直接地使用produce()
函数会出现问题。
进行大规模数据处理时,必须估算规模。运行100万次距离计算后,用timeit()
函数测出的运行时间如下:
- 欧氏距离:2.8
- 曼哈顿距离:1.8
扩大1000倍,从运行100万次到运行10亿次,曼哈顿距离计算需要1800秒,即半小时,欧氏距离计算则需要46分钟。对于大型数据集,这种计算方法效率太低了。
更重要的是,这种做法是错误的。这种“宽度×高度×颜色”的直接处理是糟糕的算法设计,很多情况下有更好的方案。