java实现:根据图片生成配色方案

本文介绍了如何使用Java实现根据图片自动生成配色方案的项目需求,选择了K-means聚类算法来完成。算法思路包括将RGB值映射到三维坐标,随机选取种子点,通过计算像素点与种子点的距离进行聚类,最终得到图片的主色调和配色方案。文章还提到了实现过程的关键步骤和内部类定义,并提供了源码(imageUtil.java)供参考。
摘要由CSDN通过智能技术生成

因为项目的需求,要做一个根据图片自动生成配色方案的功能。
网上查了文献大概有几种算法
1.K-means聚类算法
2.八叉树算法
3.最小差值法
4….
这里我选用了K-means算法,就不介绍K-means算法了。网上很多参考资料

先来介绍一下算法的思路:
将每个像素点的RGB值映射到xyz三维坐标中,这样相当于一张图片所有的像素点都分散在三维坐标当中

在图片上随机取N个点作为种子点,然后计算出图片上的所有像素点与这N个种子点的距离,每个像素点可以得到与其距离最近的种子点,就可以把该像素点加入到该种子点的点群中(这里体现了聚类的思想)。

遍历过整张图片后,每个像素都会加入到其中一个种子点群中(种子点群会记录下他拥有的全部像素点RGB总和,拥有的像素点个数),然后每个种子点群求得自己所拥有点的平均RGB值,作为新的种子点代替原来的种子结点。

重复这个过程,直到种子结点不再移动(收敛于某个RGB值)或者迭代次数超过阈值,最后得到的权重(点群中 点的数量)最高的RGB值便是图片的主色调, 也可以搭配权重前3的RGB值生成一套不错的配色方案

先看看效果图:
这里写图片描述

大概的流程是这样的:
定义了以下几个内部类

    //定义RGB像素点
    public class Point{
    int R;
    int G;
    int B;
    //..省略一些构造方法
    //计算两个RGB值的相似度 (根据方差)
    public int colorDistance(Point point){
        int absR = this.R - point.R;
        int absG = this.G - point.G;
        int absB = this.B - point.B;    
        return (int) Math.sqrt(absR*absR+absG*absG+absB*absB);
    }
    //..省略了一些重写的equls方法等


    //种子点群内部类
    public class PointGroup{
    int sumaryR = 0;
    int sumaryG = 0;
    int sumaryB = 0;
    int pointCount = 0;
    Point point;
    public void addPoint(Point point){
        this.sumaryR += point.R;
        this.sumaryG += point.G;
        this.sumaryB += point.B;
        pointCount++;
    }
    public Point getNewRGB(){
        Point newpoint = new Point();
        if(pointCount != 0 ){
            newpoint.R = sumaryR / pointCount;
            newpoint.G = sumaryG / pointCount;
            newpoint.B = sumaryB / pointCount;
        }else{
            newpoint= this.point;
        }
        return newpoint;
    }
}

1.按照比例获取图片上一定数量的点,筛选其中一些点作为种子点

    //得到图上上32*32个点放入集合中作为种子点群的备选点
    List<PointGroup> rootPoint = new ArrayList<PointGroup>();
    for(int i = 0; i < width; i += offsetWidth)
        for(int j = 0; j < height; j += offsetHeight){
            PointGroup pg = new PointGroup();
            //得到图片上坐标为(i,j)的RGB值
            pg.point = getRGB(i,j);
    }
    //设置相似颜色初始阈值
    int threshold = 6;
    //当前的种子点个数大于用户设置的上限时 提高阈值 以减少点的数量
    while(rootPoint.size() > rootPointNum){
        for(int i = 0; i < rootPoint.size(); i++)
            for(int j = i+1; j < rootPoint.size(); j++){
                if(rootPoint.get(i).point.colorDistance(rootPoint.get(j).point) < threshold){
                    rootPoint.remove(j);
                }

            }       
        //提高阈值
        threshold += 1;
    }

2.主循环

            //统计运算数次,当超过阈值时退出循环
            int count = 0;
            do{
            //遍历图片所有像素点,将每个点都加入与其最接近的种子点
            for(int i = 0; i < width ; i++)
                for(int j = 0; j < height; j++){
                    Point point = getRGB(i,j);
                    int index = 0;
                    int dis = 10000;
                    for (int m = 0; m < rootPoint.size() ; m++) {
                        //计算当前点与第m个种子点的距离
                        int curDis = point.colorDistance(rootPoint.get(m).point);
                        //如果距离小于最小距离 ,则替换最小距离并记录种子
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值