- 实现环境:python
处理一张红苹果图:
先描述一下中位切割算法吧:
- 将图片内的所有像素加入到同一个区域
- 对于所有的区域做以下的事:
- 计算此区域内所有像素的 RGB 三元素最大值与最小值的差。
- 选出相差最大的那个颜色(R 或 G 或 B)
- 根据那个颜色去排序此区域内所有像素
- 分割前一半与后一半的像素到二个不同的区域(这里就是“中位切
割”名字的由来) - 重复第二步直到你有 256 个区域
- 将每个区域内的像素平均起来,于是你就得到了 256 色
于是根据维基百科的算法描述先是实现了一个 cube 的类用于进行区域的筛选,
cube.py:
from statistics import mean
class Cube(object):
def __init__(self, colors):
self.colors = colors or []
self.red = [r[0] for r in colors]
self.green = [g[1] for g in colors]
self.blue = [b[2] for b in colors]
self.size = (max(self.red) - min(self.red),
max(self.green) - min(self.green),
max(self.blue) - min(self.blue))
self.range = max(self.size)
self.channel = self.size.index(self.range)
def __lt__(self, other):
return self.range < other.range
def average(self):
r = int(mean(self.red))
g = int(mean(self.green))
b = int(mean(self.blue))
return r, g, b
def split(self):
middle = int(len(self.colors) / 2)
colors = sorted(self.colors, key=lambda c: c[self.channel])
return Cube(colors[:middle]), Cube(colors[middle:])
main 函数借助 Cube 类实现了对图像中像素 rgb 值对应 LUT 的匹配:
main.py
from PIL import Image
from cube import Cube
import numpy as np
import matplotlib.pyplot as plt
def median_cut(img, num):
colors = []
for count, color in img.getcolors(img.width * img.height):
colors += [color]
cubes = [Cube(colors)]
while len(cubes) < num:
cubes.sort()
cubes += cubes.pop().split()
i = 0
LUT = {}
index = ()
for c in cubes:
average = c.average()
for color in c.colors:
LUT[color] = average
return LUT
def main() :
image = Image.open('E://Desktop//duomeiti//redapple.jpg')
LUT = median_cut(image, 256)
img = np.array(image)
rows,cols,channel=img.shape
for i in range(rows):
for j in range(cols):
index = (img[i,j,0],img[i,j,1],img[i,j,2])
color = LUT[index]
img[i,j] = color
plt.imshow(img)
plt.axis('off')
plt.savefig('result3.jpg')
plt.show()
if __name__ == "__main__":
main()
结果示例:
如果将颜色表提取出来效果如下:
(因256色带是在太大csdn无法显示,故只截取了一部分)