有很多方法可以量化颜色。这里我描述四个。在
均匀量子化
这里我们使用的是一个颜色均匀分布的颜色图,不管它们是否存在于图像中。在MATLAB语言中,你可以写qimg = round(img*(N/255))*(255/N);
将每个通道量化为N级(假设输入在范围[0255]内)。您还可以使用floor,这在某些情况下更合适。这导致N^3不同的颜色。例如,使用N=8可以得到512种唯一的RGB颜色。在
K均值聚类
这是生成自适应调色板的“经典”方法。显然这将是最贵的。OP正在对所有像素的集合应用k-means。相反,k-means可以应用于颜色直方图。这个过程是相同的,但是不是1000万个数据点(现在的典型图像),你可能只有32^3=3.3万。在处理自然照片时,由于直方图的减少而导致的量化效果很小。如果你量化一个图,它有一个有限的颜色集,你不需要做k-均值聚类。在
您只需对所有像素进行一次扫描,即可创建直方图。接下来,运行常规的k-means聚类,但要使用柱状图单元。每个数据点现在也有一个权重(在那个箱子里的像素数),你需要考虑这个权重。算法中确定簇中心的步骤受到影响。您需要计算数据点的加权平均值,而不是常规平均值。在
结果受初始化的影响。在
八叉树量化
八叉树是一种用于空间索引的数据结构,在这种结构中,通过将每个轴对分,将卷递归地分为8个子卷。因此,树由节点组成,每个节点有8个子节点。对于颜色量化,RGB立方体用八叉树表示,并计算每个节点的像素数(这相当于构建一个颜色直方图,并在此基础上构建一个八叉树)。接下来,叶节点被移除,直到剩下所需数量的叶节点。删除叶节点一次发生8个,这样一个节点上一级就变成了一个叶子。有不同的策略来选择要修剪的节点,但它们通常围绕着低像素数的节点进行修剪。在
这是Gimp使用的方法。在
因为八叉树总是从中间拆分节点,所以它不如k-means聚类或下一种方法灵活。在
最小方差量化
OP提到的MATLAB's ^{}进行统一量化,他们称之为“最小方差量化”:Minimum variance quantization cuts the RGB color cube into smaller boxes (not necessarily cubes) of different sizes, depending on how the colors are distributed in the image.
我不知道这意味着什么。This page没有提供更多信息,但它的图形看起来像是RGB立方体的k-d树分区。K-d树是一种空间索引结构,它递归地将空间数据分成两半。在每一个级别上,选择间隔最大的维度,并沿该维度拆分,从而产生一个额外的叶节点。与八叉树不同的是,分裂可以发生在一个最佳位置,而不是在节点的中间。在
使用空间索引结构(k-d树或八叉树)的优点是颜色查找非常快速。从根节点开始,根据R、G或B值进行二进制决定,直到到达叶节点。不需要像k-means那样计算到每个原型集群的距离。在
[两周后编辑]我一直在考虑一个可能的实现,并且came up with one。算法如下:全色直方图被视为一个分区。这将是k-d树的根,它现在也是叶节点,因为还没有其他节点。在
将创建优先级队列。它包含k-d树的所有叶节点。优先级由沿着一个轴划分,减去两半的方差,如果我们要沿着这个轴分割分区。选择分割位置,使两半的方差最小(使用Otsu算法)。也就是说,优先级越大,我们通过分割减少的总方差就越多。对于每个叶节点,我们计算每个轴的该值,并使用最大的结果。在
我们在队列上处理分区,直到获得所需的分区数:
我们沿着轴分割优先级最高的分区,并在确定优先级时计算的位置。在
我们计算两部分的优先级,并将它们放入队列中。在
这是一个相对简单的算法,当这样描述时,the code稍微复杂一些,因为我试图使其高效但通用。在
比较
在256x256x256的RGB直方图上,我比较了k均值聚类和这个新算法,得到了这些时间:
^{pr2}$
注意,k-means需要更多的迭代,因为集群的数量增加,因此指数时间增加。通常人们不会使用这么大的柱状图,我希望有大的数据,以使计时更稳健。在
以下是应用于测试图像的这三种方法的示例:
输入:
统一使用N=4导致多达64种不同的颜色[使用N=2得到8种不同的颜色,与其他方法相比,结果非常难看]:
8种颜色的K-均值:
新的8种颜色的“最小方差”:
我更喜欢最后一个结果,而不是K-means结果,尽管它们相当相似。在