Code source de Sample
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# This file is part of PHYMOBAT 1.2.
# Copyright 2016 Sylvio Laventure (IRSTEA - UMR TETIS)
#
# PHYMOBAT 1.2 is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# PHYMOBAT 1.2 is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with PHYMOBAT 1.2. If not, see <http://www.gnu.org/licenses/>.
import sys, os
import random
import numpy as np
from Vector import Vector
try :
import ogr
except :
from osgeo import ogr
[docs]class Sample(Vector):
"""
Vector class inherits the super vector class properties. This class create training sample.
:param vector_used: Input/Output shapefile to clip (path)
:type vector_used: str
:param vector_cut: Area shapefile (path)
:type vector_cut: str
:param nb_sample: Number of polygons for every sample
:type nb_sample: int
:param vector_val: Output shapefile to validate the futur classification
:type vector_val: str
:opt: Refer to the Vector class
"""
def __init__(self, used, cut, nb_sample, **opt):
"""Create a new 'Sample' instance
"""
Vector.__init__(self, used, cut, **opt)
self._nb_sample = nb_sample
self.vector_val = ''
[docs] def create_sample(self, **kwargs):
"""
Function to create a sample shapefile of a specific class
:kwargs: **fieldname** (list of str) - Fieldname in the input shapefile (if the user want select polygons of the class names specific)
**class** (list of str) - class names in the input shapefile (with fieldname index).
Can use one or several classes like this --> example : [classname1, classname2, ...]
"""
kw_field = kwargs['fieldname'] if kwargs.get('fieldname') else ''
kw_classes = kwargs['class'] if kwargs.get('class') else ''
# If the users want select polygons with a certain class name
if kw_field and kw_classes:
# The random sample with class name selected only
random_sample = np.array(random.sample(self.select_random_sample(kw_field, kw_classes), int(self._nb_sample)))
else:
# The random sample without class name selected
random_sample = np.array(random.sample(range(self.data_source.GetLayer().GetFeatureCount()), self._nb_sample))
# Output shapefile of the sample's polygons (path)
self.vector_used = self.vector_used[:-4] + '_' + kw_classes.replace(',','').replace(' ','') + 'rd.shp'
# Fill and create the sample shapefile
self.fill_sample(self.vector_used, random_sample[:len(random_sample)/2])
# Output shapefile of the validate polygon (path)
self.vector_val = self.vector_used[:-6] + 'val.shp'
# Fill and create the validate polygons shapefile
self.fill_sample(self.vector_val, random_sample[len(random_sample)/2:])
[docs] def select_random_sample(self, kw_field, kw_classes):
"""
Function to select id with class name specific only. This function is used in :func:`create_sample`
:param kw_field: Field name in the input shapefile
:type kw_field: str
:param kw_classes: Class names in the input shapefile like this --> 'classname1, classname2'
:type kw_classes: str
:returns: list -- variable **select_id**, List of id with a class name specific.
"""
# Convert string in a list. For that, it remove
# space and clip this string with comma (Add everywhere if the script modified
# because the process work with a input string chain)
kw_classes = kw_classes.replace(' ','').split(',')
# List of class name id
select_id = []
shp_ogr = self.data_source.GetLayer()
# Loop on input polygons
in_feature = shp_ogr.SetNextByIndex(0) # Initialization
in_feature = shp_ogr.GetNextFeature()
while in_feature:
# if polygon is a defined class name
## .replace('0','') to remove '0' in front of for example '1' (RPG -> '01')
table_name_class = in_feature.GetField(self.field_names[self.field_names.index(kw_field)])
# To avoid that the process crashed this part of the algorithm will be launch if the field is contains characters
if table_name_class != None :
if in_feature.GetField(self.field_names[self.field_names.index(kw_field)]).replace('0','') in kw_classes:
# Add id in the extract list
select_id.append(in_feature.GetFID())
in_feature.Destroy()
in_feature = shp_ogr.GetNextFeature()
return select_id
[docs] def fill_sample(self, output_sample, polygon, **opt):
"""
Function to fill and create the output sample shapefile. This function is used in :func:`create_sample`
to create samples polygons and validated polygons (to the take out the precision of the classification)
:param output_sample: Path of the output shapefile
:type output_sample: str
:param polygon: Identity of the selected random polygons. If this variable = 0, the processing will take all polygons
:type polygon: list or int
:opt: **add_fieldname** (int) - Variable to kown if add a field. By default non (0), if it have to add (1)
**fieldname** (str) - Fieldname to add in the input shapefile
**class** (int) - class names in integer to add in the input shapefile
"""
# In option to add a integer field
add_field = opt['add_fieldname'] if opt.get('add_fieldname') else 0
opt_field = opt['fieldname'] if opt.get('fieldname') else ''
opt_class = opt['class'] if opt.get('class') else 0
shp_ogr = self.data_source.GetLayer()
# To take all polygon
if type(polygon) == int:
polygon = range(shp_ogr.GetFeatureCount())
# Projection
# Import input shapefile projection
srsObj = shp_ogr.GetSpatialRef()
# Conversion to syntax ESRI
srsObj.MorphToESRI()
## Remove the output shapefile if it exists
if os.path.exists(output_sample):
self.data_source.GetDriver().DeleteDataSource(output_sample)
out_ds = self.data_source.GetDriver().CreateDataSource(output_sample)
if out_ds is None:
print('Could not create file')
sys.exit(1)
# Specific output layer
out_layer = out_ds.CreateLayer(str(output_sample), srsObj, geom_type=ogr.wkbMultiPolygon)
# Add existing fields
for i in range(0, len(self.field_names)):
# use the input FieldDefn to add a field to the output
fieldDefn = shp_ogr.GetFeature(0).GetFieldDefnRef(self.field_names[i])
out_layer.CreateField(fieldDefn)
# In Option : Add a integer field
if add_field == 1:
new_field = ogr.FieldDefn(opt_field, 0)
out_layer.CreateField(new_field)
# Feature for the ouput shapefile
featureDefn = out_layer.GetLayerDefn()
# Loop on the input elements
# Create a existing polygons in random list
for cnt in polygon:
# Select input polygon by id
in_feature = shp_ogr.SetNextByIndex(cnt)
in_feature = shp_ogr.GetNextFeature()
geom = in_feature.GetGeometryRef() # Extract input geometry
# Create a new polygon
out_feature = ogr.Feature(featureDefn)
# Set the polygon geometry and attribute
out_feature.SetGeometry(geom)
for i in range(0, len(self.field_names)):
out_feature.SetField(self.field_names[i], in_feature.GetField(self.field_names[i]))
# In Option : Add a integer field
if add_field == 1:
out_feature.SetField(opt_field, opt_class[0])
# Append polygon to the output shapefile
out_layer.CreateFeature(out_feature)
# Destroy polygons
out_feature.Destroy()
in_feature.Destroy()
# Close data
out_ds.Destroy()