Historical Map  1.0
Plugin for automatic extraction of old forest from historical map
 All Classes Namespaces Files Functions Variables
function_historical_map.py
Go to the documentation of this file.
1 """!@brief Interface between qgisForm and function_historical_map.py
2 ./***************************************************************************
3  HistoricalMap
4  A QGIS plugin
5  Mapping old landcover (specially forest) from historical maps
6  -------------------
7  begin : 2016-01-26
8  git sha : $Format:%H$
9  copyright : (C) 2016 by Karasiak & Lomellini
10  email : karasiak.nicolas@gmail.com
11  ***************************************************************************/
12 
13 /***************************************************************************
14  * *
15  * This program is free software; you can redistribute it and/or modify *
16  * it under the terms of the GNU General Public License as published by *
17  * the Free Software Foundation; either version 2 of the License, or *
18  * (at your option) any later version. *
19  * *
20  ***************************************************************************/
21 """
22 # -*- coding: utf-8 -*-
23 import function_dataraster as dataraster
24 import pickle
25 import os
26 import accuracy_index as ai
27 import tempfile
28 import gmm_ridge as gmmr
29 import scipy as sp
30 from scipy import ndimage
31 from osgeo import gdal, ogr, osr
32 from PyQt4.QtGui import QProgressBar, QApplication
33 from PyQt4 import QtCore
34 from qgis.utils import iface
35 from qgis.core import QgsMessageLog
36 
38  """!@brief Filter a raster with median and closing filter.
39 
40  Filter class to isolate the forest, delete dark lines and fonts from Historical Map
41 
42  Input :
43  inImage : image name to filter ('text.tif',str)
44  outName : outname name of the filtered file (str)
45  inShapeGrey : Size for the grey closing convolution matrix (odd number, int)
46  inShapeMedian : Size for the median convolution matrix (odd number, int)
47 
48  Output :
49  Nothing except a raster file (outName)
50 
51  """
52 
53  def __init__(self,inImage,outName,inShapeGrey,inShapeMedian,iterMedian):
54  # open data with Gdal
55  try:
56  data,im=dataraster.open_data_band(inImage)
57  except:
58  print 'Cannot open image'
59 
60  # get proj,geo and dimension (d) from data
61  proj = data.GetProjection()
62  geo = data.GetGeoTransform()
63  d = data.RasterCount
64 
65  # Progress Bar
66  maxStep=d+d*iterMedian
67  try:
68  filterProgress=progressBar(' Filtering...',maxStep)
69  except:
70  print 'Failed loading progress Bar'
71 
72  # create empty geotiff with d dimension, geotransform & projection
73  try:
74  outFile=dataraster.create_empty_tiff(outName,im,d,geo,proj)
75  except:
76  print 'Cannot write empty image '+outName
77 
78  # fill outFile with filtered band
79  for i in range(d):
80  # Read data from the right band
81  try:
82  filterProgress.addStep()
83  temp = data.GetRasterBand(i+1).ReadAsArray()
84 
85  except:
86  print 'Cannot get rasterband'+i
87  QgsMessageLog.logMessage("Problem reading band "+str(i)+" from image "+inImage)
88  # Filter with greyclosing, then with median filter
89  try:
90  temp = ndimage.morphology.grey_closing(temp,size=(inShapeGrey,inShapeGrey))
91  except:
92  print 'Cannot filter with Grey_Closing'
93  QgsMessageLog.logMessage("Problem with Grey Closing")
94 
95  for j in range(iterMedian):
96  try:
97  filterProgress.addStep()
98  temp = ndimage.filters.median_filter(temp,size=(inShapeMedian,inShapeMedian))
99  except:
100  print 'Cannot filter with Median'
101  QgsMessageLog.logMessage("Problem with median filter")
102 
103  # Save bandand outFile
104  try:
105  out=outFile.GetRasterBand(i+1)
106  out.WriteArray(temp)
107  out.FlushCache()
108  temp = None
109  except:
110  QgsMessageLog.logMessage("Cannot save band"+str(i)+" on image" + outName)
111 
112  filterProgress.reset()
113 
114 class learnModel():
115  """!@brief Learn model with a shp file and a raster image.
116 
117  Input :
118  inRaster : Filtered image name ('sample_filtered.tif',str).
119  inVector : Name of the training shpfile ('training.shp',str).
120  inField : Column name where are stored class number (str).
121  inSplit : (int).
122  inSeed : (int).
123  outModel : Name of the model to save, will be compulsory for the 3rd step (classifying).
124  outMatrix : Default the name of the file inRaster(minus the extension)_inClassifier_inSeed_confu.csv (str).
125  inClassifier : GMM,KNN,SVM, or RF. (str).
126 
127  Output :
128  Model file.
129  Confusion Matrix.
130 
131  """
132  def __init__(self,inRaster,inVector,inField='Class',inSplit=0.5,inSeed=0,outModel=None,outMatrix=None,inClassifier='GMM'):
133 
134 
135  learningProgress=progressBar('Learning model...',6)
136 
137  # Convert vector to raster
138 
139  try:
140  temp_folder = tempfile.mkdtemp()
141  filename = os.path.join(temp_folder, 'temp.tif')
142 
143  data = gdal.Open(inRaster,gdal.GA_ReadOnly)
144  shp = ogr.Open(inVector)
145 
146  lyr = shp.GetLayer()
147  except:
148  QgsMessageLog.logMessage("Problem with making tempfile or opening raster or vector")
149 
150  # Create temporary data set
151  try:
152  driver = gdal.GetDriverByName('GTiff')
153  dst_ds = driver.Create(filename,data.RasterXSize,data.RasterYSize, 1,gdal.GDT_Byte)
154  dst_ds.SetGeoTransform(data.GetGeoTransform())
155  dst_ds.SetProjection(data.GetProjection())
156  OPTIONS = 'ATTRIBUTE='+inField
157  gdal.RasterizeLayer(dst_ds, [1], lyr, None,options=[OPTIONS])
158  data,dst_ds,shp,lyr=None,None,None,None
159  except:
160  QgsMessageLog.logMessage("Cannot create temporary data set")
161 
162  # Load Training set
163  try:
164  X,Y = dataraster.get_samples_from_roi(inRaster,filename)
165  except:
166  QgsMessageLog.logMessage("Problem while getting samples from ROI with"+inRaster)
167 
168  [n,d] = X.shape
169  C = int(Y.max())
170  SPLIT = inSplit
171  os.remove(filename)
172  os.rmdir(temp_folder)
173 
174  # Scale the data
175  X,M,m = self.scale(X)
176 
177 
178  learningProgress.addStep() # Add Step to ProgressBar
179 
180  # Learning process take split of groundthruth pixels for training and the remaining for testing
181  try:
182  if SPLIT < 1:
183  # progressBar, set Max to C
184 
185  # Random selection of the sample
186  x = sp.array([]).reshape(0,d)
187  y = sp.array([]).reshape(0,1)
188  xt = sp.array([]).reshape(0,d)
189  yt = sp.array([]).reshape(0,1)
190 
191  sp.random.seed(inSeed) # Set the random generator state
192  for i in range(C):
193  t = sp.where((i+1)==Y)[0]
194  nc = t.size
195  ns = int(nc*SPLIT)
196  rp = sp.random.permutation(nc)
197  x = sp.concatenate((X[t[rp[0:ns]],:],x))
198  xt = sp.concatenate((X[t[rp[ns:]],:],xt))
199  y = sp.concatenate((Y[t[rp[0:ns]]],y))
200  yt = sp.concatenate((Y[t[rp[ns:]]],yt))
201  #Add Pb
202  except:
203  QgsMessageLog.logMessage("Problem while learning if SPLIT <1")
204 
205  else:
206  x,y=X,Y
207 
208  learningProgress.addStep() # Add Step to ProgressBar
209  # Train Classifier
210  try:
211  if inClassifier == 'GMM':
212  # tau=10.0**sp.arange(-8,8,0.5)
213  model = gmmr.GMMR()
214  model.learn(x,y)
215  # htau,err = model.cross_validation(x,y,tau)
216  # model.tau = htau
217  except:
218  QgsMessageLog.logMessage("Cannot train with GMMM")
219  else:
220  try:
221  from sklearn import neighbors
222  from sklearn.svm import SVC
223  from sklearn.ensemble import RandomForestClassifier
224  from sklearn.cross_validation import StratifiedKFold
225  from sklearn.grid_search import GridSearchCV
226  except:
227  QgsMessageLog.logMessage("You must have sklearn dependencies on your computer. Please consult the documentation")
228  try:
229  if inClassifier == 'RF':
230  param_grid_rf = dict(n_estimators=5**sp.arange(1,5),max_features=sp.arange(1,4))
231  y.shape=(y.size,)
232  cv = StratifiedKFold(y, n_folds=5)
233  grid = GridSearchCV(RandomForestClassifier(), param_grid=param_grid_rf, cv=cv,n_jobs=-1)
234  grid.fit(x, y)
235  model = grid.best_estimator_
236  model.fit(x,y)
237  elif inClassifier == 'SVM':
238  param_grid_svm = dict(gamma=2.0**sp.arange(-4,4), C=10.0**sp.arange(-2,5))
239  y.shape=(y.size,)
240  cv = StratifiedKFold(y, n_folds=5)
241  grid = GridSearchCV(SVC(), param_grid=param_grid_svm, cv=cv,n_jobs=-1)
242  grid.fit(x, y)
243  model = grid.best_estimator_
244  model.fit(x,y)
245  elif inClassifier == 'KNN':
246  param_grid_knn = dict(n_neighbors = sp.arange(1,50,5))
247  y.shape=(y.size,)
248  cv = StratifiedKFold(y, n_folds=5)
249  grid = GridSearchCV(neighbors.KNeighborsClassifier(), param_grid=param_grid_knn, cv=cv,n_jobs=-1)
250  grid.fit(x, y)
251  model = grid.best_estimator_
252  model.fit(x,y)
253  except:
254  print 'Cannot train with Classifier '+inClassifier
255  QgsMessageLog.logMessage("Cannot train with Classifier"+inClassifier)
256 
257 
258 
259  learningProgress.prgBar.setValue(5) # Add Step to ProgressBar
260  # Assess the quality of the model
261  if SPLIT < 1 :
262  # if inClassifier == 'GMM':
263  # yp = model.predict(xt)[0]
264  # else:
265  yp = model.predict(xt)
266  CONF = ai.CONFUSION_MATRIX()
267  CONF.compute_confusion_matrix(yp,yt)
268  sp.savetxt(outMatrix,CONF.confusion_matrix,delimiter=',',fmt='%1.4d')
269 
270 
271  # Save Tree model
272  if outModel is not None:
273  output = open(outModel, 'wb')
274  pickle.dump([model,M,m], output)
275  output.close()
276 
277  learningProgress.addStep() # Add Step to ProgressBar
278 
279  # Close progressBar
280  learningProgress.reset()
281  learningProgress=None
282  def scale(self,x,M=None,m=None):
283  """!@brief Function that standardize the data.
284 
285  Input:
286  x: the data
287  M: the Max vector
288  m: the Min vector
289  Output:
290  x: the standardize data
291  M: the Max vector
292  m: the Min vector
293  """
294  [n,d]=x.shape
295  if not sp.issubdtype(x.dtype,float):
296  x=x.astype('float')
297 
298  # Initialization of the output
299  xs = sp.empty_like(x)
300 
301  # get the parameters of the scaling
302  M,m = sp.amax(x,axis=0),sp.amin(x,axis=0)
303  den = M-m
304  for i in range(d):
305  if den[i] != 0:
306  xs[:,i] = 2*(x[:,i]-m[i])/den[i]-1
307  else:
308  xs[:,i]=x[:,i]
309 
310  return xs,M,m
311 
313  """!@brief Classify image with learn clasifier and learned model
314 
315  Create a raster file, fill hole from your give class (inClassForest), convert to a vector,
316  remove parcel size which are under a certain size (defined in inMinSize) and save it to shp.
317 
318  Input :
319  inRaster : Filtered image name ('sample_filtered.tif',str)
320  inModel : Output name of the filtered file ('training.shp',str)
321  outShpFile : Output name of vector files ('sample.shp',str)
322  inMinSize : min size in acre for the forest, ex 6 means all polygons below 6000 m2 (int)
323  TODO inMask : Mask size where no classification is done |||| NOT YET IMPLEMENTED
324  inField : Column name where are stored class number (str)
325  inNODATA : if NODATA (int)
326  inClassForest : Classification number of the forest class (int)
327 
328  Output :
329  SHP file with deleted polygon below inMinSize
330 
331  """
332 
333 
334  def initPredict(self,inRaster,inModel):
335 
336 
337  # Load model
338  try:
339  model = open(inModel,'rb') # TODO: Update to scale the data
340  if model is None:
341  print "Model not load"
342  QgsMessageLog.logMessage("Model : "+inModel+" is none")
343  else:
344  tree,M,m = pickle.load(model)
345  model.close()
346  except:
347  QgsMessageLog.logMessage("Error while loading the model : "+inModel)
348 
349  # Creating temp file for saving raster classification
350  try:
351  temp_folder = tempfile.mkdtemp()
352  rasterTemp = os.path.join(temp_folder, 'temp.tif')
353  except:
354  QgsMessageLog.logMessage("Cannot create temp file "+rasterTemp)
355  # Process the data
356  try:
357  predictedImage=self.predict_image(inRaster,rasterTemp,tree,None,-10000,SCALE=[M,m])
358  except:
359  QgsMessageLog.logMessage("Problem while predicting "+inRaster+" in temp"+rasterTemp)
360 
361  return predictedImage
362 
363 
364  def rasterMod(self,rasterTemp,inClassForest):
365  try:
366  data,im=dataraster.open_data_band(rasterTemp)
367  # get proj,geo and dimension (d) from data
368  proj = data.GetProjection()
369  geo = data.GetGeoTransform()
370  d = data.RasterCount
371 
372  rasterTemp=rasterTemp+'f'
373  except:
374  QgsMessageLog.logMessage("Cant opening band")
375  try:
376  outFile=dataraster.create_empty_tiff(rasterTemp,im,1,geo,proj)
377  except:
378  QgsMessageLog.logMessage("Cannot create empty tif in "+rasterTemp)
379 
380  try:
381  temp = data.GetRasterBand(1).ReadAsArray()
382  # All data which is not forest is set to 0, so we fill all for the forest only, because it's a binary fill holes.
383  # Set selected class as 1
384  temp[temp!=inClassForest]=0
385  temp[temp==inClassForest]=1
386 
387  temp = ndimage.morphology.binary_fill_holes(temp)
388  #temp = ndimage.median_filter(temp,size=(3,3)).astype(int)
389  except:
390  QgsMessageLog.logMessage("Cannot fill binary holes")
391 
392  # All non forest, or non selected class is set to 2
393  #temp[temp==0]=2
394 
395  try :
396  out=outFile.GetRasterBand(1)
397  out.WriteArray(temp)
398  out.FlushCache()
399  temp = None
400  # Cleaning outFile or vectorizing doesn't work
401  outFile= None
402  except:
403  print 'Cannot save '+rasterTemp
404  return rasterTemp
405 
406  def vectorMod(self,rasterTemp,inMinSize,outShpFile):
407  # Vectorizing with gdal.Polygonize
408  try:
409  sourceRaster = gdal.Open(rasterTemp)
410  band = sourceRaster.GetRasterBand(1)
411  driver = ogr.GetDriverByName("ESRI Shapefile")
412  # If shapefile already exist, delete it
413  if os.path.exists(outShpFile):
414  driver.DeleteDataSource(outShpFile)
415 
416  outDatasource = driver.CreateDataSource(outShpFile)
417  # get proj from raster
418  srs = osr.SpatialReference()
419  srs.ImportFromWkt( sourceRaster.GetProjectionRef() )
420  # create layer with proj
421  outLayer = outDatasource.CreateLayer(outShpFile,srs)
422  # Add class column (1,2...) to shapefile
423 
424  newField = ogr.FieldDefn('Class', ogr.OFTInteger)
425  outLayer.CreateField(newField)
426  gdal.Polygonize(band, None,outLayer, 0,[],callback=None)
427  outDatasource.Destroy()
428  sourceRaster=None
429 
430  except:
431  QgsMessageLog.logMessage("Cannot vectorize "+rasterTemp)
432 
433  try:
434  # Add area for each feature
435  ioShpFile = ogr.Open(outShpFile, update = 1)
436 
437  lyr = ioShpFile.GetLayerByIndex(0)
438  lyr.ResetReading()
439 
440  field_defn = ogr.FieldDefn( "Area", ogr.OFTReal )
441  lyr.CreateField(field_defn)
442 
443 
444  for i in lyr:
445  # feat = lyr.GetFeature(i)
446  geom = i.GetGeometryRef()
447  area = round(geom.GetArea())
448 
449  lyr.SetFeature(i)
450  i.SetField( "Area", area )
451  lyr.SetFeature(i)
452  # if area is less than inMinSize or if it isn't forest, remove polygon
453  if area<inMinSize or i.GetField('Class')!=1:
454  lyr.DeleteFeature(i.GetFID())
455  ioShpFile.Destroy()
456  except:
457  QgsMessageLog.logMessage("Cannot add area and remove it if size under"+inMinSize)
458  return outShpFile
459 
460  def scale(self,x,M=None,m=None): # TODO: DO IN PLACE SCALING
461  """!@brief Function that standardize the data
462 
463  Input:
464  x: the data
465  M: the Max vector
466  m: the Min vector
467  Output:
468  x: the standardize data
469  M: the Max vector
470  m: the Min vector
471  """
472  [n,d]=x.shape
473  if not sp.issubdtype(x.dtype,float):
474  x=x.astype('float')
475 
476  # Initialization of the output
477  xs = sp.empty_like(x)
478 
479  # get the parameters of the scaling
480  if M is None:
481  M,m = sp.amax(x,axis=0),sp.amin(x,axis=0)
482 
483  den = M-m
484  for i in range(d):
485  if den[i] != 0:
486  xs[:,i] = 2*(x[:,i]-m[i])/den[i]-1
487  else:
488  xs[:,i]=x[:,i]
489 
490  return xs
491 
492  def predict_image(self,inRaster,outRaster,model,inMask=None,NODATA=-10000,SCALE=None):
493  """!@brief The function classify the whole raster image, using per block image analysis.
494 
495  The classifier is given in classifier and options in kwargs
496 
497  Input :
498  inRaster : Filtered image name ('sample_filtered.tif',str)
499  outRaster :Raster image name ('outputraster.tif',str)
500  model : model file got from precedent step ('model', str)
501  inMask : mask to
502  NODATA : Default set to -10000 (int)
503  SCALE : Default set to None
504 
505  Output :
506  nothing but save a raster image
507  """
508  # Open Raster and get additionnal information
509  raster = gdal.Open(inRaster,gdal.GA_ReadOnly)
510  if raster is None:
511  print 'Impossible to open '+inRaster
512  exit()
513 
514  # If provided, open mask
515  if inMask is None:
516  mask=None
517  else:
518  mask = gdal.Open(inMask,gdal.GA_ReadOnly)
519  if mask is None:
520  print 'Impossible to open '+inMask
521  exit()
522  # Check size
523  if (raster.RasterXSize != mask.RasterXSize) or (raster.RasterYSize != mask.RasterYSize):
524  print 'Image and mask should be of the same size'
525  exit()
526  if SCALE is not None:
527  M,m=sp.asarray(SCALE[0]),sp.asarray(SCALE[1])
528 
529  # Get the size of the image
530  d = raster.RasterCount
531  nc = raster.RasterXSize
532  nl = raster.RasterYSize
533 
534  # Get the geoinformation
535  GeoTransform = raster.GetGeoTransform()
536  Projection = raster.GetProjection()
537 
538  # Get block size
539  band = raster.GetRasterBand(1)
540  block_sizes = band.GetBlockSize()
541  x_block_size = block_sizes[0]
542  y_block_size = block_sizes[1]
543  del band
544 
545  ## Initialize the output
546  driver = gdal.GetDriverByName('GTiff')
547  dst_ds = driver.Create(outRaster, nc,nl, 1, gdal.GDT_Byte)
548  dst_ds.SetGeoTransform(GeoTransform)
549  dst_ds.SetProjection(Projection)
550  out = dst_ds.GetRasterBand(1)
551 
552  ## Perform the classification
553  for i in range(0,nl,y_block_size):
554  if i + y_block_size < nl: # Check for size consistency in Y
555  lines = y_block_size
556  else:
557  lines = nl - i
558  for j in range(0,nc,x_block_size): # Check for size consistency in X
559  if j + x_block_size < nc:
560  cols = x_block_size
561  else:
562  cols = nc - j
563 
564  # Load the data and Do the prediction
565  X = sp.empty((cols*lines,d))
566  for ind in xrange(d):
567  X[:,ind] = raster.GetRasterBand(int(ind+1)).ReadAsArray(j, i, cols, lines).reshape(cols*lines)
568 
569  # Do the prediction
570  if mask is None:
571  mask_temp=raster.GetRasterBand(1).ReadAsArray(j, i, cols, lines).reshape(cols*lines)
572  t = sp.where((mask_temp!=0) & (X[:,0]!=NODATA))[0]
573  yp=sp.zeros((cols*lines,))
574  else :
575  mask_temp=mask.GetRasterBand(1).ReadAsArray(j, i, cols, lines).reshape(cols*lines)
576  t = sp.where((mask_temp!=0) & (X[:,0]!=NODATA))[0]
577  yp=sp.zeros((cols*lines,))
578 
579  # TODO: Change this part accorindgly ...
580  if t.size > 0:
581  yp[t]= model.predict(self.scale(X[t,:],M=M,m=m)).astype('uint8')
582 
583  # Write the data
584  out.WriteArray(yp.reshape(lines,cols),j,i)
585  out.FlushCache()
586  del X,yp
587 
588  # Clean/Close variables
589  raster = None
590  dst_ds = None
591  return outRaster
592 
593 
594 class progressBar():
595  """!@brief Manage progressBar and loading cursor.
596  Allow to add a progressBar in Qgis and to change cursor to loading
597  input:
598  -inMsg : Message to show to the user (str)
599  -inMax : The steps of the script (int)
600 
601  output:
602  nothing but changing cursor and print progressBar inside Qgis
603  """
604  def __init__(self,inMsg=' Loading...',inMaxStep=1):
605  # initialize progressBar
606  """
607  """# Save reference to the QGIS interface
608  QApplication.processEvents() # Help to keep UI alive
609 
610  widget = iface.messageBar().createMessage('Please wait ',inMsg)
611  prgBar = QProgressBar()
612  self.prgBar=prgBar
613  self.iface=iface
614  widget.layout().addWidget(self.prgBar)
615  iface.messageBar().pushWidget(widget, iface.messageBar().WARNING)
616  QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
617 
618  # if Max 0 and value 0, no progressBar, only cursor loading
619  # default is set to 0
620  prgBar.setValue(1)
621  # set Maximum for progressBar
622  prgBar.setMaximum(inMaxStep)
623 
624  def addStep(self):
625  """!@brief Add a step to the progressBar
626  addStep() simply add +1 to current value of the progressBar
627  """
628  plusOne=self.prgBar.value()+1
629  self.prgBar.setValue(plusOne)
630  def reset(self):
631  """!@brief Simply remove progressBar and reset cursor
632 
633  """
634  # Remove progressBar and back to default cursor
635  self.iface.messageBar().clearWidgets()
636  self.iface.mapCanvas().refresh()
637  QApplication.restoreOverrideCursor()
638 
639 #if __name__=='__main__':
640 
641 
642 
643  # Image to work on
644 #
645 # inImage='img/samples/map.tif'
646 #
647 # inFile,inExtension = os.path.splitext(inImage) # Split filename and extension
648 # outFilter=inFile+'_filtered'+inExtension
649 #
650 # # Filtering....
651 # filtered=historicalFilter(inImage,outFilter,inShapeGrey=11,inShapeMedian=11, iterMedian=1)
652 # print 'Image saved as : '+outFilter
653 #
654 ## #Learn Model...
655 ## inVector='img/samples/train.shp'
656 ## inClassifier='GMM'
657 # outModel='/home/sigma/test/modelGMM'
658 ## inSeed=0
659 ##
660 ## model=learnModel('img/samples/map_filtered.tif','img/samples/train.shp',inField='Class',inSplit=0.5,inSeed=0,outModel='img/samples/model',outMatrix='img/samples/matrix.csv',inClassifier=inClassifier)
661 ## print 'Model saved as : '+outModel
662 ## print 'Confusion matrix saved as : '+str(inFile)+'_'+str(inClassifier)+'_'+str(inSeed)+'_confu.csv'
663 
664  #Classify image...
665 
666 # outShpFile='img/samples/SHP/vectorized.shp'
667 # classifyImage('/home/sigma/test/map_fltr.tif','/home/sigma/test/modelGMM','/home/sigma/test/vec.shp',None,5000,-10000,1)
668  #classified=classifyImage(outFilter,outModel,outShpFile,None,6000,-10000,1)
669 
670 # inFilteredStep3,inTrainingStep3,outRasterClass,None,inMinSize,None,'Class',inNODATA=-10000
671 # inRaster,inModel,outRaster,inMask=None,inMinSize=6,outShpFolder='img/samples/outSHP/',inField='Class',inNODATA=-10000
Filter a raster with median and closing filter.
def scale
Function that standardize the data.
def predict_image
The function classify the whole raster image, using per block image analysis.
Classify image with learn clasifier and learned model.
def addStep
Add a step to the progressBar addStep() simply add +1 to current value of the progressBar.
Learn model with a shp file and a raster image.
def reset
Simply remove progressBar and reset cursor.