写点什么

App 基于手机壳颜色换肤?先尝试一下用 KMeans 来提取图像中的主色

用户头像
Android架构
关注
发布于: 刚刚

break;}times++;}


//update the result imageList<Scalar> colors = new ArrayList<Scalar>();for(ClusterCenter cc : clusterCenterList) {


colors.add(cc.color);}return colors;}


private boolean isStop(double[][] oldClusterCenterColors, double[][] newClusterCenterColors) {boolean stop = false;for (int i = 0; i < oldClusterCenterColors.length; i++) {if (oldClusterCenterColors[i][0] == newClusterCenterColors[i][0] &&oldClusterCenterColors[i][1] == newClusterCenterColors[i][1] &&oldClusterCenterColors[i][2] == newClusterCenterColors[i][2]) {stop = true;break;}}return stop;}


/**


  • update the cluster index by distance value*/private void stepClusters() {// initialize the clusters for each pointdouble[] clusterDisValues = new double[clusterCenterList.size()];for(int i=0; i<pointList.size(); i++){for(int j=0; j<clusterCenterList.size(); j++){clusterDisValues[j] = calculateEuclideanDistance(pointList.get(i), clusterCenterList.get(j));}pointList.get(i).clusterIndex = (getCloserCluster(clusterDisValues));}


}


/**


  • using cluster color of each point to update cluster center color

  • @return*/private double[][] reCalculateClusterCenters() {


// clear the points nowfor(int i=0; i<clusterCenterList.size(); i++){clusterCenterList.get(i).numOfPoints = 0;}


// recalculate the sum and total of points for each clusterdouble[] redSums = new double[numOfCluster];double[] greenSum = new double[numOfCluster];double[] blueSum = new double[numOfCluster];for(int i=0; i<pointList.size(); i++){int cIndex = (int)pointList.get(i).clusterIndex;clusterCenterList.get(cIndex).numOfPoints++;int tr = pointList.get(i).pixelColor.red;int tg = pointList.get(i).pixelColor.green;int tb = pointList.get(i).pixelColor.blue;redSums[cIndex] += tr;greenSum[cIndex] += tg;blueSum[cIndex] += tb;}


double[][] oldClusterCentersColors = new double[clusterCenterList.size()][3];for(int i=0; i<clusterCenterList.size(); i++){double sum = clusterCenterList.get(i).numOfPoints;int cIndex = clusterCenterList.get(i).cIndex;int red = (int)(greenSum[cIndex]/sum);int green = (int)(greenSum[cIndex]/sum);int blue = (int)(blueSum[cIndex]/sum);cluster


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


CenterList.get(i).color = new Scalar(red, green, blue);oldClusterCentersColors[i][0] = red;oldClusterCentersColors[i][0] = green;oldClusterCentersColors[i][0] = blue;}


return oldClusterCentersColors;}


/***


  • @param clusterDisValues

  • @return*/private double getCloserCluster(double[] clusterDisValues) {double min = clusterDisValues[0];int clusterIndex = 0;for(int i=0; i<clusterDisValues.length; i++){if(min > clusterDisValues[i]){min = clusterDisValues[i];clusterIndex = i;}}return clusterIndex;}


/***


  • @param p

  • @param c

  • @return distance value*/private double calculateEuclideanDistance(ClusterPoint p, ClusterCenter c) {int pr = p.pixelColor.red;int pg = p.pixelColor.green;int pb = p.pixelColor.blue;int cr = c.color.red;int cg = c.color.green;int cb = c.color.blue;return Math.sqrt(Math.pow((pr - cr), 2.0) + Math.pow((pg - cg), 2.0) + Math.pow((pb - cb), 2.0));}


在 Android 中使用该算法来提取主色:




完整的算法实现可以在:github.com/imageproces… 找到,它是一个典型的 KMeans 算法。


我们的算法中,K 默认值是 5,当然也可以自己指定。

以上算法目前在 demo 上耗时蛮久,不过可以有优化空间。例如,可以使用 RxJava 在 computation 线程中做复杂的计算操作然后切换回 ui 线程。亦或者可以使用类似 Kotlin 的 Coroutines 来做复杂的计算操作然后切换回 ui 线程。总结

提取图像中的主色,还有其他算法例如八叉树等,在 Android 中也可以使用 Palette 的 API 来实现。cv4j?是gloomyfish和我一起开发的图像处理库,纯 java 实现,我们已经分离了一个 Android 版本和一个 Java 版本。如果您想看该系列先前的文章可以访问下面的文集: www.jianshu.com/nb/10401400最后提醒一句,作为程序员,还是要多健身。

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
App基于手机壳颜色换肤?先尝试一下用 KMeans 来提取图像中的主色