-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy path06_make_polygons.py
243 lines (180 loc) · 8.2 KB
/
06_make_polygons.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# -*- coding: utf-8 -*-
"""
Created on Mon Mar 19 16:51:32 2018
@author: braatenj
"""
import time
import os
from osgeo import gdal, ogr, osr
import sys
import shutil
from glob import glob
import subprocess
# change working directory to this script's dir so we can load the ltcdb library
scriptAbsPath = os.path.abspath(__file__)
scriptDname = os.path.dirname(scriptAbsPath)
os.chdir(scriptDname)
import ltcdb
# get the head folder
headDir = ltcdb.get_dir("Select the project head folder", scriptDname)
ltcdb.is_headDir(headDir)
# get dir paths we need
changeDir = ltcdb.dir_path(headDir, 'rLc')
# get the various run dirs
ltRunDirs = [os.path.join(changeDir, thisRunDir) for thisRunDir in os.listdir(changeDir)]
ltRunDirsBase = [os.path.basename(thisRunDir) for thisRunDir in ltRunDirs]
print('\nHere is the list of raster change definitions:')
for i, thisOne in enumerate(ltRunDirsBase):
print(str(i+1)+': '+thisOne)
changeDirIndexGood = 0
while changeDirIndexGood is 0:
changeDirIndex = raw_input('\nWhich one would you like to convert to polygons (enter the number): ')
try:
changeDirIndex = int(changeDirIndex)
changeDirIndex -= 1
changeDirIndexGood = 1
if changeDirIndex not in range(len(ltRunDirsBase)):
print('\nERROR: The selected value is outside the valid range.')
print(' Please try again and make sure to enter a valid selection.')
changeDirIndexGood = 0
except ValueError:
print('\nERROR: The selected value cannot be converted to an integer.')
print(' Please try again and make sure to enter a number.')
"""
# get the dir that contains the change raster stacks TODO make this more descriptive about what dir to get
changeDir = ltcdb.get_dir("Select a folder that contains LT change files\n\n(*\\raster\\landtrendr\\change\\*)")
if changeDir is '.':
sys.exit()
if len(changeDir.split('-')) is not 6:
sys.exit('\nERROR: The folder you selected does not seem correct.\n'+
'It should look something like this:\n\n'+
'PARK_CODE-MORA-NBR-7-19842017-06010930\n\n'+
'Please re-run the script and select a different folder.')
"""
ltRunDirs = [ltRunDirs[changeDirIndex]]
mmus = []
for changeDir in ltRunDirs:
# get the mmu
mmuGood = 0
while mmuGood is 0:
mmu = raw_input('\n\nRegarding raster change definition: '+os.path.basename(changeDir) + '\nWhat is the desired minimum mapping unit in pixels per patch: ')
try:
mmu = int(mmu)
mmuGood = 1
except ValueError:
print('\nERROR: The selected value cannot be converted to an integer.')
print(' Please try again and make sure to enter a number.')
mmus.append(mmu)
# get the connected
connectednesses = []
for changeDir in ltRunDirs:
connectednessGood = 0
while connectednessGood is 0:
connectedness = raw_input('\n\nRegarding raster change definition: '+os.path.basename(changeDir) + '\nShould diagonal adjacency warrant pixel inclusion in patches? - yes or no: ').lower().strip()
if connectedness not in ['yes', 'no']:
print('\nERROR: The given entry was not yes or no.')
print(' Please type either: yes or no.\n')
else:
if connectedness == 'yes':
connectedness = 8
else:
connectedness = 4
connectednessGood = 1
connectednesses.append(connectedness)
for i, changeDir in enumerate(ltRunDirs):
print('\n\nWorking on raster change definition: ' + os.path.basename(changeDir))
# get the year of detection file - will patchify this
yodFile = glob(os.path.join(changeDir,'*yrs.tif'))
if len(yodFile) == 0:
sys.exit('ERROR: There was no *yrs.tif file in the folder selected.\nPlease fix this.')
yodFile = yodFile[0] # TODO what if multiple were found
mmu = mmus[i]
connectedness = connectednesses[i]
startTime = time.time()
# get info
info = ltcdb.get_info(os.path.basename(yodFile))
# figure out the vector path
#TODO: add the changeDir name to the info getter/printer
bname = os.path.basename(changeDir) #info['name']
vectorBnameDir = bname+'-'+str(mmu)+'mmu_'+str(connectedness)+'con'#+'nbr' #os.path.join(polyDir, 'ltee_mora_'+str(mmu)+'mmu_annual_dist.shp') # this should be set !!!!USED TO BE: vectorBname
vectorBname = 'change' # TODO: this can change to grow, if we switch to mapping growth
vectorDirFull = os.path.join(headDir, 'vector', 'change', vectorBnameDir)
#vectorDirFullBlank = os.path.join(vectorDirFull, 'blank') # not used ???
if os.path.exists(vectorDirFull):
sys.exit('\nERROR: Directory '+vectorDirFull+' already exits.\n Please re-run with different MMU and/or connectivity, if so desired.')
else:
os.makedirs(vectorDirFull)
# copy the change attributes file
chngAttrFile = yodFile.replace('yrs.tif', 'attributes.csv')
if not os.path.exists(chngAttrFile):
sys.exit('ERROR: Could not find file: '+chngAttrFile+'.\Something might have gone wrong while running script: 05_extract_annual_change.py')
chngAttrFileCopy = os.path.join(vectorDirFull, 'attributes.csv')
shutil.copyfile(chngAttrFile, chngAttrFileCopy)
# make a patch raster file from years
patchMaskFile = os.path.join(vectorDirFull, 'patches.tif')
shutil.copyfile(yodFile, patchMaskFile)
print(' sieving to minimum mapping unit...')
srcPatches = gdal.Open(patchMaskFile, gdal.GA_Update)
nBands = srcPatches.RasterCount
for band in range(1,nBands+1):
srcBand = srcPatches.GetRasterBand(band)
dstBand = srcBand
maskBand = None
# will also fill gaps that less than threshold
gdal.SieveFilter(srcBand, maskBand, dstBand, threshold=mmu, connectedness=connectedness)
srcPatches = None
# make polygons
print(' making polygons from disturbance pixel patches...')
# read in the patch raster
srcPatches = gdal.Open(patchMaskFile, gdal.GA_ReadOnly)
# make a srs definition from patch raster file
srs = osr.SpatialReference()
srs.ImportFromWkt(srcPatches.GetProjectionRef())
# set things needed for each band (year)
nBands = srcPatches.RasterCount
drv = ogr.GetDriverByName('ESRI shapefile')
dst_layername = 'out'
dst_fieldname = 'yod'
# loop through bands
mergedPolyOutPath = os.path.join(vectorDirFull, '_'+vectorBname+'_merged.shp')
for band, year in enumerate(range(info['startYear']+1,info['endYear']+1)):
band += 1
print(' working on year: '+str(band)+'/'+str(nBands)+' ('+str(year)+')')
polyFile = os.path.join(vectorDirFull, vectorBname+'_'+str(year)+'.shp') #os.path.join(polyDir, info['name']+'-'+str(year)+'.shp')
srcBand = srcPatches.GetRasterBand(band)
maskBand = srcBand
# create a polygon file
dstPoly = drv.CreateDataSource(polyFile)
# set the layer name and srs of the poly file
dstLayer = dstPoly.CreateLayer(dst_layername, geom_type=ogr.wkbPolygon, srs=srs)
# create a field
fd = ogr.FieldDefn(dst_fieldname, ogr.OFTInteger)
dstLayer.CreateField(fd)
# perform the operation
gdal.Polygonize(srcBand, maskBand, dstLayer, iPixValField=0, options=['8CONNECTED=8'])
dstPoly = None
# merge the polygons
if band == 1:
mergeCmd = 'ogr2ogr -f "ESRI Shapefile" ' + mergedPolyOutPath + ' ' + polyFile
else:
mergeCmd = 'ogr2ogr -f "ESRI Shapefile" -append -update ' + mergedPolyOutPath + ' ' + polyFile
subprocess.call(mergeCmd, shell=True)
# close the files
srcPatches = None
"""
# find the annual files and merge them
shpFiles = glob(os.path.join(vectorBnameDir,'*.shp'))
if len(shpFiles) == 0:
sys.exit('ERROR: No .shp files were found in directory: '+vectorBnameDir)
# merge the polygons
mergedPolyOutPath = os.path.join(vectorBnameDir, os.path.splitext(os.path.basename(shpFiles[0]))[0][:-4]+'all.shp')
mergeCmd = 'ogr2ogr -f "ESRI Shapefile" ' + mergedPolyOutPath + ' ' + shpFiles[0]
subprocess.call(mergeCmd, shell=True)
for i in range(1,len(shpFiles)):
mergeCmd = 'ogr2ogr -f "ESRI Shapefile" -append -update ' + mergedPolyOutPath + ' ' + shpFiles[i]
subprocess.call(mergeCmd, shell=True)
# remove the individual year files
#shutil.rmtree(polyDir)
"""
print('\n\nDone!')
print("Polygon creation took {} minutes".format(round((time.time() - startTime)/60, 1)))