Пример #1
0
        public void getNodesCenter()
        {
            double sensorX  = 0;
            double sensorY  = 0;
            double halfRad  = PublicParameters.clusterRadius / 2;
            double clusterX = this.clusterLocMargin.X + halfRad;
            double clusterY = this.clusterLocMargin.Y + halfRad;

            clusterActualCenter = new Point(clusterX, clusterY);


            double sumX = 0;
            double sumY = 0;
            double n    = clusterNodes.Count;

            foreach (Sensor sensor in this.clusterNodes)
            {
                sensorX += sensor.CenterLocation.X;
                sensorY += sensor.CenterLocation.Y;
            }


            sumX = (double)clusterX + (sensorX / n);
            sumY = (double)clusterY + (sensorY / n);

            sumX = sumX / 2;
            sumY = sumY / 2;

            //double marginTop = Math.Floor(clusterY - this.clusterLocMargin.Y) - label_clustercenter.Height/2;
            // double marginLeft =Math.Floor( clusterX - this.clusterLocMargin.X) - label_clustercenter.Width/2;


            clusterCenterMargin = new Point(sumX, sumY);
            ClusterCenter center = new ClusterCenter(clusterCenterMargin, this.getID());

            this.centerOfCluster = center;

            clusterCenterComputed = new Point(sumX, sumY);
        }
Пример #2
0
        /// <summary>
        /// The greater the value of M,
        /// the more spatial proximity is emphasized and the more compact the cluster,
        /// M should be in range of 1 to 20.
        /// </summary>
        public static int[] ClusterPixels(ReadOnlySpan <Rgba32> pixels, int width, int height,
                                          int clusters, float m = 10, int maxIterations = 10, bool enforceConnectivity = true)
        {
            if (clusters < 2)
            {
                throw new ArgumentException("Number of clusters should be more than 1");
            }

            //Grid interval S
            float S = MathF.Sqrt(pixels.Length / (float)clusters);

            int[] clusterIndices = new int[pixels.Length];

            var labXys = ConvertToLabXy(pixels, width, height);


            Span <ClusterCenter> clusterCenters  = InitialClusterCenters(width, height, clusters, S, labXys);
            Span <ClusterCenter> previousCenters = new ClusterCenter[clusters];

            float       Error     = 999;
            const float threshold = 0.1f;
            int         iter      = 0;

            while (Error > threshold)
            {
                if (maxIterations > 0 && iter >= maxIterations)
                {
                    break;
                }
                iter++;

                clusterCenters.CopyTo(previousCenters);

                Array.Fill(clusterIndices, -1);

                // Find closest cluster for pixels
                for (int j = 0; j < clusters; j++)
                {
                    int xL = Math.Max(0, (int)(clusterCenters[j].x - S));
                    int xH = Math.Min(width, (int)(clusterCenters[j].x + S));
                    int yL = Math.Max(0, (int)(clusterCenters[j].y - S));
                    int yH = Math.Min(height, (int)(clusterCenters[j].y + S));

                    for (int x = xL; x < xH; x++)
                    {
                        for (int y = yL; y < yH; y++)
                        {
                            int i = x + y * width;

                            if (clusterIndices[i] == -1)
                            {
                                clusterIndices[i] = j;
                            }
                            else
                            {
                                float prevDistance = clusterCenters[clusterIndices[i]].Distance(labXys[i], m, S);
                                float distance     = clusterCenters[j].Distance(labXys[i], m, S);
                                if (distance < prevDistance)
                                {
                                    clusterIndices[i] = j;
                                }
                            }
                        }
                    }
                }

                Error = RecalculateCenters(clusters, m, labXys, clusterIndices, previousCenters, S, ref clusterCenters);
            }

            if (enforceConnectivity)
            {
                clusterIndices = EnforceConnectivity(clusterIndices, width, height, clusters);
            }

            return(clusterIndices);
        }
Пример #3
0
        /// <summary>
        /// ISO Data分类算法。
        /// </summary>
        /// <param name="InputDS">输入的数据集。</param>
        /// <param name="MinKind">最小分类数。</param>
        /// <param name="MaxKind">最大分类数。</param>
        /// <param name="MaxItera">最大迭代次数。</param>
        /// <param name="CenterDiff">最大中心变化率</param>
        /// <param name="MinPixelNumInClass">类内最小像元数。</param>
        /// <param name="MaxClassStddev">最大类内标准差</param>
        /// <param name="MinClassDist">最小类间距离。</param>
        /// <param name="OutPath">结果数据集输出路径。</param>
        /// <returns>操作成功或失败。</returns>
        public static bool IsoData(OSGeo.GDAL.Dataset InputDS, int MinKind, int MaxKind, int MaxItera, double CenterDiff, int MinPixelNumInClass, double MaxClassStddev, double MinClassDist, string OutPath)
        {
            try
            {
                if (InputDS == null)
                {
                    throw new ArgumentNullException("输入数据集为空。");
                }
                if (String.IsNullOrWhiteSpace(OutPath.Trim()))
                {
                    throw new ArgumentNullException("输出路径为空或非法。");
                }
                OSGeo.GDAL.Driver Dri = OSGeo.GDAL.Gdal.GetDriverByName("Gtiff");
                if (Dri == null)
                {
                    throw new Exception("无法获取GDAL Driver。");
                }

                int bandNum = InputDS.RasterCount;
                int xSize   = InputDS.RasterXSize;
                int ySize   = InputDS.RasterYSize;

                FrmProgress FP = new FrmProgress()
                {
                    Text = "正在进行ISO Data分类...",
                };

                Thread t = new Thread(() =>
                {
                    FP.ShowDialog();
                });
                t.SetApartmentState(ApartmentState.STA);
                t.Start();

                OSGeo.GDAL.Dataset DS = Dri.Create(OutPath, xSize, ySize, 1, OSGeo.GDAL.DataType.GDT_Byte, null);
                FP.Output("已创建输出数据集\"" + OutPath + "\",数据类型为GDT_Byte。");
                Tools.Common.CopyMetadata(InputDS, DS);

                int  tmpItera    = 1;
                bool tmpContinue = true;

                double[]             min      = new double[bandNum];
                double[]             max      = new double[bandNum];
                double[]             mean     = new double[bandNum];
                double[]             stddev   = new double[bandNum];
                int                  InitKind = (MinKind + MaxKind) / 2;
                List <ClusterCenter> ICenter  = new List <ClusterCenter>();

                //计算数据集各波段统计数据
                for (int i = 0; i < bandNum; i++)
                {
                    Tools.Common.GetStatistics(InputDS.GetRasterBand(i + 1), out min[i], out max[i], out mean[i], out stddev[i]);
                }

                //初始化聚类中心
                for (int i = 0; i < InitKind; i++)
                {
                    ICenter.Add(new ClusterCenter(bandNum));
                    for (int band = 0; band < bandNum; band++)
                    {
                        ICenter[i].NewCenter[band] = ICenter[i].OldCenter[band] = mean[band] + stddev[band] - 2 * i * stddev[band] / InitKind;
                    }
                }

                //循环体
                while (tmpContinue)
                {
                    FP.Output("正在迭代第" + tmpItera.ToString() + "次...");
                    FP.SetProgress2("正在迭代:", tmpItera, MaxItera, "次");
                    //清空所有聚类中心的和、平均值、标准差、像元列表
                    foreach (ClusterCenter C in ICenter)
                    {
                        C.ResetAll();
                    }

                    //重置所有类的像元计数为0
                    for (int i = 0; i < ICenter.Count; i++)
                    {
                        ICenter[i].PixelCount = 0;
                    }

                    for (int i = 0; i < ICenter.Count; i++)
                    {
                        string tmpCenter = "第" + (i + 1).ToString() + "类中心:";
                        for (int band = 0; band < bandNum; band++)
                        {
                            tmpCenter += ICenter[i].OldCenter[band] + ", ";
                        }
                        FP.Output(tmpCenter);
                    }

                    //遍历数据集每一行
                    for (int row = 0; row < ySize; row++)
                    {
                        FP.SetProgress1("正在处理:", row + 1, ySize, "行");
                        double[][] tmpInput = new double[bandNum][];    //用于存储输入像元的交错数组

                        //将一行的所有波段像元值读取入交错数组
                        for (int band = 0; band < bandNum; band++)
                        {
                            tmpInput[band] = new double[xSize];
                            InputDS.GetRasterBand(band + 1).ReadRaster(0, row, xSize, 1, tmpInput[band], xSize, 1, 0, 0);
                        }

                        byte[] tmpOut = new byte[xSize];    //用于存储输出像元的数组

                        //遍历一行的每一列,对像元分类
                        for (int col = 0; col < xSize; col++)
                        {
                            double[] tmpPix = new double[bandNum];  //临时存储单个像元所有波段的数组

                            //将指定行列的所有波段像元转储到数组
                            for (int band = 0; band < bandNum; band++)
                            {
                                tmpPix[band] = tmpInput[band][col];
                            }

                            double[] tmpDis = new double[ICenter.Count]; //单个像元到不同聚类中心的距离数组

                            //计算像元到不同聚类中心的距离
                            for (int i = 0; i < ICenter.Count; i++)
                            {
                                tmpDis[i] = Distance(tmpPix, ICenter[i].OldCenter);
                            }

                            double tmpMinDis = tmpDis[0]; //最小距离
                            int    tmpClass  = 0;         //分类

                            //计算最小值及分类
                            for (int i = 1; i < ICenter.Count; i++)
                            {
                                if (tmpDis[i] < tmpMinDis)
                                {
                                    tmpMinDis = tmpDis[i];
                                    tmpClass  = i;
                                }
                            }

                            //将该像元添加到对应聚类的列表中
                            ICenter[tmpClass].CenterList.Add(tmpPix);

                            //写入分类并增加对应类的像元计数
                            tmpOut[col] = (byte)(tmpClass + 1);
                            ICenter[tmpClass].PixelCount += 1;
                        }
                        DS.GetRasterBand(1).WriteRaster(0, row, xSize, 1, tmpOut, xSize, 1, 0, 0);
                        DS.FlushCache();
                        Thread.Sleep(1);
                        if (FP.Canceled)
                        {
                            Thread.Sleep(500);

                            FP.Finish();
                            throw new OperationCanceledException("操作被用户取消。");
                        }
                    }

                    //重新计算每个集群的均值和方差
                    foreach (ClusterCenter c in ICenter)
                    {
                        c.GetStddev();  //计算方差之前会自动求和和平均值

                        //将聚类中所有像元的平均值作为聚类的新中心?
                        for (int band = 0; band < bandNum; band++)
                        {
                            c.NewCenter[band] = c.CenterMean[band];
                        }
                    }

                    for (int i = 0; i < ICenter.Count; i++)
                    {
                        string tmpCenter = "聚类后第" + (i + 1).ToString() + "类:";
                        tmpCenter += "\r\n\t像元数:" + ICenter[i].PixelCount + ", ";
                        tmpCenter += "\r\n\t和:";
                        for (int band = 0; band < bandNum; band++)
                        {
                            tmpCenter += ICenter[i].CenterTotal[band] + ", ";
                        }
                        tmpCenter += "\r\n\t平均中心:";
                        for (int band = 0; band < bandNum; band++)
                        {
                            tmpCenter += ICenter[i].CenterMean[band] + ", ";
                        }
                        tmpCenter += "\r\n\t标准差:";
                        for (int band = 0; band < bandNum; band++)
                        {
                            tmpCenter += ICenter[i].CenterStddev[band] + ", ";
                        }
                        FP.Output(tmpCenter);
                    }

                    bool tmpCenterModified = false; //判断是否有聚类中心数量的变动

Delete:
                    //删除像元数在阈值以下的聚类
                    for (int i = 0; i < ICenter.Count; i++)
                    {
                        if (ICenter[i].PixelCount < MinPixelNumInClass)
                        {
                            FP.Output("第" + (i + 1).ToString() + "类像元数只有" + ICenter[i].PixelCount.ToString() + "个,将被删除。");
                            if (ICenter.Count - 1 >= MinKind)
                            {
                                tmpCenterModified = true;
                                ICenter.RemoveAt(i);
                                goto Delete;
                            }
                            else
                            {
                                FP.Output("第" + (i + 1).ToString() + "类删除失败,已达到最小分类数。");
                                goto EndDelete;
                            }
                        }
                    }
                    EndDelete :;

                    //合并与分裂
                    List <ClusterCenter> tmpChangeCenter = new List <ClusterCenter>();    //用于暂存对全局列表的更改
                    //偶次合并
                    if (tmpItera % 2 == 0)
                    {
Combine:
                        for (int i = 0; i < ICenter.Count; i++)
                        {
                            for (int j = 0; j < ICenter.Count; j++)
                            {
                                //不与自身比较
                                if (i == j)
                                {
                                    continue;
                                }
                                //类间距离小于设定阈值,进行合并
                                if (Distance(ICenter[i].CenterMean, ICenter[j].CenterMean) < MinClassDist)
                                {
                                    FP.Output("第" + (i + 1).ToString() + "类和第" + (j + 1).ToString() + "类的距离过小,为" + Distance(ICenter[i].CenterMean, ICenter[j].CenterMean) + ",将被合并。");
                                    if (ICenter.Count - 1 >= MinKind)
                                    {
                                        tmpCenterModified = true;
                                        tmpChangeCenter.Add(new ClusterCenter(ICenter[i], ICenter[j])); //合并两类并在临时列表中新建中心。
                                                                                                        //考虑i、j的大小,依次删除全局列表中对应索引处的中心(从大的开始删除)。
                                        if (i > j)
                                        {
                                            ICenter.RemoveAt(i);
                                            ICenter.RemoveAt(j);
                                        }
                                        else
                                        {
                                            ICenter.RemoveAt(j);
                                            ICenter.RemoveAt(i);
                                        }
                                        //每次迭代是只合并一次嘛?如果是的话就不需要goto
                                        goto Combine;
                                    }
                                    else
                                    {
                                        FP.Output("第" + (i + 1).ToString() + "类和第" + (j + 1).ToString() + "类合并失败,已达到最小分类数。");
                                        goto EndCombine;
                                    }
                                }
                            }
                        }
                        EndCombine :;
                    }
                    else   //奇次分裂
                    {
                        Split :
                        for (int i = 0; i < ICenter.Count; i++)
                        {
                            if (ICenter[i].MaxStddev > MaxClassStddev)
                            {
                                FP.Output("第" + (i + 1).ToString() + "类的类内最大方差为" + ICenter[i].MaxStddev.ToString() + ",将被分裂。");
                                if (ICenter.Count + 1 <= MaxKind)
                                {
                                    tmpCenterModified = true;
                                    ClusterCenter C1 = new ClusterCenter(bandNum);
                                    ClusterCenter C2 = new ClusterCenter(bandNum);
                                    //新建两聚类,中心为旧中心加减方差的一半
                                    //分裂后中心的参数怎么算?
                                    for (int band = 0; band < bandNum; band++)
                                    {
                                        //只改变大于标准差的中心值,若不大于则保持不变。
                                        if (ICenter[i].CenterStddev[band] > MaxClassStddev)
                                        {
                                            C1.OldCenter[band] = C1.NewCenter[band] = ICenter[i].NewCenter[band] + ICenter[i].CenterStddev[band] / 2;
                                            C2.OldCenter[band] = C2.NewCenter[band] = ICenter[i].NewCenter[band] - ICenter[i].CenterStddev[band] / 2;
                                        }
                                        else
                                        {
                                            C1.OldCenter[band] = C1.NewCenter[band] = ICenter[i].NewCenter[band];
                                            C2.OldCenter[band] = C2.NewCenter[band] = ICenter[i].NewCenter[band];
                                        }
                                        //C1.OldCenter[band] = C1.NewCenter[band] = ICenter[i].NewCenter[band] + MaxClassStddev / 2;
                                        //C2.OldCenter[band] = C2.NewCenter[band] = ICenter[i].NewCenter[band] - MaxClassStddev / 2;
                                    }
                                    tmpChangeCenter.Add(C1);
                                    tmpChangeCenter.Add(C2);
                                    ICenter.RemoveAt(i);
                                    goto Split;
                                }
                                else
                                {
                                    FP.Output("第" + (i + 1).ToString() + "类分裂失败,已达到最大分类数。");
                                    goto EndSplit;
                                }
                            }
                        }
                        EndSplit :;
                    }

                    double tmpCenterChangeMax = 100000000;
                    //仅在聚类中心数量没有变化的时候才计算中心变化率
                    if (!tmpCenterModified)
                    {
                        double[] tmpCenterChange = new double[ICenter.Count];
                        //计算聚类中心变化率
                        for (int i = 0; i < ICenter.Count; i++)
                        {
                            for (int band = 0; band < bandNum; band++)
                            {
                                if (Math.Abs(ICenter[i].OldCenter[band]) <= 1e-7)   //分母为0
                                {
                                    tmpCenterChange[i] += Math.Abs(ICenter[i].NewCenter[band] - ICenter[i].OldCenter[band]) / 0.0001;
                                }
                                else
                                {
                                    tmpCenterChange[i] += Math.Abs(ICenter[i].NewCenter[band] - ICenter[i].OldCenter[band]) / ICenter[i].OldCenter[band];
                                }
                            }
                            tmpCenterChange[i] /= bandNum;
                        }

                        //计算最大变化率
                        tmpCenterChangeMax = tmpCenterChange[0];
                        for (int i = 1; i < ICenter.Count; i++)
                        {
                            if (tmpCenterChange[i] > tmpCenterChangeMax)
                            {
                                tmpCenterChangeMax = tmpCenterChange[i];
                            }
                        }
                        FP.Output("中心变化率:" + tmpCenterChangeMax + ",阈值:" + CenterDiff);
                        FP.SetProgress1("最大中心变化率:", CenterDiff, tmpCenterChangeMax, "");
                    }
                    else
                    {
                        FP.Output("第" + tmpItera.ToString() + "次迭代出现聚类中心的合并或分裂,不计算中心变化率...");
                    }

                    //将新的中心变为旧的中心,准备开始新一轮迭代
                    for (int i = 0; i < ICenter.Count; i++)
                    {
                        for (int band = 0; band < bandNum; band++)
                        {
                            ICenter[i].OldCenter[band] = ICenter[i].NewCenter[band];
                        }
                    }

                    //将临时新建的聚类中心添加到全局聚类中心的末尾,并清空临时聚类中心
                    ICenter.AddRange(tmpChangeCenter);
                    tmpChangeCenter.Clear();

                    tmpItera++;
                    //判断是否继续循环。
                    if (tmpItera % 2 == 0)
                    {
                        if (((MaxItera > 1) && (tmpItera > MaxItera)) || (!tmpCenterModified && tmpCenterChangeMax < CenterDiff) || (tmpItera > 10000))
                        {
                            tmpContinue = false;
                        }
                    }
                }
                FP.Finish();
                DS.Dispose();
                return(true);
            }
            catch (Exception err)
            {
                MessageBox.Show(err.ToString());
                return(false);
            }
        }
Пример #4
0
        /// <summary>
        /// K-Means算法。
        /// </summary>
        /// <param name="InputDS">输入的数据集。</param>
        /// <param name="Kind">分类数。</param>
        /// <param name="MaxItera">最大迭代次数。</param>
        /// <param name="CenterDiff">聚类中心变化率阈值。</param>
        /// <param name="OutPath">输出路径。</param>
        /// <returns>操作成功或失败。</returns>
        public static bool KMeans(OSGeo.GDAL.Dataset InputDS, int Kind, int MaxItera, double CenterDiff, string OutPath)
        {
            try
            {
                if (InputDS == null)
                {
                    throw new ArgumentNullException("输入数据集为空。");
                }
                if (String.IsNullOrWhiteSpace(OutPath.Trim()))
                {
                    throw new ArgumentNullException("输出路径为空或非法。");
                }
                OSGeo.GDAL.Driver Dri = OSGeo.GDAL.Gdal.GetDriverByName("Gtiff");
                if (Dri == null)
                {
                    throw new Exception("无法获取GDAL Driver。");
                }

                int bandNum = InputDS.RasterCount;
                int xSize   = InputDS.RasterXSize;
                int ySize   = InputDS.RasterYSize;

                FrmProgress FP = new FrmProgress()
                {
                    Text = "正在进行K-Means分类...",
                };

                Thread t = new Thread(() =>
                {
                    FP.ShowDialog();
                });
                t.SetApartmentState(ApartmentState.STA);
                t.Start();

                OSGeo.GDAL.Dataset DS = Dri.Create(OutPath, xSize, ySize, 1, OSGeo.GDAL.DataType.GDT_Byte, null);
                FP.Output("已创建输出数据集\"" + OutPath + "\",数据类型为GDT_Byte。");
                Tools.Common.CopyMetadata(InputDS, DS);

                int  tmpItera    = 0;
                bool tmpContinue = true;

                double[]        min     = new double[bandNum];
                double[]        max     = new double[bandNum];
                double[]        mean    = new double[bandNum];
                double[]        stddev  = new double[bandNum];
                ClusterCenter[] KCenter = new ClusterCenter[Kind];

                //计算数据集各波段统计数据
                for (int i = 0; i < bandNum; i++)
                {
                    Tools.Common.GetStatistics(InputDS.GetRasterBand(i + 1), out min[i], out max[i], out mean[i], out stddev[i]);
                }

                //初始化聚类中心
                for (int i = 0; i < Kind; i++)
                {
                    KCenter[i] = new ClusterCenter(bandNum);
                    for (int band = 0; band < bandNum; band++)
                    {
                        KCenter[i].NewCenter[band] = KCenter[i].OldCenter[band] = mean[band] + stddev[band] - 2 * i * stddev[band] / Kind;
                    }
                }

                //循环体
                while (tmpContinue)
                {
                    FP.Output("正在迭代第" + (tmpItera + 1).ToString() + "次...");
                    FP.SetProgress2("正在迭代:", tmpItera + 1, MaxItera, "次");
                    //重置所有类的像元计数为1
                    for (int i = 0; i < Kind; i++)
                    {
                        KCenter[i].PixelCount = 1;
                    }

                    for (int i = 0; i < Kind; i++)
                    {
                        string tmpCenter = "第" + (i + 1).ToString() + "类中心:\r\n";
                        for (int band = 0; band < bandNum; band++)
                        {
                            tmpCenter += "\t第" + (band + 1).ToString() + "波段中心:" + KCenter[i].OldCenter[band] + "\r\n";
                        }
                        FP.Output(tmpCenter);
                    }

                    //遍历数据集每一行
                    for (int row = 0; row < ySize; row++)
                    {
                        FP.SetProgress1("正在处理:", row + 1, ySize, "行");
                        double[][] tmpInput = new double[bandNum][];    //用于存储输入像元的交错数组

                        //将一行的所有波段像元值读取入交错数组
                        for (int band = 0; band < bandNum; band++)
                        {
                            tmpInput[band] = new double[xSize];
                            InputDS.GetRasterBand(band + 1).ReadRaster(0, row, xSize, 1, tmpInput[band], xSize, 1, 0, 0);
                        }

                        byte[] tmpOut = new byte[xSize];    //用于存储输出像元的数组

                        //遍历一行的每一列,对像元分类
                        for (int col = 0; col < xSize; col++)
                        {
                            double[] tmpPix = new double[bandNum];  //临时存储单个像元所有波段的数组

                            //将指定行列的所有波段像元转储到数组
                            for (int band = 0; band < bandNum; band++)
                            {
                                tmpPix[band] = tmpInput[band][col];
                            }

                            double[] tmpDis = new double[Kind]; //单个像元到不同聚类中心的距离数组

                            //计算像元到不同聚类中心的距离
                            for (int i = 0; i < Kind; i++)
                            {
                                tmpDis[i] = Distance(tmpPix, KCenter[i].OldCenter);
                            }

                            double tmpMinDis = tmpDis[0]; //最小距离
                            int    tmpClass  = 0;         //分类

                            //计算最小值及分类
                            for (int i = 1; i < Kind; i++)
                            {
                                if (tmpDis[i] < tmpMinDis)
                                {
                                    tmpMinDis = tmpDis[i];
                                    tmpClass  = i;
                                }
                            }

                            //更新聚类中心
                            for (int band = 0; band < bandNum; band++)
                            {
                                KCenter[tmpClass].NewCenter[band] = (KCenter[tmpClass].NewCenter[band] * KCenter[tmpClass].PixelCount + tmpPix[band]) / (KCenter[tmpClass].PixelCount + 1);
                            }

                            //写入分类并增加对应类的像元计数
                            tmpOut[col] = (byte)(tmpClass + 1);
                            KCenter[tmpClass].PixelCount += 1;
                        }
                        DS.GetRasterBand(1).WriteRaster(0, row, xSize, 1, tmpOut, xSize, 1, 0, 0);
                        DS.FlushCache();
                        Thread.Sleep(1);
                        if (FP.Canceled)
                        {
                            Thread.Sleep(500);

                            FP.Finish();
                            throw new OperationCanceledException("操作被用户取消。");
                        }
                    }

                    for (int i = 0; i < Kind; i++)
                    {
                        string tmpCenter = "聚类后第" + (i + 1).ToString() + "类:\r\n\t新中心:";
                        for (int band = 0; band < bandNum; band++)
                        {
                            tmpCenter += KCenter[i].NewCenter[band] + ", ";
                        }
                        FP.Output(tmpCenter);
                    }

                    double[] tmpCenterChange = new double[Kind];
                    //计算聚类中心变化率
                    for (int i = 0; i < Kind; i++)
                    {
                        for (int band = 0; band < bandNum; band++)
                        {
                            if (Math.Abs(KCenter[i].OldCenter[band]) <= 1e-7)   //分母为0
                            {
                                tmpCenterChange[i] += Math.Abs(KCenter[i].NewCenter[band] - KCenter[i].OldCenter[band]) / 0.0001;
                            }
                            else
                            {
                                tmpCenterChange[i] += Math.Abs(KCenter[i].NewCenter[band] - KCenter[i].OldCenter[band]) / KCenter[i].OldCenter[band];
                            }
                        }
                        tmpCenterChange[i] /= bandNum;
                    }

                    //计算最大变化率
                    double tmpCenterChangeMax = tmpCenterChange[0];
                    for (int i = 1; i < Kind; i++)
                    {
                        if (tmpCenterChange[i] > tmpCenterChangeMax)
                        {
                            tmpCenterChangeMax = tmpCenterChange[i];
                        }
                    }

                    FP.Output("中心变化率:" + tmpCenterChangeMax + ",阈值:" + CenterDiff);
                    FP.SetProgress1("最大中心变化率:", CenterDiff, tmpCenterChangeMax, "");

                    //将新的中心变为旧的中心,准备开始新一轮迭代
                    for (int i = 0; i < Kind; i++)
                    {
                        for (int band = 0; band < bandNum; band++)
                        {
                            KCenter[i].OldCenter[band] = KCenter[i].NewCenter[band];
                        }
                    }

                    tmpItera++;

                    //判断是否继续循环
                    if (((MaxItera > 1) && (tmpItera > MaxItera)) || (tmpCenterChangeMax < CenterDiff) || (tmpItera > 10000))
                    {
                        tmpContinue = false;
                    }
                }

                FP.Finish();
                DS.Dispose();
                return(true);
            }
            catch (Exception err)
            {
                MessageBox.Show(err.ToString());
                return(false);
            }
        }