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: }
测试图像如下,
矢量化后的矢量(使用要素值渲染方式)
放大细节处对比(下左图为栅格图像,下右图为矢量化后的矢量):