/// <summary>
        /// 辐射定标。
        /// </summary>
        /// <param name="InputDS">输入的栅格数据集。</param>
        /// <param name="OutDataType">输出的数据类型。</param>
        /// <param name="Gain">增益倍数。</param>
        /// <param name="Offset">偏移量。</param>
        /// <param name="OutPath">输出栅格数据集的位置。</param>
        /// <returns>返回操作成功或失败。</returns>
        public static bool ApplyGainAndOffset(OSGeo.GDAL.Dataset InputDS, OSGeo.GDAL.DataType OutDataType, List <double> Gain, List <double> Offset, string OutPath)
        {
            try
            {
                if (InputDS == null)
                {
                    throw new ArgumentNullException("输入数据集为空。");
                }
                if (String.IsNullOrWhiteSpace(OutPath.Trim()))
                {
                    throw new ArgumentNullException("输出路径为空或非法。");
                }
                if ((Gain.Count != InputDS.RasterCount) || (Offset.Count != InputDS.RasterCount))
                {
                    throw new IndexOutOfRangeException("增益数据或偏移数据与输入数据集波段数不符。");
                }
                OSGeo.GDAL.Driver Dri = OSGeo.GDAL.Gdal.GetDriverByName("Gtiff");
                if (Dri == null)
                {
                    throw new Exception("无法获取GDAL Driver。");
                }

                FrmProgress FP = new FrmProgress()
                {
                    Text = "正在进行辐射定标...",
                };

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

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

                for (int i = 0; i < InputDS.RasterCount; i++) //遍历每个波段
                {
                    FP.SetProgress2("正在处理波段:", i + 1, InputDS.RasterCount, "");
                    for (int Row = 0; Row < ySize; Row++)   //遍历每一行(y)
                    {
                        FP.SetProgress1("正在处理:", Row + 1, ySize, "行");
                        double[] Values = new double[xSize];

                        //读取DN到数组
                        InputDS.GetRasterBand(i + 1).ReadRaster(0, Row, xSize, 1, Values, xSize, 1, 0, 0);
                        for (int Col = 0; Col < xSize; Col++)   //对每一个值进行计算
                        {
                            Values[Col] = GainOffset(Values[Col], Gain[i], Offset[i]);
                        }
                        //写结果到新栅格
                        DS.GetRasterBand(i + 1).WriteRaster(0, Row, xSize, 1, Values, xSize, 1, 0, 0);
                        DS.FlushCache();
                        Thread.Sleep(1);
                        if (FP.Canceled)
                        {
                            Thread.Sleep(500);

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

                FP.Finish();
                Dri.Dispose();
                DS.Dispose();
                return(true);
            }
            catch (Exception err)
            {
                MessageBox.Show(err.ToString());
                return(false);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// 数据集相除。
        /// </summary>
        /// <param name="D1">被除数据集。</param>
        /// <param name="D2">除数据集。</param>
        /// <param name="OutDataType">输出数据集的数据类型。</param>
        /// <param name="OutPath">输出路径。</param>
        /// <returns>操作成功或失败。</returns>
        public static bool Divide(OSGeo.GDAL.Dataset D1, OSGeo.GDAL.Dataset D2, OSGeo.GDAL.DataType OutDataType, string OutPath)
        {
            try
            {
                if (D1 == null || D2 == 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 Width  = Math.Min(D1.RasterXSize, D2.RasterXSize);
                int Height = Math.Min(D1.RasterYSize, D2.RasterYSize);
                int band   = Math.Min(D1.RasterCount, D2.RasterCount);

                FrmProgress FP = new FrmProgress()
                {
                    Text = "正在进行数据集除法运算...",
                };

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

                OSGeo.GDAL.Dataset DS = Dri.Create(OutPath, Width, Height, band, OutDataType, null);
                FP.Output("已创建输出数据集\"" + OutPath + "\",数据类型为" + OutDataType.ToString() + "。");
                Tools.Common.CopyMetadata(D1, DS);

                for (int bandcount = 1; bandcount <= band; bandcount++)
                {
                    FP.SetProgress2("正在处理", bandcount, band, "波段");
                    for (int row = 0; row < Height; row++)
                    {
                        FP.SetProgress1("正在处理:", row + 1, Height, "行");
                        double[] d1Tmp = new double[Width];
                        double[] d2Tmp = new double[Width];
                        double[] dsTmp = new double[Width];
                        D1.GetRasterBand(bandcount).ReadRaster(0, row, Width, 1, d1Tmp, Width, 1, 0, 0);
                        D2.GetRasterBand(bandcount).ReadRaster(0, row, Width, 1, d2Tmp, Width, 1, 0, 0);
                        for (long i = 0; i < Width; i++)
                        {
                            if (d2Tmp[i] == 0)
                            {
                                dsTmp[i] = 0;
                            }
                            else
                            {
                                dsTmp[i] = d1Tmp[i] / d2Tmp[i];
                            }
                        }

                        DS.GetRasterBand(bandcount).WriteRaster(0, row, Width, 1, dsTmp, Width, 1, 0, 0);
                        DS.FlushCache();
                        Thread.Sleep(1);
                        if (FP.Canceled)
                        {
                            Thread.Sleep(500);

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

                FP.Finish();
                Dri.Dispose();
                DS.Dispose();
                return(true);
            }
            catch (Exception err)
            {
                MessageBox.Show(err.ToString());
                return(false);
            }
        }
Esempio n. 3
0
        public static bool CutImage(OSGeo.GDAL.Dataset InputDS, int CutWidth, int CutHeight, OSGeo.GDAL.DataType OutDataType, string OutFolder)
        {
            try
            {
                if (InputDS == null)
                {
                    throw new ArgumentNullException("输入的数据集不可为空。");
                }
                if (String.IsNullOrWhiteSpace(OutFolder))
                {
                    throw new ArgumentNullException("输出路径为空或非法。");
                }
                OSGeo.GDAL.Driver Dri = OSGeo.GDAL.Gdal.GetDriverByName("Gtiff");
                if (Dri == null)
                {
                    throw new Exception("无法获取GDAL Driver。");
                }

                //取输入的宽、高、波段最小值创建输出数据集。
                int Width  = InputDS.RasterXSize;
                int Height = InputDS.RasterYSize;

                int Rows = Height / CutHeight;
                int Cols = Width / CutWidth;

                FrmProgress FP = new FrmProgress()
                {
                    Text = "正在进行影像裁剪...",
                };

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

                FP.Output("输出的目录为:" + OutFolder);
                FP.Output("输出的数据类型为:" + OutDataType.ToString());

                for (int row = 0; row < Rows; row++)
                {
                    FP.SetProgress2("总进度:", row + 1, Rows, "");
                    string ParentPath = row.ToString();
                    Directory.CreateDirectory(Path.Combine(OutFolder, ParentPath));
                    for (int col = 0; col < Cols; col++)
                    {
                        FP.SetProgress1("当前行进度:", col + 1, Cols, "");
                        string             OutName = row.ToString() + "_" + col.ToString() + ".tif";
                        OSGeo.GDAL.Dataset DS      = Dri.Create(Path.Combine(OutFolder, ParentPath, OutName), CutWidth, CutHeight, InputDS.RasterCount, OutDataType, null);
                        for (int band = 1; band <= InputDS.RasterCount; band++)
                        {
                            double[] buf = new double[CutWidth * CutHeight];
                            InputDS.GetRasterBand(band).ReadRaster(col * CutWidth, row * CutHeight, CutWidth, CutHeight, buf, CutWidth, CutHeight, 0, 0);
                            DS.GetRasterBand(band).WriteRaster(0, 0, CutWidth, CutHeight, buf, CutWidth, CutHeight, 0, 0);
                        }
                        ////单行读取写入,防止爆内存。
                        //for (int cRow = 0; cRow < CutHeight; cRow++)
                        //{
                        //    double[] buf = new double[CutWidth];
                        //    InputDS.GetRasterBand(band).ReadRaster(col * CutWidth, row * CutHeight + cRow, CutWidth, 1, buf, CutWidth, 1, 0, 0);
                        //    DS.GetRasterBand(band).WriteRaster(0, cRow, CutWidth, 1, buf, CutWidth, 1, 0, 0);
                        //    DS.FlushCache();
                        //    Thread.Sleep(1);
                        //}

                        DS.FlushCache();
                        DS.Dispose();
                        Thread.Sleep(1);
                        if (FP.Canceled)
                        {
                            Thread.Sleep(500);

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

                FP.Finish();
                InputDS.Dispose();
                Dri.Dispose();
                return(true);
            }
            catch (Exception err)
            {
                MessageBox.Show(err.ToString());
                return(false);
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Brovey变换融合。融合前会将多光谱数据集的每一波段与全色数据集做直方图匹配。
        /// </summary>
        /// <param name="PanDS">全色数据集。</param>
        /// <param name="MSDS">多光谱数据集</param>
        /// <param name="PanCumu">全色数据集的累积概率表。</param>
        /// <param name="MSCumu">多光谱数据集的累积概率表。</param>
        /// <param name="MSBandList">多光谱数据集的波段组合。</param>
        /// <param name="OutDataType">输出数据类型。</param>
        /// <param name="OutPath">输出路径。</param>
        /// <returns>返回操作成功或失败。</returns>
        public static bool Brovey(OSGeo.GDAL.Dataset PanDS, OSGeo.GDAL.Dataset MSDS, double[][] PanCumu, double[][] MSCumu, int[] MSBandList, OSGeo.GDAL.DataType OutDataType, string OutPath)
        {
            try
            {
                if (PanDS == null)
                {
                    throw new ArgumentNullException("输入的全色数据集为空。");
                }
                if (PanDS.RasterCount > 1)
                {
                    throw new RankException("全色数据集波段大于1。");
                }
                if (MSDS == 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 panWidth  = PanDS.RasterXSize;
                int panHeight = PanDS.RasterYSize;
                int msWidth   = MSDS.RasterXSize;
                int msHeight  = MSDS.RasterYSize;
                //int rat = (int)Math.Ceiling((double)panHeight / msHeight);

                if (panWidth < msWidth)
                {
                    throw new RankException("全色数据集宽度小于多光谱数据集宽度。");
                }
                if (panHeight < msHeight)
                {
                    throw new RankException("全色数据集高度小于多光谱数据集高度。");
                }
                //if (rat <= 0)
                //    throw new ArgumentOutOfRangeException("全色高度:多光谱高度小于1。");

                FrmProgress FP = new FrmProgress()
                {
                    Text = "正在进行Brovey融合...",
                };

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

                #region 预处理
                //创建临时文件,进行直方图匹配。
                string             HisMatFileName = Tools.Common.GetTempFileName();
                OSGeo.GDAL.Dataset MatchingDS     = Dri.CreateCopy(HisMatFileName, MSDS, 0, null, null, null);
                FP.Output("已创建直方图匹配临时文件\"" + HisMatFileName + "\"");
                for (int band = 1; band <= MSDS.RasterCount; band++)
                {
                    FP.Output("正在进行直方图匹配(" + band.ToString() + "/" + MSDS.RasterCount.ToString() + ")...");
                    Band b = Tools.BaseProcess.HistogramMatching(MSDS.GetRasterBand(band), PanDS.GetRasterBand(1), MSCumu[band - 1], PanCumu[0], OutDataType);
                    if (b == null)
                    {
                        throw new ArgumentNullException("直方图匹配返回波段为空。");
                    }
                    for (int row = 0; row < b.YSize; row++)
                    {
                        double[] tmp = new double[b.XSize];
                        b.ReadRaster(0, row, b.XSize, 1, tmp, b.XSize, 1, 0, 0);
                        MatchingDS.GetRasterBand(band).WriteRaster(0, row, MatchingDS.GetRasterBand(band).XSize, 1, tmp, MatchingDS.GetRasterBand(band).XSize, 1, 0, 0);
                        MatchingDS.FlushCache();
                        Thread.Sleep(1);
                    }
                }

                //创建临时文件,进行重采样。
                double[]           resamptmp;
                string             ResampFileName = Tools.Common.GetTempFileName();
                OSGeo.GDAL.Dataset ResampDS       = Dri.Create(ResampFileName, panWidth, panHeight, 3, MSDS.GetRasterBand(1).DataType, null);
                FP.Output("已创建重采样临时文件\"" + ResampFileName + "\"");
                //Tools.Common.CopyMetadata(PanDS, tmpDS);
                //Gdal.ReprojectImage(MSDS, tmpDS, null, null, 0, 0, 0, null, null);

                //将直方图匹配后的图像重采样。
                for (int i = 0; i < 3; i++)
                {
                    FP.Output("正在对直方图匹配后影像进行重采样(" + (i + 1).ToString() + "/" + "3)...");
                    resamptmp = new double[panWidth * panHeight];
                    MatchingDS.GetRasterBand(MSBandList[i]).ReadRaster(0, 0, msWidth, msHeight, resamptmp, panWidth, panHeight, 0, 0);
                    ResampDS.GetRasterBand(i + 1).WriteRaster(0, 0, panWidth, panHeight, resamptmp, panWidth, panHeight, 0, 0);
                    ResampDS.FlushCache();
                    Thread.Sleep(1);
                    if (FP.Canceled)
                    {
                        Thread.Sleep(500);

                        FP.Finish();
                        throw new OperationCanceledException("操作被用户取消。");
                    }
                }
                //释放直方图匹配图像资源。
                MatchingDS.Dispose();
                if (File.Exists(HisMatFileName))
                {
                    File.Delete(HisMatFileName);
                }
                FP.Output("已删除直方图匹配临时文件");
                #endregion

                //创建输出数据集。
                OSGeo.GDAL.Dataset DS = Dri.Create(OutPath, panWidth, panHeight, 3, OutDataType, null);
                FP.Output("已创建输出数据集\"" + OutPath + "\",数据类型为" + OutDataType.ToString() + "。");
                Tools.Common.CopyMetadata(PanDS, DS);

                double[]   p;
                double[][] ms;
                double[]   ds;

                for (int row = 0; row < panHeight; row++)
                {
                    FP.SetProgress2("正在处理", row + 1, panHeight, "行");
                    //将全色波段行读取进数组。
                    p = new double[panWidth];
                    PanDS.GetRasterBand(1).ReadRaster(0, row, panWidth, 1, p, panWidth, 1, 0, 0);

                    //将重采样后的多光谱行读取进数组。
                    ms    = new double[3][];
                    ms[0] = new double[panWidth];
                    ms[1] = new double[panWidth];
                    ms[2] = new double[panWidth];
                    ResampDS.GetRasterBand(1).ReadRaster(0, row, panWidth, 1, ms[0], panWidth, 1, 0, 0);
                    ResampDS.GetRasterBand(2).ReadRaster(0, row, panWidth, 1, ms[1], panWidth, 1, 0, 0);
                    ResampDS.GetRasterBand(3).ReadRaster(0, row, panWidth, 1, ms[2], panWidth, 1, 0, 0);

                    //遍历三波段
                    for (int bandcount = 0; bandcount < 3; bandcount++)
                    {
                        FP.SetProgress1("正在处理", bandcount + 1, 3, "波段");
                        ds = new double[panWidth];  //临时数组
                        for (long i = 0; i < panWidth; i++)
                        {
                            ds[i] = p[i] * ms[bandcount][i] / (ms[0][i] + ms[1][i] + ms[2][i]);                  //Brovey公式
                        }
                        DS.GetRasterBand(bandcount + 1).WriteRaster(0, row, panWidth, 1, ds, panWidth, 1, 0, 0); //计算完后的数据写入
                        DS.FlushCache();
                    }
                    Thread.Sleep(1);
                    if (FP.Canceled)
                    {
                        Thread.Sleep(500);

                        FP.Finish();
                        throw new OperationCanceledException("操作被用户取消。");
                    }
                }
                //释放重采样图像资源。
                ResampDS.Dispose();
                if (File.Exists(ResampFileName))
                {
                    File.Delete(ResampFileName);
                }
                FP.Output("已删除重采样临时文件");

                /*一次性读取一时爽,遇到大文件爆内存。
                *  一次性读取一时爽,遇到大文件爆内存。
                *  一次性读取一时爽,遇到大文件爆内存。*/
                //p = new double[panWidth * panHeight];
                //ms = new double[3][];
                //ms[0] = new double[panWidth * panHeight];
                //ms[1] = new double[panWidth * panHeight];
                //ms[2] = new double[panWidth * panHeight];

                //PanDS.GetRasterBand(1).ReadRaster(0, 0, panWidth, panHeight, p, panWidth, panHeight, 0, 0);
                //MSDS.GetRasterBand(MSBandList[0]).ReadRaster(0, 0, msWidth, msHeight, ms[0], panWidth, panHeight, 0, 0);
                //MSDS.GetRasterBand(MSBandList[1]).ReadRaster(0, 0, msWidth, msHeight, ms[1], panWidth, panHeight, 0, 0);
                //MSDS.GetRasterBand(MSBandList[2]).ReadRaster(0, 0, msWidth, msHeight, ms[2], panWidth, panHeight, 0, 0);

                //for (int bandcount = 0; bandcount < 3; bandcount++)
                //{
                //    ds = new double[panWidth * panHeight];
                //    for (int row = 0; row < panHeight; row++)
                //    {
                //        for (int col = 0; col < panWidth; col++)
                //        {
                //            ds[row * panWidth + col] = p[row * panWidth + col] * ms[bandcount][row * panWidth + col] / (ms[0][row * panWidth + col] + ms[1][row * panWidth + col] + ms[2][row * panWidth + col]);
                //        }
                //    }
                //    DS.GetRasterBand(bandcount + 1).WriteRaster(0, 0, panWidth, panHeight, ds, panWidth, panHeight, 0, 0);
                //    DS.FlushCache();
                //}

                FP.Finish();
                Dri.Dispose();
                DS.Dispose();
                return(true);
            }
            catch (Exception err)
            {
                MessageBox.Show(err.ToString());
                return(false);
            }
        }
Esempio n. 5
0
        /// <summary>
        /// 影像直方图匹配。
        /// </summary>
        /// <param name="InputDS">输入的数据集。</param>
        /// <param name="MatchDS">要匹配到的数据集。</param>
        /// <param name="InputCumu">输入的数据集的累积概率表。</param>
        /// <param name="MatchingCumu">要匹配到的数据集的累积概率表。</param>
        /// <param name="OutDataType">输出的数据类型。</param>
        /// <param name="OutPath">输出栅格数据集的位置。</param>
        /// <returns>操作成功或失败。</returns>
        public static bool HistogramMatching(OSGeo.GDAL.Dataset InputDS, OSGeo.GDAL.Dataset MatchDS, double[][] InputCumu, double[][] MatchingCumu, OSGeo.GDAL.DataType OutDataType, string OutPath)
        {
            try
            {
                if (InputDS.RasterCount != MatchDS.RasterCount)
                {
                    throw new ArgumentException("数据集波段数不一致。");
                }

                FrmProgress FP = new FrmProgress()
                {
                    Text = "正在进行影像直方图匹配...",
                };

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

                int[][] LUT = new int[InputDS.RasterCount][];
                FP.Output("正在计算查找表...");
                for (int i = 0; i < InputDS.RasterCount; i++)
                {
                    LUT[i] = HistogramMatching(InputCumu[i], MatchingCumu[i]);
                }

                OSGeo.GDAL.Driver Dri = OSGeo.GDAL.Gdal.GetDriverByName("Gtiff");
                if (Dri == null)
                {
                    throw new Exception("无法获取GDAL Driver。");
                }

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

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

                for (int bandcount = 0; bandcount < InputDS.RasterCount; bandcount++)
                {
                    FP.SetProgress2("正在处理", bandcount + 1, InputDS.RasterCount, "波段");
                    Tools.Common.GetMinimum(InputDS.GetRasterBand(bandcount + 1), out double inputDSBandMin);
                    Tools.Common.GetMinimum(MatchDS.GetRasterBand(bandcount + 1), out double matchDSBandMin);
                    for (int Row = 0; Row < ySize; Row++)
                    {
                        FP.SetProgress1("正在处理", Row + 1, ySize, "行");
                        double[] Values = new double[xSize];
                        //读取DN到数组
                        InputDS.GetRasterBand(bandcount + 1).ReadRaster(0, Row, xSize, 1, Values, xSize, 1, 0, 0);
                        for (int Col = 0; Col < xSize; Col++)
                        {
                            //防止GDAL自带方法算出的统计数据越界。
                            if ((Values[Col] - inputDSBandMin) <= 0)
                            {
                                Values[Col] = matchDSBandMin + LUT[bandcount][0];
                                continue;
                            }
                            if ((Values[Col] - inputDSBandMin) >= LUT[bandcount].Length - 1)
                            {
                                Values[Col] = matchDSBandMin + LUT[bandcount][LUT[bandcount].Length - 1];
                                continue;
                            }
                            Values[Col] = matchDSBandMin + LUT[bandcount][(int)(Values[Col] - inputDSBandMin)];
                        }
                        //写结果到新栅格
                        DS.GetRasterBand(bandcount + 1).WriteRaster(0, Row, xSize, 1, Values, xSize, 1, 0, 0);
                        DS.FlushCache();
                        Thread.Sleep(1);
                        if (FP.Canceled)
                        {
                            Thread.Sleep(500);

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

                FP.Finish();
                Dri.Dispose();
                DS.Dispose();
                return(true);
            }
            catch (Exception err)
            {
                MessageBox.Show(err.ToString());
                return(false);
            }
        }
Esempio n. 6
0
        public static bool CalculateFloodArea(string InDir, string OutDir)
        {
            try
            {
                if (!Directory.Exists(InDir))
                {
                    throw new FileNotFoundException("输入路径不存在。");
                }
                if (!Directory.Exists(OutDir))
                {
                    Directory.CreateDirectory(OutDir);
                }
                OSGeo.GDAL.Driver Dri = OSGeo.GDAL.Gdal.GetDriverByName("Gtiff");
                if (Dri == null)
                {
                    throw new Exception("无法获取GDAL Driver。");
                }

                FrmProgress FP = new FrmProgress()
                {
                    Text = "正在处理洪水范围...",
                };
                Thread t = new Thread(() =>
                {
                    FP.ShowDialog();
                });
                t.SetApartmentState(ApartmentState.STA);
                t.Start();


                bool               createFlag = true;
                string[]           ascFiles   = Directory.GetFiles(InDir);
                int                xSize      = 0;
                int                ySize      = 0;
                OSGeo.GDAL.Dataset rangeDS    = new OSGeo.GDAL.Dataset(IntPtr.Zero, false, null);
                OSGeo.GDAL.Dataset depthDS    = new OSGeo.GDAL.Dataset(IntPtr.Zero, false, null);
                OSGeo.GDAL.Dataset timeDS     = new OSGeo.GDAL.Dataset(IntPtr.Zero, false, null);

                for (int i = 0; i < ascFiles.Length; i++)
                {
                    FP.SetProgress2("正在处理文件:", i + 1, ascFiles.Length, "");
                    string tmpPath = ascFiles[i];
                    FP.Output("正在处理:" + (i + 1).ToString() + ". " + tmpPath);
                    if (tmpPath.Substring(tmpPath.LastIndexOf(".")) != ".txt")
                    {
                        FP.Output(tmpPath + "不是txt文件。");
                        continue;
                    }

                    OSGeo.GDAL.Dataset tmpDS = OSGeo.GDAL.Gdal.Open(tmpPath, OSGeo.GDAL.Access.GA_ReadOnly);
                    if (createFlag)
                    {
                        xSize = tmpDS.RasterXSize;
                        ySize = tmpDS.RasterYSize;
                        string inDirName = Path.GetDirectoryName(tmpPath).Substring(Path.GetDirectoryName(tmpPath).LastIndexOf("\\") + 1);
                        rangeDS = Dri.Create(Path.Combine(OutDir, inDirName + "_floodRange.tiff"), xSize, ySize, 1, OSGeo.GDAL.DataType.GDT_Float32, null);
                        Tools.Common.CopyMetadata(tmpDS, rangeDS);
                        FP.Output("已创建输出数据集\"" + Path.Combine(OutDir, inDirName + "_floodRange.tiff") + "\"。");

                        depthDS = Dri.Create(Path.Combine(OutDir, inDirName + "_floodDepth.tiff"), xSize, ySize, 1, OSGeo.GDAL.DataType.GDT_Float32, null);
                        Tools.Common.CopyMetadata(tmpDS, depthDS);
                        FP.Output("已创建输出数据集\"" + Path.Combine(OutDir, inDirName + "_floodDepth.tiff") + "\"。");

                        timeDS = Dri.Create(Path.Combine(OutDir, inDirName + "_floodTime.tiff"), xSize, ySize, 1, OSGeo.GDAL.DataType.GDT_Float32, null);
                        Tools.Common.CopyMetadata(tmpDS, timeDS);
                        FP.Output("已创建输出数据集\"" + Path.Combine(OutDir, inDirName + "_floodTime.tiff") + "\"。");

                        createFlag = false;
                    }

                    for (int Row = 0; Row < ySize; Row++)
                    {
                        double[] tmpValues   = new double[xSize];
                        double[] rangeValues = new double[xSize];
                        double[] depthValues = new double[xSize];
                        double[] timeValues  = new double[xSize];

                        tmpDS.GetRasterBand(1).ReadRaster(0, Row, xSize, 1, tmpValues, xSize, 1, 0, 0);
                        rangeDS.GetRasterBand(1).ReadRaster(0, Row, xSize, 1, rangeValues, xSize, 1, 0, 0);
                        depthDS.GetRasterBand(1).ReadRaster(0, Row, xSize, 1, depthValues, xSize, 1, 0, 0);
                        timeDS.GetRasterBand(1).ReadRaster(0, Row, xSize, 1, timeValues, xSize, 1, 0, 0);

                        for (int Col = 0; Col < xSize; Col++)
                        {
                            //计算洪水范围
                            if (Math.Abs(tmpValues[Col]) <= 1e-7)  //Nodata
                            {
                                continue;
                            }
                            else
                            {
                                rangeValues[Col] = 1;
                                if (tmpValues[Col] > depthValues[Col])
                                {
                                    depthValues[Col] = tmpValues[Col];
                                }
                                timeValues[Col] += 1;
                            }
                        }

                        rangeDS.GetRasterBand(1).WriteRaster(0, Row, xSize, 1, rangeValues, xSize, 1, 0, 0);
                        rangeDS.FlushCache();
                        depthDS.GetRasterBand(1).WriteRaster(0, Row, xSize, 1, depthValues, xSize, 1, 0, 0);
                        depthDS.FlushCache();
                        timeDS.GetRasterBand(1).WriteRaster(0, Row, xSize, 1, timeValues, xSize, 1, 0, 0);
                        timeDS.FlushCache();
                    }


                    tmpDS.Dispose();
                    Thread.Sleep(1);
                    if (FP.Canceled)
                    {
                        Thread.Sleep(500);

                        FP.Finish();
                        throw new OperationCanceledException("操作被用户取消。");
                    }
                }
                FP.Finish();
                rangeDS.Dispose();
                depthDS.Dispose();
                timeDS.Dispose();
                return(true);
            }
            catch (Exception err)
            {
                MessageBox.Show(err.ToString());
                return(false);
            }
        }
Esempio n. 7
0
        /// <summary>
        /// 导出当前视图。
        /// </summary>
        /// <param name="InputImg">影像对象。</param>
        /// <param name="OutDataType">输出数据类型。</param>
        /// <param name="OutPath">输出路径。</param>
        /// <returns>返回操作成功或失败。</returns>
        public static bool ExportView(Img InputImg, OSGeo.GDAL.DataType OutDataType, string OutPath)
        {
            try
            {
                if (OutPath == InputImg.Path)
                {
                    throw new Exception("输出路径与源文件相同。");
                }
                if (InputImg.GDALDataset == 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 xSize   = InputImg.Width;
                int ySize   = InputImg.Height;
                int Bandnum = 3;
                if (InputImg.IsGrayscale)
                {
                    Bandnum = 1;
                }
                else
                {
                    Bandnum = 3;
                }

                FrmProgress FP = new FrmProgress()
                {
                    Text = "正在导出影像...",
                };

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

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

                for (int i = 0; i < Bandnum; i++) //遍历每个波段
                {
                    FP.SetProgress2("正在处理", i + 1, Bandnum, "波段");
                    for (int Row = 0; Row < ySize; Row++)   //遍历每一行(y)
                    {
                        FP.SetProgress1("正在处理", Row + 1, ySize, "行");
                        double[] Values = new double[xSize];

                        //读取DN到数组
                        InputImg.GDALDataset.GetRasterBand(InputImg.BandList[i]).ReadRaster(0, Row, xSize, 1, Values, xSize, 1, 0, 0);
                        for (int Col = 0; Col < xSize; Col++)   //对每一个值进行计算
                        {
                            //无拉伸不做处理直接导出
                            if (InputImg.StretchMode == 0)
                            {
                                break;
                            }
                            //已经有处理的情形
                            switch (InputImg.StretchMode)
                            {
                            case 1:
                            case 2:
                            case 3:
                            case 4:
                            case 9:
                            {
                                //线性
                                Values[Col] = LinearStretch(Values[Col], InputImg.StretchInfo[InputImg.BandList[i] - 1].Item1, InputImg.StretchInfo[InputImg.BandList[i] - 1].Item2);
                                break;
                            }

                            case 5:
                            {
                                //直方图均衡
                                Values[Col] = EqualizationStretch(Values[Col], InputImg.CumulativeProbability[InputImg.BandList[i] - 1], InputImg.Min[InputImg.BandList[i] - 1], InputImg.Max[InputImg.BandList[i] - 1]);
                                break;
                            }

                            case 6:
                            {
                                //高斯
                                Values[Col] = GaussianStretch(Values[Col], InputImg.CumulativeProbability[InputImg.BandList[i] - 1], InputImg.Min[InputImg.BandList[i] - 1], InputImg.Mean[InputImg.BandList[i] - 1], InputImg.Stddev[InputImg.BandList[i] - 1]);
                                break;
                            }

                            case 7:
                            {
                                //平方根
                                Values[Col] = SquarerootStretch(Values[Col], InputImg.Min[InputImg.BandList[i] - 1], InputImg.Max[InputImg.BandList[i] - 1]);
                                break;
                            }

                            case 8:
                            {
                                //对数
                                Values[Col] = LinearStretch(LogarithmicStretch(Values[Col], InputImg.Min[InputImg.BandList[i] - 1], InputImg.Max[InputImg.BandList[i] - 1]), InputImg.Min[InputImg.BandList[i] - 1], InputImg.Max[InputImg.BandList[i] - 1]);
                                break;
                            }

                            default:
                            {
                                //不是0-9还能是啥?
                                throw new Exception("拉伸模式未知。");
                            }
                            }
                        }
                        //写结果到新栅格
                        DS.GetRasterBand(i + 1).WriteRaster(0, Row, xSize, 1, Values, xSize, 1, 0, 0);
                        DS.FlushCache();
                        Thread.Sleep(1);
                        if (FP.Canceled)
                        {
                            Thread.Sleep(500);

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

                FP.Finish();
                Dri.Dispose();
                DS.Dispose();
                return(true);
            }
            catch (Exception err)
            {
                MessageBox.Show(err.Message);
                return(false);
            }
        }
Esempio n. 8
0
        /// <summary>
        /// 平滑锐化算法。
        /// </summary>
        /// <param name="InputDS">输入的栅格数据集。</param>
        /// <param name="OutDataType">输出的数据类型。</param>
        /// <param name="Method">平滑锐化方法。</param>
        /// <param name="OutPath">输出栅格数据集的位置。</param>
        /// <returns>返回操作成功或失败。</returns>
        public static bool SmoothSharpening(OSGeo.GDAL.Dataset InputDS, OSGeo.GDAL.DataType OutDataType, SmoothShapeninngMethods Method, 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 xSize = InputDS.RasterXSize;
                int ySize = InputDS.RasterYSize;

                FrmProgress FP = new FrmProgress()
                {
                    Text = "正在进行平滑锐化操作...",
                };

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

                FP.Output("选择的平滑/锐化方法为:\"" + (typeof(SmoothShapeninngMethods).GetField((Method).ToString()).GetCustomAttributes(false)[0] as DescriptionAttribute).Description + "\"");
                OSGeo.GDAL.Dataset DS = Dri.Create(OutPath, xSize, ySize, InputDS.RasterCount, OutDataType, null);
                FP.Output("已创建输出数据集\"" + OutPath + "\",数据类型为" + OutDataType.ToString() + "。");
                Tools.Common.CopyMetadata(InputDS, DS);

                for (int band = 0; band < InputDS.RasterCount; band++) //遍历每个波段
                {
                    FP.SetProgress1("正在处理", band + 1, InputDS.RasterCount, "波段");
                    for (int Row = 0; Row < ySize - 2; Row++)   //从第1行遍历至倒数第三行
                    {
                        FP.SetProgress2("正在处理", Row, ySize - 2, "行");
                        double[] Values = new double[3 * xSize];                                              //读取的数值
                        double[] Result = new double[xSize];                                                  //结果数值
                        InputDS.GetRasterBand(band + 1).ReadRaster(0, Row, xSize, 3, Values, xSize, 3, 0, 0); //读取3行
                        Array.Copy(Values, xSize, Result, 0, xSize);                                          //
                        for (int Col = 0; Col < xSize - 2; Col++)                                             //对每一个值进行计算
                        {
                            double[,] Input = new double[3, 3];
                            for (int i = 0; i < 3; i++)
                            {
                                Input[i, 0] = Values[Col + i * xSize];
                                Input[i, 1] = Values[Col + i * xSize + 1];
                                Input[i, 2] = Values[Col + i * xSize + 2];
                            }
                            Result[Col + 1] = SmoothSharpening(Input, Method);    //计算输入数据中心像元的值
                        }
                        //写结果到新栅格
                        DS.GetRasterBand(band + 1).WriteRaster(0, Row + 1, xSize, 1, Result, xSize, 1, 0, 0);
                    }
                    if ((Method.ToString()).Contains("Smooth"))
                    {
                        double[] row = new double[xSize];
                        InputDS.GetRasterBand(band + 1).ReadRaster(0, 0, xSize, 1, row, xSize, 1, 0, 0);         //读取第一行
                        DS.GetRasterBand(band + 1).WriteRaster(0, 0, xSize, 1, row, xSize, 1, 0, 0);
                        InputDS.GetRasterBand(band + 1).ReadRaster(0, ySize - 1, xSize, 1, row, xSize, 1, 0, 0); //读取最后一行
                        DS.GetRasterBand(band + 1).WriteRaster(0, ySize - 1, xSize, 1, row, xSize, 1, 0, 0);
                    }
                    DS.FlushCache();
                    Thread.Sleep(1);
                    if (FP.Canceled)
                    {
                        Thread.Sleep(500);

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

                FP.Finish();
                Dri.Dispose();
                DS.Dispose();
                return(true);
            }
            catch (Exception err)
            {
                MessageBox.Show(err.ToString());
                return(false);
            }
        }
Esempio n. 9
0
        /// <summary>
        /// 迭代阈值法寻找分割阈值。
        /// </summary>
        /// <param name="InputDS">输入的数据集。</param>
        /// <param name="ThresholdDiff">前后阈值之差的变化限值,小于此值则终止循环。</param>
        /// <returns>最优阈值。</returns>
        public static double IterateThreshold(OSGeo.GDAL.Dataset InputDS, double ThresholdDiff = 1)
        {
            try
            {
                if (InputDS == null)
                {
                    throw new ArgumentNullException("输入数据集为空。");
                }
                if (InputDS.RasterCount != 1)
                {
                    throw new ArgumentException("输入的数据集波段大于1。");
                }

                FrmProgress FP = new FrmProgress()
                {
                    Text = "正在使用迭代阈值法寻找分割阈值...",
                };

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

                FP.Output("正在计算影像统计数据...");
                Tools.Common.ComputeRasterMinMax(InputDS.GetRasterBand(1), out double Min, out double Max);

                //初始阈值及新阈值。
                double tmpThreshold = (Min + Max) / 2.0;
                double newThreshold = 1000000;
                double Diff         = 1000000; //迭代T值之差。

                FP.Output("最小值:" + Min.ToString() + "\r\n最大值:" + Max.ToString() + "\r\n变化阈值:" + ThresholdDiff.ToString());

                while (Diff >= ThresholdDiff)
                {
                    FP.SetProgress1("阈值变化", ThresholdDiff, Diff, "");
                    //前景、背景像元平均值及计数。
                    double foregroundAvg = 0.0, backgroundAvg = 0.0;
                    int    foregroundCount = 0, backgroundCount = 0;

                    for (int row = 0; row < InputDS.RasterYSize; row++)
                    {
                        FP.SetProgress2("迭代已处理", row + 1, InputDS.RasterYSize, "行");
                        double[] tmp = new double[InputDS.RasterXSize];
                        InputDS.GetRasterBand(1).ReadRaster(0, row, InputDS.RasterXSize, 1, tmp, InputDS.RasterXSize, 1, 0, 0);
                        for (int col = 0; col < InputDS.RasterXSize; col++)
                        {
                            //逐像元累加前、背景计数和总和。
                            if (ThresholdCheck(tmp[col], tmpThreshold))
                            {
                                foregroundCount++;
                                foregroundAvg += tmp[col];
                            }
                            else
                            {
                                backgroundCount++;
                                backgroundAvg += tmp[col];
                            }
                        }
                    }
                    foregroundAvg /= foregroundCount;
                    backgroundAvg /= backgroundCount;
                    newThreshold   = (foregroundAvg + backgroundAvg) / 2.0;
                    Diff           = Math.Abs(newThreshold - tmpThreshold); //阈值差
                    tmpThreshold   = newThreshold;
                    FP.Output("新的阈值:" + newThreshold.ToString());
                    Thread.Sleep(1);
                    if (FP.Canceled)
                    {
                        Thread.Sleep(500);

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

                FP.Finish();
                return(newThreshold);
            }
            catch (Exception err)
            {
                MessageBox.Show(err.Message);
                return(0);
            }
        }
Esempio n. 10
0
        /// <summary>
        /// Otsu(最大类间方差法)寻找分割阈值。
        /// </summary>
        /// <param name="InputDS">输入的数据集。</param>
        /// <param name="Divide">将最大最小值区间内分割为的份数。</param>
        /// <returns>最优阈值。</returns>
        public static double Otsu(OSGeo.GDAL.Dataset InputDS, int Divide = 256)
        {
            try
            {
                if (InputDS == null)
                {
                    throw new ArgumentNullException("输入数据集为空。");
                }
                if (InputDS.RasterCount != 1)
                {
                    throw new ArgumentException("输入的数据集波段大于1。");
                }

                double[]    g  = new double[Divide];
                FrmProgress FP = new FrmProgress()
                {
                    Text = "正在使用Otsu法寻找分割阈值...",
                };

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

                FP.Output("正在计算影像统计数据...");
                Tools.Common.ComputeRasterMinMax(InputDS.GetRasterBand(1), out double Min, out double Max);
                FP.Output("最小值:" + Min.ToString() + "\r\n最大值:" + Max.ToString() + "\r\n分割段数:" + Divide.ToString());

                for (int i = 1; i <= Divide; i++)
                {
                    FP.SetProgress2("正在计算:", i, Divide, "区间");
                    double foregroundRatio = 0.0, foregroundAvg = 0.0, backgroundRatio = 0.0, backgroundAvg = 0.0;
                    int    foregroundCount = 0, backgroundCount = 0;
                    double tmpThreshold = Min + (Max - Min) * ((double)i / Divide);
                    for (int row = 0; row < InputDS.RasterYSize; row++)
                    {
                        FP.SetProgress1("正在处理:", row + 1, InputDS.RasterYSize, "行");
                        double[] tmp = new double[InputDS.RasterXSize];
                        InputDS.GetRasterBand(1).ReadRaster(0, row, InputDS.RasterXSize, 1, tmp, InputDS.RasterXSize, 1, 0, 0);
                        for (int col = 0; col < InputDS.RasterXSize; col++)
                        {
                            //逐像元累加前、背景计数和总和。
                            if (ThresholdCheck(tmp[col], tmpThreshold))
                            {
                                foregroundCount++;
                                foregroundAvg += tmp[col];
                            }
                            else
                            {
                                backgroundCount++;
                                backgroundAvg += tmp[col];
                            }
                        }
                    }
                    foregroundRatio = (double)foregroundCount / (foregroundCount + backgroundCount);
                    foregroundAvg  /= foregroundCount;
                    backgroundRatio = (double)backgroundCount / (foregroundCount + backgroundCount);
                    backgroundAvg  /= backgroundCount;
                    double totalGrayAvg = foregroundRatio * foregroundAvg + backgroundRatio * backgroundAvg;
                    g[i - 1] = foregroundRatio * backgroundRatio * Math.Pow(foregroundAvg - backgroundAvg, 2);
                    Thread.Sleep(1);
                    if (FP.Canceled)
                    {
                        Thread.Sleep(500);

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

                //找一个最小值
                int    index = 0;
                double max   = -100000000;
                for (int i = 0; i < Divide; i++)
                {
                    if (g[i] > max)
                    {
                        max   = g[i];
                        index = i;
                    }
                }

                FP.Finish();
                return(Min + (Max - Min) * ((double)index / (Divide - 1)));
            }
            catch (Exception err)
            {
                MessageBox.Show(err.Message);
                return(0);
            }
        }
Esempio n. 11
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);
            }
        }
Esempio n. 12
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);
            }
        }