颜色量子化(K-Means聚合算法以及八叉树的运用)

本文介绍了颜色量子化的概念,包括图像主要颜色提取和由图像生成调色板。通过K-Means算法进行颜色聚类,实现图像主要颜色的提取,同时探讨了8叉树在生成调色板中的应用,详细阐述了建树过程和减少叶子节点以保持颜色数据的方法。
摘要由CSDN通过智能技术生成

颜色量子化,又可以理解为图像主要颜色提取或者由图像生成调色板。归根结底,就是对一组颜色进行筛选处理,进而选择出其中具有代表性的N个颜色。

下面我们从两个应用场景来对该主题进行讲述:

一、图像主要颜色提取

假设场景

现在假设一种场景:从一张图片中提取n个主要颜色。

该场景下颜色的量子化可以使用聚合算法,集合算法是一种用于把一组数据进行分类为几个分组的算法。在我们设想的场景中,就是将一组颜色数据分类为几个分组,并获取到每个分组所代表的颜色。

解决方案

聚合算法有很多种实现方式,其中比较经典的一种实现方式是K-Means聚类算法,K-Means算法的基本思想是:以空间中k个点为质点进行聚类,对最靠近他们的对象归类。通过迭代的方法,逐次更新各簇的质点的值,直至得到最好的聚类结果。

大致流程如下:

K-Means聚合算法流程

以下是一个简单的示意图:

K-Means聚合算法示意图

其中,对于分类时所用到的距离,我们可以计算数据点到质点的欧式距离

欧式距离

欧氏距离是一个通常采用的距离定义,指在m维空间中两个点之间的真实距离,或者向量的自然长度(即该点到原点的距离)。在二维和三维空间中的欧氏距离就是两点之间的实际距离。

  1. 欧式距离二维空间表达式

    欧式距离二维空间表达式

  2. 欧式距离三维空间表达式

    欧式距离三维空间表达式

  3. 欧式距离n维空间表达式

    欧式距离n维空间表达式

算法实现

类比到我们假设的场景中,就是输入一组以RGB表示的颜色数据,然后对这些颜色数据进行归类,接下来我们用代码来实现该算法:

1. 首先定义一个结构体来表示颜色
typedef struct MDMColor {
    NSUInteger red;
    NSUInteger green;
    NSUInteger blue;
} MDMColor;
2. 定义一个表示点的结构体
typedef struct MDMNode {
    MDMColor color;
    NSUInteger i;
} MDMNode;

该结构体有两个用途:

  • 表示颜色数据所在的点,其中color就是颜色数据,i表示所属质点。
  • 表示质点数据,其中color表示质点类下所有颜色数据中RGB颜色的总量,i表示分类下颜色数据的个数。
3. 算法方法入口
/**
 通过k-means算法来进行颜色量子化
 @param colorArray 需要进行量子化的颜色数据
 @param count 需要进行量子化的颜色数据个数
 @param maxCount 需要量子化得到的颜色个数

 @return 量子化之后的颜色数据
 */
+ (MDMColor *)calculateColorTableWithColorArray:(MDMColor *)colorArray count:(NSUInteger)count maxCount:(NSUInteger)maxCount;
4. 随机生成第一次聚合所需要的质点
//生成所需质点
for (NSUInteger i = 0; i < maxCount; i++) {
    NSUInteger index = arc4random() % count;
    MDMColor tmpColor = colorArray[index];
    MDMColor color;
    color.red = tmpColor.red;
    color.green = tmpColor.green;
    color.blue = tmpColor.blue;
    colorTable[i] = color;
}
5. 遍历数据,对数据进行分类
for (NSUInteger i = 0; i < count; i++) {
    MDMColor color = colorArray[i];
    NSUInteger index = 0;
    CGFloat minDis = CGFLOAT_MAX;
    for (NSUInteger j = 0; j < maxCount; j++) {
        MDMColor anotherColor = colorTable[j];
        CGFloat dis = [self calculateDisWithColor:color anotherColor:anotherColor];
        index = minDis > dis ? j : index;
        minDis = minDis > dis ? dis : minDis;
        if (minDis < __FLT_EPSILON__) {
            break;
        }
    }
    materialPoint[index].color.red += color.red;
    materialPoint[index].color.green += color.green;
    materialPoint[index].color.blue += color.blue;
    materialPoint[index].i += 1;
}

其中,colorTable表示此次迭代中所有质点所在位置;materialPoint表示此次迭代中,每个质点所包含的分类数据(所有所属颜色数据RGB的总量以及颜色数据数量)。

6. 更新质点数据
for (NSUInteger i = 0; i < maxCount; i++) {
   
    MDMNode node = materialPoint[i];
    if (node.i != 0) {
        colorTable[i].red = node.color.red / node.i;
        colorTable[i].green = node.color.green / node.i;
        colorTable[i].blue = node.color.blue / node.i;
    }
}

获取该质点所属分类下所有颜色数据,并求取所有RGB总量的平均值来作为新质点的位置。

7. 重复迭代步骤5、6
8. 结束条件
CGFloat maxDis = 0;
for (NSUInteger i = 0; i < maxCount; i++) {
   
    MDMNode node = materialPoint[i];
    MDMColor color;
    color.red = colorTable[i].red;
    color.green = colorTable[i].green
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值