<Machine Learning in Action >之四 二分k-均值算法 C#实现图像分割

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using System.Collections.Generic;

namespace K_means
{
    public partial class Form1 : Form
    {
        const int pictureSize = 640 * 480;
        const int k = 3;                             //质心的数量
        Color[] arrayColor = new Color[pictureSize];        //数据集
        int[,] resultArray = new int[pictureSize, 2];   //存储每个点的簇分配结果及与质心的距离
        int[,] centArray = new int[k, 4];    //存储质心
        int[,] tmpcentArray = new int[k, 4];

        public Form1()
        {
            InitializeComponent();
            pictureBox1.ImageLocation = "test.jpg";
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Bitmap map = new Bitmap(pictureBox1.Image);
            for (int j = 0; j < map.Height; j++)
            {
                for (int i = 0; i < map.Width; i++)
                {
                    arrayColor[j * map.Width + i] = map.GetPixel(i, j);
                }
            }
            new Thread(new ThreadStart(kmeans)).Start();
        }

        private void button1_Resize(object sender, EventArgs e)
        {
            this.Width = 800;
            this.Height = 600;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            Bitmap map = new Bitmap(pictureBox1.Image);
            Bitmap newmap = map;
            Color color = new Color();
            Color newcolor = new Color();
            Byte r, g, b, gray;
            for (int j = 0; j < map.Height; j++)
            {
                for (int i = 0; i < map.Width; i++)
                {
                    color = map.GetPixel(i, j);
                    r = color.R;
                    g = color.G;
                    b = color.B;
                    if (r + g + b != 0)
                    {
                        gray = (Byte)((r * 19595 + g * 38469 + b * 7472) >> 16);
                        newcolor = Color.FromArgb(gray, gray, gray);
                        newmap.SetPixel(i, j, newcolor);
                    }
                }
            }
            pictureBox1.Image = newmap;
        }

        private int getDistance(int[,] a, Color b, int i)
        {
            return (int)Math.Sqrt(Math.Pow(a[i, 0] - b.R, 2) + Math.Pow(a[i, 1] - b.G, 2) + Math.Pow(a[i, 2] - b.B, 2) + Math.Pow(a[i, 3] - b.A, 2));
        }

        private void kmeans()
        {
            DateTime dt = DateTime.Now;
            for (int i = 0; i < k; i++)   //初始k个随机质心,颜色取值不看数据集了,直接0-255
            {
                tmpcentArray[i, 0] = centArray[i, 0] = new Random(BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0)).Next(0, 256);
                tmpcentArray[i, 1] = centArray[i, 1] = new Random(BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0)).Next(0, 256);
                tmpcentArray[i, 2] = centArray[i, 2] = new Random(BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0)).Next(0, 256);
                tmpcentArray[i, 3] = centArray[i, 3] = new Random(BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0)).Next(0, 256);
            }
            while (true)
            {
                for (int i = 0; i < arrayColor.Length; i++)       //遍历数据集中每个点并簇分配
                {
                    int minDistance = getDistance(centArray, arrayColor[i], 0);
                    int count = 0;
                    for (int j = 1; j < k; j++)
                    {
                        int tmpDistance = getDistance(centArray, arrayColor[i], j);
                        if (minDistance > tmpDistance)
                        {
                            minDistance = tmpDistance;
                            count = j;
                        }
                    }
                    resultArray[i, 0] = count;
                    resultArray[i, 1] = minDistance;
                }
                for (int j = 0; j < 3; j++)      //计算新的质心
                {
                    int r = 0;
                    int g = 0;
                    int b = 0;
                    int a = 0;
                    int m = 0;
                    for (int i = 0; i < arrayColor.Length; i++)
                    {
                        if (resultArray[i, 0] == j)
                        {
                            r += arrayColor[i].R;
                            g += arrayColor[i].G;
                            b += arrayColor[i].B;
                            a += arrayColor[i].A;
                            m++;
                        }
                    }
                    if (m != 0)
                    {
                        centArray[j, 0] = r / m;
                        centArray[j, 1] = g / m;
                        centArray[j, 2] = b / m;
                        centArray[j, 3] = a / m;
                    }
                    this.Invoke(new MethodInvoker(() => { this.label1.Text = centArray[j, 0] + "\r\n" + centArray[j, 1] + "\r\n" + centArray[j, 2] + "\r\n" + centArray[j, 3] + "\r\n" + (DateTime.Now - dt).TotalSeconds; }));
                }
                bool isBreak = true;
                for (int i = 0; i < k; i++)    //检测质心是否还有变化
                {
                    for (int j = 0; j < 4; j++)
                    {
                        if (tmpcentArray[i, j] != centArray[i, j])
                        {
                            isBreak = false;
                            break;
                        }
                    }
                }
                if (isBreak)           //质心不变就可以退出了
                {
                    break;
                }
                else
                {
                    for (int i = 0; i < k; i++)    //保存上一轮计算出的质心
                    {
                        for (int j = 0; j < 4; j++)
                        {
                            tmpcentArray[i, j] = centArray[i, j];
                        }
                    }
                }
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            Bitmap map = new Bitmap(pictureBox1.Width, pictureBox1.Height);
            for (int j = 0; j < map.Height; j++)
            {
                for (int i = 0; i < map.Width; i++)
                {
                    if (resultArray[j * map.Width + i, 0] == 0)
                    {
                        map.SetPixel(i, j, Color.Red);
                    }
                    else if (resultArray[j * map.Width + i, 0] == 1)
                    {
                        map.SetPixel(i, j, Color.Green);
                    }
                    else if (resultArray[j * map.Width + i, 0] == 2)
                    {
                        map.SetPixel(i, j, Color.Yellow);
                    }
                }
            }
            pictureBox1.Image = map;
        }
    }
}

代码随便写的,没啥优化,那个二分k-means有些细节还没弄清楚,只好先用一般的k-means做了 ,效果就看下面吧。

时间: 2024-08-10 21:28:50

<Machine Learning in Action >之四 二分k-均值算法 C#实现图像分割的相关文章

二分-k均值算法

首先我们都知道k均值算法有一个炒鸡大的bug,就是在很多情况下他只会收敛到局部最小值而不是全局最小值,为了解决这个问题,很多学者提出了很多的方法,我们在这里介绍一种叫做2分k均值的方法. 该算法首先将所有点作为一个簇,然后将该簇一分为二.之后选择其中一个簇继续进行划分,选择哪一个簇进行划分取决于哪个簇的sse是最大值.上述基于sse的划分过程不断重复,直到得到用户指定的簇数目为止. 将所有的点看成一个簇,当粗的数目小于k时,对每一个簇计算总误差,在给定的粗上进行k均值聚类(k=2),计算将该粗一

Machine Learning In Action 第二章学习笔记: kNN算法

本文主要记录<Machine Learning In Action>中第二章的内容.书中以两个具体实例来介绍kNN(k nearest neighbors),分别是: 约会对象预测 手写数字识别 通过“约会对象”功能,基本能够了解到kNN算法的工作原理.“手写数字识别”与“约会对象预测”使用完全一样的算法代码,仅仅是数据集有变化. 约会对象预测 1 约会对象预测功能需求 主人公“张三”喜欢结交新朋友.“系统A”上面注册了很多类似于“张三”的用户,大家都想结交心朋友.“张三”最开始通过自己筛选的

Machine Learning in Action -- Support Vector Machines

虽然SVM本身算法理论,水比较深,很难懂 但是基本原理却非常直观易懂,就是找到与训练集中支持向量有最大间隔的超平面 形式化的描述: 其中需要满足m个约束条件,m为数据集大小,即数据集中的每个数据点function margin都是>=1,因为之前假设所有支持向量,即离超平面最近的点,的function margin为1 对于这种有约束条件的最优化问题,用拉格朗日定理,于是得到如下的形式, 现在我们的目的就是求出最优化的m个拉格朗日算子,因为通过他们我们可以间接的算出w和b,从而得到最优超平面 考

【机器学习实战】Machine Learning in Action 代码 视频 项目案例

MachineLearning 欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远 Machine Learning in Action (机器学习实战) | ApacheCN(apache中文网) 视频每周更新:如果你觉得有价值,请帮忙点 Star[后续组织学习活动:sklearn + tensorflow] ApacheCN - 学习机器学习群[629470233] 第一部分 分类 1.) 机器学习基础 2.) k-近邻算法 3.) 决策树 4.) 基于概率论的分类方法:朴素

Machine Learning In Action

The mind-road of "Machine Learning In Action". Read though the book totally by English!!

Machine Learning—k-nearest neighbor classification(k近邻分类)

印象笔记同步分享:Machine Learning-k-nearest neighbor classification(k近邻分类)

k-均值聚类算法;二分k均值聚类算法

根据<机器学习实战>一书第十章学习k均值聚类算法和二分k均值聚类算法,自己把代码边敲边理解了一下,修正了一些原书中代码的细微差错.目前代码有时会出现如下4种报错信息,这有待继续探究和完善. 报错信息: Warning (from warnings module): File "F:\Python2.7.6\lib\site-packages\numpy\core\_methods.py", line 55 warnings.warn("Mean of empty

DM里的K均值算法

1.Preface 因为一直在做的是聚类算法的研究,算是总结了一些心得,这里总结些知识性与思路性的东西,我想在其他地方也是很容易的找到类似的内容的.毕竟,世界就是那么小. 声明:本文比较不适合没有DM基础的人来阅读.我只是胡乱的涂鸦而已 2.聚类算法 在DM里的聚类算法里,有基于划分的算法,基于层次的算法,基于密度的算法,基于网格的算法,基于约束的算法. 其中每一种基于的算法都会衍生出一至几种算法,对应的每一种算法不管在学术界还是工业界都存在着许多的改进的算法 这里想介绍的是基于基于划分的算法里

k均值算法

import matplotlib.pyplot as plt import numpy as np import time from django.template.defaultfilters import center def loadDataSet(fileName): dataMat=[] fr=open(fileName) for line in fr.readlines(): curLine=line.strip().split('\t') fltLine=map(float,cu