ラプラシアン図とエッジ図を作成してみました。

概要

f:id:Chiakikun:20211230000905p:plain

DEM

ラプラシアン

エッジ図

 

コード

using System;
using System.Runtime.InteropServices;

using DotSpatial.Data;
using DotSpatial.Data.Rasters.GdalExtension;

namespace Laplacianzu
{
    class Program
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        static extern bool SetDllDirectory(string lpPathName);

        static void Main(string[] args)
        {
            string dllpath = @"D:\DotSpatial-master\Source\bin\Debug\Windows Extensions\DotSpatial.Data.Rasters.GdalExtension\gdal\x86";
            string loadfilepath = @"D:\DEM.tif";
            string savelappath = @"D:\ラプラシアン.tif";
            string saveedgpath = @"D:\エッジ.tif";

            SetDllDirectory(dllpath);

            // GeoTiff読み込み
            GdalRasterProvider d = new GdalRasterProvider();
            IRaster src = d.Open(loadfilepath);

            int ncol = src.NumColumns;
            int nrow = src.NumRows;
            int band_num = src.NumBands;
            string prj = src.ProjectionString;
            double nodata = src.NoDataValue;

            double[] pGT = src.Bounds.AffineCoefficients;
            double xllcenter = pGT[0];
            double cellsize_x = pGT[1];
            double rotate1 = pGT[2];
            double yllcenter = pGT[3];
            double rotate2 = pGT[4];
            double cellsize_y = pGT[5];

            // GeoTiff書き出し先作成
            IRaster lap = Raster.CreateRaster(savelappath, null, ncol, nrow, 1, typeof(float), new[] { string.Empty });
            lap.NoDataValue = nodata;
            lap.ProjectionString = prj;
            lap.Bounds = new RasterBounds(nrow, ncol, new double[] { xllcenter - cellsize_x / 2, cellsize_x, 0, yllcenter - cellsize_y / 2, 0, cellsize_y });
            IRaster edg = Raster.CreateRaster(saveedgpath, null, ncol, nrow, 1, typeof(float), new[] { string.Empty });
            edg.NoDataValue = nodata;
            edg.ProjectionString = prj;
            edg.Bounds = new RasterBounds(nrow, ncol, new double[] { xllcenter - cellsize_x / 2, cellsize_x, 0, yllcenter - cellsize_y / 2, 0, cellsize_y });

            Laplacianzu(src.Value, nrow, ncol, lap.Value, edg.Value);

            lap.Save();
            edg.Save();

            Console.WriteLine("終了しました。");
            Console.ReadKey();
            return;
        }


        static void Laplacianzu(IValueGrid src, int nrow, int ncol, IValueGrid lap, IValueGrid edg)
        {
            double dx = 8.763;
            double dy = 12.348;

            for (int x = 0; x < ncol; x++)
            {
                for (int y = 0; y < nrow; y++)
                {
                    lap[y, x] = -9999;
                    edg[y, x] = -9999;

                    if ((x < 1) || (y < 1) || (x >= ncol - 1) || (y >= nrow - 1)) continue;
                    double H11 = src[y - 1, x - 1]; if (H11 == -9999) continue;
                    double H12 = src[y - 1, x];     if (H12 == -9999) continue;
                    double H13 = src[y - 1, x + 1]; if (H13 == -9999) continue;
                    double H21 = src[y, x - 1];     if (H21 == -9999) continue;
                    double H22 = src[y, x];         if (H22 == -9999) continue;
                    double H23 = src[y, x + 1];     if (H23 == -9999) continue;
                    double H31 = src[y + 1, x - 1]; if (H31 == -9999) continue;
                    double H32 = src[y + 1, x];     if (H32 == -9999) continue;
                    double H33 = src[y + 1, x + 1]; if (H33 == -9999) continue;

                    double I = ((H21 + H23) - 2 * H22) / Math.Pow(dx, 2) + ((H12 + H32) - 2 * H22) / Math.Pow(dy, 2);

                    lap[y, x] = I;
                    edg[y, x] = Math.Abs(I);
                }
            }
            return;
        }
    }
}

準備

f:id:Chiakikun:20211230001444p:plain

前回同様「DotSpatial.Data.dll」と「DotSpatial.Data.Rasters.GdalExtension.dll」を参照に追加してからソースをコンパイルしてください。

出力結果

下図の左下は地形の変化が少ないのでラプラシアン図、エッジ図も白い部分が多く、右上は変化が多いので色が出ている部分が多くなっています。

地理院地図 出典:国土地理院 (https://cyberjapandata.gsi.go.jp

ラプラシアン

エッジ図

幌延地域を対象とした10mグリッド数値標高モデルを用いた精密地形解析図の作成』を参考に各種フィルタ作成をしてきましたが、これで終わりです。ご覧いただきありがとうございました。

高度分散量異常量図を作成

概要

DEM

高度分散量異常図

 

コード

using System;
using System.Runtime.InteropServices;
using System.Linq;

using DotSpatial.Data;
using DotSpatial.Data.Rasters.GdalExtension;

using System.Collections.Generic;

namespace KodoBunsanryoIjouzu
{
    class Program
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        static extern bool SetDllDirectory(string lpPathName);

        static void Main(string[] args)
        {
            string dllpath = @"D:\DotSpatial-master\Source\bin\Debug\Windows Extensions\DotSpatial.Data.Rasters.GdalExtension\gdal\x86";
            string loaddempath =  @"D:\DEM.tif";
            string loadkodopath = @"D:\高度分散量図.tif";
            string savefilepath = @"D:\保存先.tif";

            SetDllDirectory(dllpath);

            // GeoTiff読み込み
            GdalRasterProvider d = new GdalRasterProvider();
            IRaster dem = d.Open(loaddempath);
            IRaster kod = d.Open(loadkodopath);

            int ncol = dem.NumColumns;
            int nrow = dem.NumRows;
            int band_num = dem.NumBands;
            string prj = dem.ProjectionString;
            double nodata = dem.NoDataValue;

            double[,] avgKodoBunsan = AvgKodoBunsanryo(dem.Value, kod.Value, nrow, ncol);
            double [] keisu = GetKinjiKeisu(avgKodoBunsan);

            double[] pGT = dem.Bounds.AffineCoefficients;
            double xllcenter = pGT[0];
            double cellsize_x = pGT[1];
            double rotate1 = pGT[2];
            double yllcenter = pGT[3];
            double rotate2 = pGT[4];
            double cellsize_y = pGT[5];

            // GeoTiff書き出し先作成
            IRaster dst = Raster.CreateRaster(savefilepath, null, ncol, nrow, 1, typeof(float), new[] { string.Empty });
            dst.NoDataValue = nodata;
            dst.ProjectionString = prj;
            dst.Bounds = new RasterBounds(nrow, ncol, new double[] { xllcenter - cellsize_x / 2, cellsize_x, 0, yllcenter - cellsize_y / 2, 0, cellsize_y });

            Ijouzu(dem.Value, kod.Value, nrow, ncol, dst.Value, keisu);
            dst.Save();

            Console.WriteLine("終了しました。");
            Console.ReadKey();
            return;
        }

        static double[,] AvgKodoBunsanryo(IValueGrid dem, IValueGrid kodo, int nrow, int ncol)
        {
            List[] avgs = new List[29]; // 幌延町だとこのくらい必要
            for (int i = 0; i < avgs.Length; i++)
                avgs[i] = new List();

            for (int x = 0; x < ncol; x++)
            {
                for (int y = 0; y < nrow; y++)
                {
                    if (dem[y, x] <= -9999)
                        continue;
                    int idx = (int)dem[y, x] / 25;
                    avgs[idx].Add(kodo[y, x]);
                }
            }

            double[,] ret = new double[avgs.Length, 2];
            for (int i = 0; i < avgs.Length; i++)
            {
                ret[i, 0] = i * 25;
                ret[i, 1] = avgs[i].Sum() / avgs[i].Count;
            }
            return ret;
        }


        static public double[] GetKinjiKeisu(double[,] pnts)
        {
            double[,] Det_a = new double[4, 4];
            double[,] Inv_a = new double[4, 4];
            double[,] Det_b = new double[4, 1];
            double[,] Det_c = new double[4, 1];
            double buf;
            int m = 4;

            for (int i = 1; i < pnts.GetLength(0) - 2; i++) // 資料の見た目に合わせるために調整した
            {
                double x6 = Math.Pow(pnts[i, 0], 6);
                double x5 = Math.Pow(pnts[i, 0], 5);
                double x4 = Math.Pow(pnts[i, 0], 4);
                double x3 = Math.Pow(pnts[i, 0], 3);
                double x2 = Math.Pow(pnts[i, 0], 2);
                double x  = pnts[i, 0];

                Det_a[0, 0] += x6; Det_a[0, 1] += x5; Det_a[0, 2] += x4; Det_a[0, 3] += x3;
                Det_a[1, 0] += x5; Det_a[1, 1] += x4; Det_a[1, 2] += x3; Det_a[1, 3] += x2;
                Det_a[2, 0] += x4; Det_a[2, 1] += x3; Det_a[2, 2] += x2; Det_a[2, 3] += x;
                Det_a[3, 0] += x3; Det_a[3, 1] += x2; Det_a[3, 2] += x;  Det_a[3, 3] = 26;

                Det_b[0, 0] += x3 * pnts[i, 1];
                Det_b[1, 0] += x2 * pnts[i, 1];
                Det_b[2, 0] += x  * pnts[i, 1];
                Det_b[3, 0] += pnts[i, 1];
            }
            
            for (int i = 0; i < m; i++)
                for (int j = 0; j < m; j++)
                    Inv_a[i, j] = (i == j) ? 1.0 : 0.0;

            for (int i = 0; i < m; i++)
            {
                buf = 1 / Det_a[i, i];
                for (int j = 0; j < m; j++)
                {
                    Det_a[i, j] *= buf;
                    Inv_a[i, j] *= buf;
                }
                for (int j = 0; j < m; j++)
                    if (i != j)
                    {
                        buf = Det_a[j, i];
                        for (int k = 0; k < m; k++)
                        {
                            Det_a[j, k] -= Det_a[i, k] * buf;
                            Inv_a[j, k] -= Inv_a[i, k] * buf;
                        }
                    }
            }

            for (int i = 0; i < 4; i++)
                for (int j = 0; j < 1; j++)
                    for (int k = 0; k < 4; k++)
                        Det_c[i, j] += Inv_a[i, k] * Det_b[k, j];

            double[] result = new double[4];
            result[0] = Det_c[0, 0];
            result[1] = Det_c[1, 0];
            result[2] = Det_c[2, 0];
            result[3] = Det_c[3, 0];
            return result;
        }


        static void Ijouzu(IValueGrid dem, IValueGrid kodo, int nrow, int ncol, IValueGrid dst, double []keisu)
        {
            double a = keisu[0];
            double b = keisu[1];
            double c = keisu[2];
            double d = keisu[3];

            for (int x = 0; x < ncol; x++)
            {
                for (int y = 0; y < nrow; y++)
                {
                    if (dem[y, x] <= -9999) continue;

                    double kinji = a * Math.Pow(dem[y, x], 3) + b * Math.Pow(dem[y, x], 2) + c * dem[y, x] + d;
                    dst[y, x] = kodo[y, x] - kinji;
                }
            }
            return;
        }
    }
}

メモ コードの37行目で平均高度分散量(下図の青色線)、38行目で高度分散量近似曲線(下図の橙色線)を取得しています。参考資料に合わせたかったのでプログラムを調整しています。

平均高度分散量と高度分散量近似曲線

準備

f:id:Chiakikun:20211230001444p:plain

前回同様「DotSpatial.Data.dll」と「DotSpatial.Data.Rasters.GdalExtension.dll」を参照に追加してからソースをコンパイルしてください。

出力結果

高度分散量異常量図

高度分散量図

 

近似曲線から特に大きく外れている箇所の高度分散量図と高度分散量異常量図を並べてみました。何で大きく外れることとなったのかは...わかりません。


最後までご覧いただき、ありがとうございました。

高度分散量図を作成

概要

DEM

高度分散量図

コード

using System;
using System.Runtime.InteropServices;

using DotSpatial.Data;
using DotSpatial.Data.Rasters.GdalExtension;

using System.Collections.Generic;

namespace KodoBunsanryozu
{
    class Program
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        static extern bool SetDllDirectory(string lpPathName);

        static void Main(string[] args)
        {
            string dllpath = @"D:\DotSpatial-master\Source\bin\Debug\Windows Extensions\DotSpatial.Data.Rasters.GdalExtension\gdal\x86";
            string loadfilepath = @"D:\DEM.tif";
            string savefilepath = @"D:\保存先.tif";

            SetDllDirectory(dllpath);

            // GeoTiff読み込み
            GdalRasterProvider d = new GdalRasterProvider();
            IRaster src = d.Open(loadfilepath);

            int ncol = src.NumColumns;
            int nrow = src.NumRows;
            int band_num = src.NumBands;
            string prj = src.ProjectionString;
            double nodata = src.NoDataValue;

            double[] pGT = src.Bounds.AffineCoefficients;
            double xllcenter = pGT[0];
            double cellsize_x = pGT[1];
            double rotate1 = pGT[2];
            double yllcenter = pGT[3];
            double rotate2 = pGT[4];
            double cellsize_y = pGT[5];

            // GeoTiff書き出し先作成
            IRaster dst = Raster.CreateRaster(savefilepath, null, ncol, nrow, 1, typeof(float), new[] { string.Empty });
            dst.NoDataValue = nodata;
            dst.ProjectionString = prj;
            dst.Bounds = new RasterBounds(nrow, ncol, new double[] { xllcenter - cellsize_x / 2, cellsize_x, 0, yllcenter - cellsize_y / 2, 0, cellsize_y });

            KodoBunsanryo(src.Value, nrow, ncol, dst.Value);

            dst.Save();

            Console.WriteLine("終了しました。");
            Console.ReadKey();
            return;
        }


        static void KodoBunsanryo(IValueGrid src, int nrow, int ncol, IValueGrid dst)
        {
            int r = 5;    // 窓サイズ

            double[,] dsrc = new double[nrow, ncol];
            for (int x = 0; x < ncol; x++)
                for (int y = 0; y < nrow; y++)
                    dsrc[y, x] = src[y, x];

            for (int x = 0; x < ncol; x++)
            {
                for (int y = 0; y < nrow; y++)
                {
                    dst[y, x] = -9999;

                    if (dsrc[y, x] <= -9999)
                        continue;

                    // 窓領域内の平均
                    double cgrid = 0;
                    double sum = 0;
                    for (int m = x - r; m <= x + r; m++)
                    {
                        for (int n = y - r; n <= y + r; n++)
                        {
                            if ((m >= 0) && (n >= 0) && (m < ncol) && (n < nrow) && (dsrc[n, m] > -9999))
                            {
                                sum += dsrc[n, m];
                                cgrid += 1;
                            }
                        }
                    }
                    double avg = sum / cgrid;

                    // 偏差
                    double dev = 0;
                    for (int m = x - r; m <= x + r; m++)
                    {
                        for (int n = y - r; n <= y + r; n++)
                            if ((m >= 0) && (n >= 0) && (m < ncol) && (n < nrow) && (dsrc[n, m] > -9999))
                                dev += Math.Pow(dsrc[n, m] - avg, 2);
                    }
                    dev = Math.Sqrt(dev / cgrid);

                    dst[y, x] = dev;
                }
            }

            return;
        }
    }
}

準備

f:id:Chiakikun:20211230001444p:plain

前回同様「DotSpatial.Data.dll」と「DotSpatial.Data.Rasters.GdalExtension.dll」を参照に追加してからソースをコンパイルしてください。

出力結果

起伏量図だと地形がギザギザ?した感じに見えますが、高度分散量図だと地形がわかり易くなりました。色設定は起伏量図と同じように設定しています。

DEM

起伏量図

高度分散量図


最後までご覧いただき、ありがとうございました。