基于ArcEngine进行地物分类景观指数计算

来源:互联网 发布:淘宝hd降版本 编辑:程序博客网 时间:2024/04/28 17:31

前两天写了一个对地物分类进行景观评价的小工具,采用ArcEngine实现,在此备忘一下,仅供学习参考.


核心过程如下:根据评价尺度大小分块获取影响,分别对各个分块进行地物统计,计算景观指数,将该得分保存在分块中心点位置.

        // rst        : 原始地物分类影像        // patchSize  : 分块大小,正方形边长,为该计算单元包含像元个数        // shpFile    : 结果保存路径,点状要素类,保存为ShpeFile文件        private void runModel(Raster rst, int patchSize, string shpFile)        {            #region 准备工作                        // 获取背景值            dynamic nodata = ((rst as IRasterBandCollection).Item(0) as IRasterProps).NoDataValue;            appendMessage("\tNodataValue = " + nodata);            // 初始化分块辅助工具            var rstProps = rst as IRasterProps;            var pixelSize = rstProps.MeanCellSize();            var rstExt = rstProps.Extent;            var pbHelper = new PixelBlockHelper(rstProps.Width, rstProps.Height,pixelSize.X, pixelSize.Y,                        rstExt.XMin, rstExt.XMax, rstExt.YMin, rstExt.YMax);            long pbCount = pbHelper.GetCount(patchSize);            int pbCols = pbHelper.GetColumns(patchSize);            int pbRows = pbHelper.GetRows(patchSize);            appendMessage("\tPatch Number : " + pbRows + "(Row) X " + pbCols + "(Col) = " + pbCount);            // 初始化分块游标            IRaster2 rst2 = rst as IRaster2;            var patchCursor = rst2.CreateCursorEx(new Pnt() { X = patchSize, Y = patchSize });            // 创建shapefile文件并开启编辑状态            var scoreName = "pjz";            var resultShp = CommonFuns.pointShp(shpFile, rstProps.SpatialReference, scoreName);            IFeatureClassWrite shpWriter = resultShp as IFeatureClassWrite;            IWorkspaceEdit shpWpsEdit = (shpWriter as IDataset).Workspace as IWorkspaceEdit;            shpWpsEdit.StartEditing(true);            shpWpsEdit.StartEditOperation();            var scoreFieldIndex = resultShp.FindField(scoreName);            // 进度指示器            long doneStep = pbCount / 10;                           // 每隔 10% 播报进度            long doneCount = 0;                                     // 当前进度            GeoLandEvaluator glEvaluator = new GeoLandEvaluator();  // 初始化地物评价工具            IFeature resultFeature;                                 // 评价结果要素            #endregion            #region 地物景观指数计算            ESRI.ArcGIS.esriSystem.ISet featureSet = new ESRI.ArcGIS.esriSystem.Set();            do            {                glEvaluator.Reset();                                // 重置评价工具                var block = patchCursor.PixelBlock as IPixelBlock3;                dynamic lands = block.get_PixelData(0);             // 获取分快像元值,System.Array                for (int x = 0; x < block.Width; x++)               // 扫描像元值填充入评价工具,过滤背景值                {                    for (int y = 0; y < block.Height; y++)                    {                        dynamic landType = lands.GetValue(x, y);                        if (nodata != landType) glEvaluator.AddLand((int)landType);                    }                }                var score = glEvaluator.Score();                    // 计算得分                var tl = patchCursor.TopLeft;                       // 计算中心点位置                var cxy = pbHelper.GetCenter(tl.X, tl.Y, patchSize);                // 保存计算结果,播报进度                resultFeature = resultShp.CreateFeature();                resultFeature.Shape = new ESRI.ArcGIS.Geometry.Point()                {                    X = cxy[0],                    Y = cxy[1]                };                resultFeature.set_Value(scoreFieldIndex, score);                featureSet.Add(resultFeature);                 doneCount++;                if (doneCount % doneStep == 0)                {                    shpWriter.WriteFeatures(featureSet);                    featureSet.RemoveAll();                    appendMessage("\t...  " + (100.0 * doneCount / pbCount) + " %  ...");                }            } while (patchCursor.Next());            shpWriter.WriteFeatures(featureSet);            featureSet.RemoveAll();            #endregion            // 关闭编辑状态,保存数据            shpWpsEdit.StopEditOperation();            shpWpsEdit.StopEditing(true);            appendMessage("<< Finished! ");        }


地物评价工具工作过程为:统计分块内各种类型的地物面积大小,计算各类地物的百分比 Pi ,采用如下公式计算景观指数得分——

 score = -(P1*ln(P1)+P2*ln(P2)+...+Pn*ln(Pn))

using System;using System.Collections.Generic;namespace ...{    /// <summary>    /// 地物类别统计评估工具    /// </summary>    public class GeoLandEvaluator    {        /// <summary>        /// 地物分类计数器        /// </summary>        private IDictionary<int, long> landCounter = null;        /// <summary>        /// 地物总数        /// </summary>        private long landSum = 0;        public GeoLandEvaluator()        {            landCounter = new Dictionary<int, long>();            Reset();        }        /// <summary>        /// 重置地物统计评估工具        /// </summary>        public void Reset()        {            if (landCounter != null) landCounter.Clear();             landSum = 0;        }        /// <summary>        /// 添加分类        /// </summary>        public void AddLand(int landType)        {            if (landCounter.ContainsKey(landType))            {                landCounter[landType]++;            }            else            {                landCounter.Add(landType, 1);            }            landSum++;        }        /// <summary>        /// 添加地物分类        /// </summary>        public void AddLand(int[] landTypes)        {            foreach (int ldType in landTypes)            {                AddLand(ldType);            }        }        /// <summary>        /// 计算景观指数评价值        /// </summary>        /// <returns></returns>        public double Score()        {            if (landCounter == null || landCounter.Count < 1) return 0;            double score = 0.0;            foreach (long ldCount in landCounter.Values)            {                double per = 1.0 * ldCount / landSum;                score += per * Math.Log(per, Math.E);            }            return score * (-1.0);        }    }}


栅格像元分块辅助工具

using System;namespace ...{    /// <summary>    /// 栅格像元分块辅助工具    /// </summary>    public class PixelBlockHelper    {        public double PixelWidth { get; private set; }        public double PixelHeight { get; private set; }        public int RstWidth { get; private set; }        public int RstHeight { get; private set; }        public double RstXMin { get; private set; }        public double RstYMin { get; private set; }        public double RstXMax { get; private set; }        public double RstYMax { get; private set; }        public PixelBlockHelper(int rstWidth, int rstHeight,double pixelWidth, double pixelHeight,            double rstXmin, double rstXmax, double rstYmin, double rstYmax)        {            this.RstWidth = rstWidth;            this.RstHeight = rstHeight;            this.PixelWidth = pixelWidth;            this.PixelHeight = pixelHeight;            this.RstXMin = rstXmin;            this.RstXMax = rstXmax;            this.RstYMin = rstYmin;            this.RstYMax = rstYmax;        }        /// <summary>        /// 计算 分块 中心坐标 , 计算原点为影像(可视)左上角        /// </summary>        /// <param name="xOffset">左上角横轴偏移量</param>        /// <param name="yOffset">左上角纵轴偏移量</param>        /// <param name="blockSize">正方形分块大小,边长</param>        /// <returns>分块中心点 地图坐标</returns>        public double[] GetCenter(double xOffset, double yOffset, int blockSize)        {            double[] xyOffset = new double[] { xOffset, yOffset };            return GetCenter(xyOffset, blockSize);        }        /// <summary>        /// 计算 分块 中心坐标 , 计算原点为影像(可视)左上角        /// </summary>        /// <param name="xyOffset">左上角偏移量,[x,y]</param>        /// <param name="blockSize">正方形分块大小,边长</param>         /// <returns>分块中心点 地图坐标</returns>        public double[] GetCenter(double[] xyOffset, int blockSize)        {            xyOffset[0] = PixelWidth * (xyOffset[0] + blockSize / 2.0) + RstXMin;            xyOffset[1] = RstYMax - PixelHeight * (xyOffset[1] + blockSize / 2.0);            return xyOffset;        }        /// <summary>        /// 计算分块 总数        /// </summary>        /// <returns>可划分的大小为 blockSize 的正方形分块总数</returns>        public long GetCount(int blockSize)        {            return (long)GetColumns(blockSize) * GetRows(blockSize);        }        /// <summary>        /// 计算X方向 分块 列数        /// </summary>        /// <returns>以blockSize为间隔可划分的列数</returns>        public int GetColumns(int blockSize)        {            return (int)Math.Ceiling((double)(this.RstWidth) / blockSize);        }        /// <summary>        /// 计算 Y方向 分块 行数        /// </summary>        /// <returns>以blockSize为间隔可划分的行数</returns>        public int GetRows(int blockSize)        {            return (int)Math.Ceiling((double)(this.RstHeight) / blockSize);        }    }}


创建Shpefile文件核心代码如下:

/// <summary>        /// 创建 点 Shapefile        /// </summary>        /// <param name="shpFile">完整的保存路径</param>        /// <param name="spatialRef">参考坐标系</param>        /// <param name="scoreName">属性值字段名称(double类型字段),默认为 pjz</param>        /// <returns>包含字段类型为double名称为scoreName的shapefile要素类</returns>        public static IFeatureClass pointShp(string shpFile, ISpatialReference spatialRef, string scoreName = "pjz")        {            FileInfo fi = new FileInfo(shpFile);            var wpsDir = fi.DirectoryName;   // shapefile保存目录            var shapeFiledName = "Shape";            var fidFieldName = "FID";            if (string.IsNullOrEmpty(scoreName)) scoreName = "pjz";            //            var factory = new ShapefileWorkspaceFactory() as IWorkspaceFactory;            var shpWps = (IFeatureWorkspace)factory.OpenFromFile(wpsDir, 0);            // prepare fileds for the shapefile            Fields fieldCollection = new Fields();            IFieldsEdit fieldCollectionEdit = fieldCollection as IFieldsEdit;            // 设置FID            Field field = new Field();            IFieldEdit fieldEdit = field as IFieldEdit;            fieldEdit.Name_2 = fidFieldName;            fieldEdit.Type_2 = esriFieldType.esriFieldTypeOID;            fieldCollectionEdit.AddField(field);            // 设置几何类型字段            field = new Field();            fieldEdit = field as IFieldEdit;            fieldEdit.Name_2 = shapeFiledName;            fieldEdit.Type_2 = esriFieldType.esriFieldTypeGeometry;            GeometryDef geoDef = new GeometryDef();            IGeometryDefEdit geoDefEdit = geoDef as IGeometryDefEdit;            geoDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPoint;            geoDefEdit.SpatialReference_2 = spatialRef;            fieldEdit.GeometryDef_2 = geoDef;            fieldCollectionEdit.AddField(field);            // 设置景观指数评价值字段            field = new Field();            fieldEdit = field as IFieldEdit;            fieldEdit.Name_2 = scoreName;            fieldEdit.Type_2 = esriFieldType.esriFieldTypeDouble;            fieldCollectionEdit.AddField(field);            //            var shp = shpWps.CreateFeatureClass(fi.Name, fieldCollection, null, null,                      esriFeatureType.esriFTSimple,shapeFiledName, string.Empty);            return shp;        }


直接上图吧~




1 0