zoukankan      html  css  js  c++  java
  • GDAL栅格矢量化

    GDAL提供了栅格矢量化等很给力的算法,但是好多算法都是通过Python脚本来提供的,对于没有安装Python环境的用户来说,这些非常有用的功能得到了很大程度的限制。GDAL工具中使用Python提供的就有栅格矢量化的功能,通过实验测试,将分类图进行矢量化后,能够很好的和原图进行匹配,而且也没有错误的多边形,下面就对GDAL中该功能做一个简单的说明。

    GDAL栅格矢量化Python脚本分析,其位置在GDAL源代码目录下的/swig/python/scripts/gdal_polygonize.py,其代码如下:

       1:  
       2: try:
       3:     from osgeo import gdal, ogr, osr
       4: except ImportError:
       5:     import gdal, ogr, osr
       6:  
       7: import sys
       8: import os.path
       9:  
      10: def Usage():
      11:     print("""
      12: gdal_polygonize [-o name=value] [-nomask] [-mask filename] raster_file [-b band]
      13:                 [-q] [-f ogr_format] out_file [layer] [fieldname]
      14: """)
      15:     sys.exit(1)
      16:  
      17: # =============================================================================
      18: #     Mainline
      19: # =============================================================================
      20:  
      21: format = 'GML'
      22: options = []
      23: quiet_flag = 0
      24: src_filename = None
      25: src_band_n = 1
      26:  
      27: dst_filename = None
      28: dst_layername = None
      29: dst_fieldname = None
      30: dst_field = -1
      31:  
      32: mask = 'default'
      33:  
      34: gdal.AllRegister()
      35: argv = gdal.GeneralCmdLineProcessor( sys.argv )
      36: if argv is None:
      37:     sys.exit( 0 )
      38:  
      39: # Parse command line arguments.
      40: i = 1
      41: while i < len(argv):
      42:     arg = argv[i]
      43:  
      44:     if arg == '-f':
      45:         i = i + 1
      46:         format = argv[i]
      47:  
      48:     elif arg == '-q' or arg == '-quiet':
      49:         quiet_flag = 1
      50:         
      51:     elif arg == '-nomask':
      52:         mask = 'none'
      53:         
      54:     elif arg == '-mask':
      55:         i = i + 1
      56:         mask = argv[i]
      57:         
      58:     elif arg == '-b':
      59:         i = i + 1
      60:         src_band_n = int(argv[i])
      61:  
      62:     elif src_filename is None:
      63:         src_filename = argv[i]
      64:  
      65:     elif dst_filename is None:
      66:         dst_filename = argv[i]
      67:  
      68:     elif dst_layername is None:
      69:         dst_layername = argv[i]
      70:  
      71:     elif dst_fieldname is None:
      72:         dst_fieldname = argv[i]
      73:  
      74:     else:
      75:         Usage()
      76:  
      77:     i = i + 1
      78:  
      79: if src_filename is None or dst_filename is None:
      80:     Usage()
      81:  
      82: if dst_layername is None:
      83:     dst_layername = 'out'
      84:     
      85: # =============================================================================
      86: #     Verify we have next gen bindings with the polygonize method.
      87: # =============================================================================
      88: try:
      89:     gdal.Polygonize
      90: except:
      91:     print('')
      92:     print('gdal.Polygonize() not available.  You are likely using "old gen"')
      93:     print('bindings or an older version of the next gen bindings.')
      94:     print('')
      95:     sys.exit(1)
      96:  
      97: # =============================================================================
      98: #    Open source file
      99: # =============================================================================
     100:  
     101: src_ds = gdal.Open( src_filename )
     102:     
     103: if src_ds is None:
     104:     print('Unable to open %s' % src_filename)
     105:     sys.exit(1)
     106:  
     107: srcband = src_ds.GetRasterBand(src_band_n)
     108:  
     109: if mask is 'default':
     110:     maskband = srcband.GetMaskBand()
     111: elif mask is 'none':
     112:     maskband = None
     113: else:
     114:     mask_ds = gdal.Open( mask )
     115:     maskband = mask_ds.GetRasterBand(1)
     116:  
     117: # =============================================================================
     118: #       Try opening the destination file as an existing file.
     119: # =============================================================================
     120:  
     121: try:
     122:     gdal.PushErrorHandler( 'QuietErrorHandler' )
     123:     dst_ds = ogr.Open( dst_filename, update=1 )
     124:     gdal.PopErrorHandler()
     125: except:
     126:     dst_ds = None
     127:  
     128: # =============================================================================
     129: #     Create output file.
     130: # =============================================================================
     131: if dst_ds is None:
     132:     drv = ogr.GetDriverByName(format)
     133:     if not quiet_flag:
     134:         print('Creating output %s of format %s.' % (dst_filename, format))
     135:     dst_ds = drv.CreateDataSource( dst_filename )
     136:  
     137: # =============================================================================
     138: #       Find or create destination layer.
     139: # =============================================================================
     140: try:
     141:     dst_layer = dst_ds.GetLayerByName(dst_layername)
     142: except:
     143:     dst_layer = None
     144:  
     145: if dst_layer is None:
     146:  
     147:     srs = None
     148:     if src_ds.GetProjectionRef() != '':
     149:         srs = osr.SpatialReference()
     150:         srs.ImportFromWkt( src_ds.GetProjectionRef() )
     151:         
     152:     dst_layer = dst_ds.CreateLayer(dst_layername, srs = srs )
     153:  
     154:     if dst_fieldname is None:
     155:         dst_fieldname = 'DN'
     156:         
     157:     fd = ogr.FieldDefn( dst_fieldname, ogr.OFTInteger )
     158:     dst_layer.CreateField( fd )
     159:     dst_field = 0
     160: else:
     161:     if dst_fieldname is not None:
     162:         dst_field = dst_layer.GetLayerDefn().GetFieldIndex(dst_fieldname)
     163:         if dst_field < 0:
     164:             print("Warning: cannot find field '%s' in layer '%s'" % (dst_fieldname, dst_layername))
     165:  
     166: # =============================================================================
     167: #    Invoke algorithm.
     168: # =============================================================================
     169:  
     170: if quiet_flag:
     171:     prog_func = None
     172: else:
     173:     prog_func = gdal.TermProgress
     174:     
     175: result = gdal.Polygonize( srcband, maskband, dst_layer, dst_field, options,
     176:                           callback = prog_func )
     177:     
     178: srcband = None
     179: src_ds = None
     180: dst_ds = None
     181: mask_ds = None

    同时该工具的说明文档见http://www.gdal.org/gdal_polygonize.html,英文的,不过都很容易看明白。查看Python代码发现,其中调用的最重要的函数是一个叫 gdal.Polygonize的函数,在GDAL算法说明文档中找到了这个函数说明,地址为:http://www.gdal.org/gdal__alg_8h.html#3f522a9035d3512b5d414fb4752671b1,如下:

       1: CPLErr CPL_DLL CPL_STDCALL
       2: GDALPolygonize( GDALRasterBandH hSrcBand,                 //输入栅格图像波段
       3:                 GDALRasterBandH hMaskBand,                //掩码图像波段,可以为NULL
       4:                 OGRLayerH hOutLayer,                      //矢量化后的矢量图层
       5:                 int iPixValField,                         //需要将像元DN值写入矢量属性字段的字段索引
       6:                 char **papszOptions,                      //算法选项,目前算法中没有用到,设置为NULL即可
       7:                 GDALProgressFunc pfnProgress,             //进度条回调函数
       8:                 void * pProgressArg );                    //进度条参数

    通过对上面的函数参数进行分析,就可以自己直接调用该函数,使用C/C++语言来对其进行封装,达到我们的目的,下面是我对该函数的一个简单封装,指定一个输入的分类图像,指定一个输出的shp文件,就可以将该分类图像进行矢量化。

       1: /**
       2: * @brief 分类后处理之栅格矢量化
       3: * @param pszSrcFile       输入的分类文件,如果输入文件是多波段文件,则只处理第一波段
       4: * @param pszDstFile       输出结果文件,一个矢量文件
       5: * @param pszFormat        输出文件格式,默认为ERSI Shapefile
       6: * @param pProgress        进度条指针
       7: * @return 成功返回0
       8: */
       9: int ImagePolygonize(const char* pszSrcFile, const char* pszDstFile, const char* pszFormat, LT_Progress *pProgress)
      10: {
      11:     if (pProgress != NULL)
      12:     {
      13:         pProgress->ReSetting();
      14:         pProgress->SetProgressCaption("提示");
      15:         pProgress->SetProgressTip("开始计算栅格矢量化...");
      16:     }
      17:  
      18:     GDALAllRegister();
      19:     OGRRegisterAll();
      20:  
      21:     GDALDataset* poSrcDS = (GDALDataset*) GDALOpen(pszSrcFile, GA_ReadOnly);    //打开栅格图像
      22:     if (poSrcDS == NULL)
      23:     {
      24:         if (pProgress != NULL)
      25:             pProgress->SetProgressTip("不能打开指定文件,请检查文件是否存在!");
      26:  
      27:         return RE_NOFILE;
      28:     }
      29:  
      30:     OGRSFDriver* poDriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(pszFormat);
      31:     if (poDriver == NULL)
      32:     {
      33:         if (pProgress != NULL)
      34:             pProgress->SetProgressTip("不能创建指定类型文件!");
      35:  
      36:         GDALClose((GDALDatasetH)poSrcDS);
      37:  
      38:         return RE_CREATEFILE;
      39:     }
      40:  
      41:     OGRDataSource* poDstDS = poDriver->CreateDataSource(pszDstFile, NULL); //创建输出矢量文件
      42:     if (poDstDS == NULL)
      43:     {
      44:         if (pProgress != NULL)
      45:             pProgress->SetProgressTip("不能创建指定类型文件!");
      46:  
      47:         GDALClose((GDALDatasetH)poSrcDS);
      48:  
      49:         return RE_CREATEFILE;
      50:     }
      51:  
      52:     OGRSpatialReference *poSpatialRef = new OGRSpatialReference(poSrcDS->GetProjectionRef());
      53:     string strLayerName = GetLayerName(pszDstFile);
      54:  
      55:     OGRLayer* poLayer = poDstDS->CreateLayer(strLayerName.c_str(), poSpatialRef, wkbPolygon, NULL);
      56:     if (poLayer == NULL)
      57:     {
      58:         if (pProgress != NULL)
      59:             pProgress->SetProgressTip("创建矢量图层失败!");
      60:  
      61:         GDALClose((GDALDatasetH)poSrcDS);
      62:         OGRDataSource::DestroyDataSource(poDstDS);
      63:  
      64:         delete poSpatialRef;
      65:         poSpatialRef = NULL;
      66:  
      67:         return RE_CREATEFILE;
      68:     }
      69:  
      70:     OGRFieldDefn ofieldDef("DN", OFTInteger);    //创建属性表,只有一个字段即“DN”,里面保存对应的栅格的像元值
      71:     if (poLayer->CreateField(&ofieldDef) != OGRERR_NONE)
      72:     {
      73:         if (pProgress != NULL)
      74:             pProgress->SetProgressTip("创建矢量图层属性表失败!");
      75:  
      76:         GDALClose((GDALDatasetH)poSrcDS);
      77:         OGRDataSource::DestroyDataSource(poDstDS);
      78:  
      79:         delete poSpatialRef;
      80:         poSpatialRef = NULL;
      81:  
      82:         return RE_CREATEFILE;
      83:     }
      84:  
      85:     GDALRasterBandH hSrcBand = (GDALRasterBandH) poSrcDS->GetRasterBand(1);    //获取图像的第一个波段
      86:  
      87:     if (GDALPolygonize(hSrcBand, NULL, (OGRLayerH)poLayer, 0, NULL, GDALProgress, pProgress) != CE_None)//调用栅格矢量化
      88:     {
      89:         if (pProgress != NULL)
      90:             pProgress->SetProgressTip("计算失败!");
      91:  
      92:         GDALClose((GDALDatasetH)poSrcDS);
      93:         OGRDataSource::DestroyDataSource(poDstDS);
      94:  
      95:         delete poSpatialRef;
      96:         poSpatialRef = NULL;
      97:  
      98:         return RE_FAILD;
      99:     }
     100:  
     101:     GDALClose((GDALDatasetH)poSrcDS);    //关闭文件
     102:     OGRDataSource::DestroyDataSource(poDstDS);
     103:  
     104:     delete poSpatialRef;
     105:     poSpatialRef = NULL;
     106:  
     107:     if (pProgress != NULL)
     108:         pProgress->SetProgressTip("计算成功!");
     109:  
     110:     return RE_SUCCESS;
     111: }

    在调用的时候,只需要指定两个文件路径即可,如下:

       1: void main()
       2: {
       3:     LT_ConsoleProgress *pProgress = new LT_ConsoleProgress(); //进度条
       4:     progress_timer *pTime = new progress_timer;    //计时
       5:  
       6:     int f = ImagePolygonize("C://Work//Data//Classify.tif","C://Work//Data//Classify.shp", "ESRI Shapefile", pProgress);
       7:  
       8:     if (f == RE_SUCCESS)
       9:         printf("计算成功/n");
      10:     else
      11:         printf("计算失败/n");
      12:  
      13:     delete pProgress;    //释放资源
      14:     delete pTime;
      15:     system("pause");
      16: }

    测试图像如下,

    image

    矢量化后的矢量(使用要素值渲染方式)

    image

    放大细节处对比(下左图为栅格图像,下右图为矢量化后的矢量):

    imageimage

  • 相关阅读:
    Java——基本语法
    Java——基本概念
    [Educational Codeforces Round 81 (Rated for Div. 2)]E. Permutation Separation(线段树,思维,前缀和)
    Educational Codeforces Round 81 (Rated for Div. 2)] D. Same GCDs (数论,因子分解,容斥定理)
    Educational Codeforces Round 81 (Rated for Div. 2) C. Obtain The String(序列自动机,贪心)
    Educational Codeforces Round 81 B. Infinite Prefixes(数学,字符串,思维)
    Codeforces Round #615 (Div. 3) F. Three Paths on a Tree(树的直径,dfs)
    Codeforces Round #612 (Div. 2) C. Garland 动态规划
    Codeforces Round #612 (Div. 2) D. Numbers on Tree 构造,树dfs
    关于set/map 等容器对string类的时间性能指标对比
  • 原文地址:https://www.cnblogs.com/xiaowangba/p/6314049.html
Copyright © 2011-2022 走看看