【手撕算法】K-means算法实现主题色提取

在这里插入图片描述

K - Means是一种对图像进行聚类的算法,属于无监督分割聚类方法,这种方法不对聚类进行层次划分,只是通过分析聚类的性质和均值,将像素简单地划分为不相交的聚类。

今天结合一个在知乎看到的问题来说:

一张图片上有上百种颜色,如何在一张图上筛选出小于五种的基本色,或者在一张图上进行颜色划分归类?
为了做品牌,我们需要从符合品牌调性的图片中提取品牌色,但一张图片的颜色有上百种 我们怎么把这些颜色归类划分 提取呢?

有答友已经回答了该问题,我们今天就是C++实现K-means算法来解决这个问题。该问题链接:

https://www.zhihu.com/question/29268904

下图回答里的链接是python版代码,本文为C++代码。
在这里插入图片描述

1,K-means算法原理

K-means算法需要我们自己定义K值,如前面知乎的问题,需要提取图片的五种基本色,所以我们就定义K为5,即将图片分为5个簇。means是均值的意思,在本问题背景下,均值代表每个簇的颜色均值。

指定K值后,我们随机生成五个像素坐标,并取这五个像素坐标的颜色作为五个簇的初始均值。

需要注意的是,K-means算法关注的是图像的像素值,我们需要将各个簇包含的像素的像素值记录下来,而不是像素坐标。

然后我们开始迭代,迭代次数也是自己定义的,每一次迭代,我们都遍历图像所有像素,并计算该像素与各个簇的颜色均值的颜色距离,选择最接近的簇,将该像素值加入到此簇中(以便计算该簇新的均值)。

在一次遍历像素完毕后,都需要重新计算各个簇的颜色均值,并判断该新的均值与上次均值是否有差别,如果没有则说明收敛了,就无需继续迭代了。如果相差巨大,则需要再一次迭代。

如果需要再一次迭代,便将所有簇的元素清空,仅保留计算的均值,然后再一次遍历所有像素,重复上一步。

2,算法实现

主函数:读取图片,定义Kmeans算法的K值以及迭代次数,并对图片进行K-means算法。


int main()
{
  Mat srcImage;
  srcImage = imread("4.jpg",17);
  Mat dstImage(Size(100,600), CV_8UC3, Scalar(0,0,0));
  if (srcImage.empty())
  {
    printf_s("图片读取失败");
    return -1;
  }
  imshow(WINDOW_1, srcImage);

  int clusters_num = 5;//kmeans算法的k值
  int iterations = 10;//迭代次数
  KMean(srcImage, dstImage, clusters_num, iterations);
  imshow(WINDOW_2, dstImage);

  waitKey();
  return 0;
}

程序中用到了K-means算法函数

KMean(srcImage, dstImage, clusters_num, iterations);

此函数就实现了对输入图像srcImage 进行聚类操作,并将结果输出到dstImage参数中。clusters_num为K值,iterations为迭代次数。

除了K-means算法函数本身,程序还定义了一个簇类,用来存放簇的一些成员变量以及对簇的操作,例如向簇中添加一个像素,清空簇等等操作。

代码(详细注释)就不在这儿贴了,太长了,就放qq群【222954293】里了。

3,算法效果

试两张七龙珠的照片看一下效果:
在这里插入图片描述
在这里插入图片描述

4,THE END

本文所用代码是我以前在github上下的,也找不到原项目地址了。稍微改了一下末尾代码实现了K-means算法提取基本色的可视化。原代码是英文注释,我结合自己理解改成了中文注释。因为代码非原创,所以仅作学习分享。

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值