App基于手机壳颜色换肤?完全做不到吗?这不就“做”出来了!

App基于手机壳颜色换肤?完全做不到吗?这不就“做”出来了!

程序员桌面必备杯垫.JPG

KMeans 算法

k -平均算法 (英文: k -means clustering)源于信号处理中的一种向量量化方法,现在则更多地作为一种聚类分析方法流行于数据挖掘领域。 k -平均聚类的目的是:把 n 个点(可以是样本的一次观察或一个实例)划分到 k 个聚类中,使得每个点都属于离他最近的均值(此即聚类中心)对应的聚类,以之作为聚类的标准。这个问题将归结为一个把数据空间划分为Voronoi cells的问题。

进群:548377875   即可获取数十套PDF哦!

App基于手机壳颜色换肤?完全做不到吗?这不就“做”出来了!

算法实现

public List<Scalar> extract(ColorProcessor processor) {

// initialization the pixel data

int width = processor.getWidth();

int height = processor.getHeight();

byte[] R = processor.getRed();

byte[] G = processor.getGreen();

byte[] B = processor.getBlue();

//Create random points to use a the cluster center

Random random = new Random();

int index = 0;

for (int i = 0; i < numOfCluster; i++)

{

int randomNumber1 = random.nextInt(width);

int randomNumber2 = random.nextInt(height);

index = randomNumber2 * width + randomNumber1;

ClusterCenter cc = new ClusterCenter(randomNumber1, randomNumber2, R[index]&0xff, G[index]&0xff, B[index]&0xff);

cc.cIndex = i;

clusterCenterList.add(cc);

}

// create all cluster point

for (int row = 0; row < height; ++row)

{

for (int col = 0; col < width; ++col)

{

index = row * width + col;

pointList.add(new ClusterPoint(row, col, R[index]&0xff, G[index]&0xff, B[index]&0xff));

}

}

// initialize the clusters for each point

double[] 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));

}

// calculate the old summary

// assign the points to cluster center

// calculate the new cluster center

// computation the delta value

// stop condition--

double[][] oldClusterCenterColors = reCalculateClusterCenters();

int times = 10;

while(true)

{

stepClusters();

double[][] newClusterCenterColors = reCalculateClusterCenters();

if(isStop(oldClusterCenterColors, newClusterCenterColors))

{

break;

}

else

{

oldClusterCenterColors = newClusterCenterColors;

}

if(times > 10) {

break;

}

times++;

}

//update the result image

List<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 point

double[] 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 now

for(int i=0; i<clusterCenterList.size(); i++)

{

clusterCenterList.get(i).numOfPoints = 0;

}

// recalculate the sum and total of points for each cluster

double[] 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);

clusterCenterList.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 中使用该算法来提取主色:

App基于手机壳颜色换肤?完全做不到吗?这不就“做”出来了!

demo1.png

App基于手机壳颜色换肤?完全做不到吗?这不就“做”出来了!

App基于手机壳颜色换肤?完全做不到吗?这不就“做”出来了!

猜你喜欢

转载自blog.csdn.net/qq_42156420/article/details/82115535