Example #1
0
    def extract_ships(self):
        '''
        Use protogen to generate potential ship locations
        '''
        # Create masked MS image
        l = protogen.Interface('lulc','masks')
        l.lulc.masks.type = 'single'
        l.lulc.masks.switch_no_data = False
        l.lulc.masks.switch_water = False
        l.lulc.masks.switch_vegetation = True
        l.lulc.masks.switch_clouds = True
        l.lulc.masks.switch_bare_soil = True
        l.lulc.masks.switch_shadows = True
        l.lulc.masks.switch_unclassified = False
        l.image_config.bands = [1, 2, 3, 4, 5, 6, 7, 8]
        l.image = self.ms_image
        l.execute()

        # Remove LULC noise
        a = protogen.Interface('morphology', 'connected_area_filter')
        a.morphology.connected_area_filter.operator = 'opening'
        a.morphology.connected_area_filter.opening_size_threshold = 10000.0
        a.morphology.connected_area_filter.closing_size_threshold = 0.0
        a.image_config.bands = [1]
        a.image = os.path.split(l.output)[-1]
        a.execute()

        # Close clouds (?)
        c = protogen.Interface('morphology', 'structural')
        c.morphology.structural.operator = 'closing'
        c.morphology.structural.structuring_element = 'disk'
        c.morphology.structural.radius1 = 10
        c.image_config.bands = [1]
        c.image = os.path.split(a.output)[-1]
        c.execute()

        # Extract ships from original image + mask
        p = protogen.Interface('extract', 'vehicles')
        p.extract.vehicles.type = 'ships'
        p.extract.vehicles.visualization = 'binary'
        p.extract.vehicles.max_length = 1500.0
        p.extract.vehicles.max_width = 100.0
        p.extract.vehicles.min_length = 50.0
        p.extract.vehicles.min_width = 10.0
        p.extract.vehicles.threshold = 100.0
        p.image_config.bands = [1, 2, 3, 4, 5, 6, 7, 8]
        p.mask_config.bands = [1]
        p.image = self.ms_image
        p.mask = os.path.split(c.output)[-1]
        p.execute()

        # Get bbox vectors of ships
        v = protogen.Interface('vectorizer', 'bounding_box')
        v.image_config.bands = [1]
        v.vectorizer.bounding_box.filetype = 'geojson'
        v.vectorizer.bounding_box.target_bbox = False
        v.vectorizer.bounding_box.target_centroid = True
        v.vectorizer.bounding_box.processor = True
        v.athos.tree_type = 'union_find'
        v.athos.area.export = [1]
        v.image = os.path.split(p.output)[-1]
        v.execute()

        return v.output
Example #2
0
File: lulc.py Project: beevor/lulc
    clouds = False
    shadows = False
    unclassified = False
    rgb = True
    tiles = 1
    verbose = False

# Create output directory
output_dir = os.path.join(output_ports_location, 'image')
if not os.path.exists(output_dir):
    os.makedirs(output_dir)
os.chdir(output_dir)

# Run lulc
if rgb:
    p = protogen.Interface('lulc', 'layers')
    p.lulc.layers.name = 'lulc'
    p.lulc.layers.visualization = 'rgb'
else:
    p = protogen.Interface('lulc', 'masks')
    p.lulc.masks.type = 'single'
    p.lulc.masks.switch_vegetation = vegetation
    p.lulc.masks.switch_water = water
    p.lulc.masks.switch_bare_soil = soil
    p.lulc.masks.switch_clouds = clouds
    p.lulc.masks.switch_shadows = shadows
    p.lulc.masks.switch_unclassified = unclassified
    # no data can never be the foreground
    p.lulc.masks.switch_no_data = False

# Specify input image and range of bands
Example #3
0
    def extract_candidates(self):
        '''
        Use protogen to generate candidate bounding boxes.
        The function returns the name of the geojson file containing the bounding
        boxes.
        '''

        # Make the multispectral image directory the working directory
        os.chdir(self.ms_image_path)

        # Get number of bands (depends on sensor)
        no_bands = gdal.Open(self.ms_image).RasterCount

        # If mask is not provided and with_mask is true then make one
        if not self.mask and self.with_mask:

            print 'Creating water mask'
            make_mask = True

            # Compute normalized difference water index
            rbr = protogen.Interface('radex_scalar', 'band_ratio')
            rbr.radex_scalar.band_ratio.index_formula = 'IDX1'
            rbr.radex_scalar.band_ratio.output_datatype = 'UINT8'
            rbr.image = self.ms_image
            rbr.image_config.bands = [1, no_bands]
            rbr.execute()

            # Create mask
            mot = protogen.Interface('morphology', 'threshold')
            mot.morphology.threshold.algorithm = 'brute_force'
            mot.morphology.threshold.threshold = 128
            mot.morphology.threshold.new_min_value = 0
            mot.morphology.threshold.new_max_value = 255
            mot.image = rbr.output
            mot.image_config.bands = [1]
            mot.execute()

            # Remove holes (due to water bodies or shadows) from land with union find size filtering
            uff = protogen.Interface('union_find', 'filter')
            uff.unionfind.filter.labels_type = 'binary'
            uff.unionfind.filter.object_representation = 'coverage'
            uff.unionfind.filter.spatial_connectivity = 4
            uff.athos.dimensions = 2
            uff.athos.tree_type = 'union_find'
            uff.athos.area.usage = ['remove if less']
            uff.athos.area.min = [250000]
            uff.image = mot.output
            uff.image_config.bands = [1]
            uff.execute()

            mask = uff.output

            # Copy mask to output folder (for debugging purposes)
            shutil.copy(mask, self.output_dir)

        # If mask is provided and with_mask is true then use the provided one
        elif self.mask and self.with_mask:
            make_mask = False
            shutil.copy(os.path.join(self.mask_path, self.mask), '.')

        # Compute band dissimilarity map with radex
        print 'Compute dissimilarity map'
        rbd = protogen.Interface('radex_scalar', 'band_dissimilarity')
        rbd.radex_scalar.band_dissimilarity.type = 'max'
        rbd.radex_scalar.band_dissimilarity.threshold = 1
        rbd.image = self.ms_image
        rbd.image_config.bands = range(1, no_bands+1)
        rbd.execute()

        if self.with_mask:

            # Apply a dilation to remove holes in the water mask (from boats and other anomalies) and invade the coastline
            print 'Dilate water mask'
            msd = protogen.Interface('morphology', 'structural')
            msd.morphology.structural.operator = 'dilation'
            msd.morphology.structural.structuring_element = 'disk'
            msd.morphology.structural.radius1 = self.dilation
            msd.image = self.mask
            msd.image_config.bands = [1]
            msd.execute()

            if not make_mask:
                print 'Match mask and image'
                # Match the dimensions of the external mask to the dissimilarity map
                # (in case there are minor differences which will mess up the masking)
                ipm = protogen.Interface('image_processor', 'match')
                ipm.image = msd.output
                ipm.image_config.bands = [1]
                ipm.slave = rbd.output
                ipm.slave_config.bands = [1]
                ipm.execute()

            # Apply the mask on the dissimilarity map
            print 'Apply mask on dissimilarity map'
            im = protogen.Interface('image_processor', 'masking')
            im.image_processor.masking.method = 'inclusion'
            im.image_processor.masking.tree_type = 'raw'
            im.image = rbd.output
            im.image_config.bands = [1]
            if not make_mask:
                im.mask = ipm.output
            else:
                im.mask = msd.output
            im.mask_config.bands = [1]
            im.execute()

        # Min-tree filtering to find objects that conform to boat geometric characteristics
        print 'Find boat candidates with min-tree filtering'
        mf = protogen.Interface('max_tree', 'filter')
        mf.maxtree.filter.filtering_rule = 'subtractive'
        mf.maxtree.filter.spatial_connectivity = 4
        mf.maxtree.filter.tree_type = 'min_tree'
        mf.athos.dimensions = 2
        mf.athos.tree_type = 'max_tree'
        mf.athos.area.usage = ['remove if outside']
        mf.athos.area.min = [self.min_size]
        mf.athos.area.max = [self.max_size]
        mf.athos.linearity2.usage = ['remove if outside']
        mf.athos.linearity2.min = [self.min_linearity]
        mf.athos.linearity2.max = [self.max_linearity]
        if self.with_mask:
            mf.image = im.output
        else:
            mf.image = rbd.output
        mf.image_config.bands = [1]
        mf.execute()

        # Produce binary image with thresholding
        print 'Threshold min-tree output'
        mot = protogen.Interface('morphology', 'threshold')
        mot.morphology.threshold.algorithm = 'brute_force'
        mot.morphology.threshold.threshold = 100
        mot.morphology.threshold.new_min_value = 0
        mot.morphology.threshold.new_max_value = 255
        mot.image = mf.output
        mot.image_config.bands = [1]
        mot.execute()

        # Generate bounding boxes
        print 'Generate vectors'
        vbb = protogen.Interface('vectorizer', 'bounding_box')
        vbb.vectorizer.bounding_box.filetype = 'geojson'
        vbb.athos.tree_type = 'union-find'
        vbb.athos.dimensions = 2
        vbb.athos.area.export = [1]
        vbb.image = mot.output
        vbb.image_config.bands = [1]
        vbb.execute()

        # Rename geojson and copy it to output folder (for debugging purposes)
        shutil.move(vbb.output, 'candidates.geojson')
        shutil.copy('candidates.geojson', self.output_dir)
Example #4
0
    def extract_candidates(self):
        '''
        Use protogen to generate candidate bounding boxes.
        The function returns the name of the geojson file containing the bounding
        boxes.
        '''

        # Make the multispectral image directory the working directory
        os.chdir(self.ms_image_path)

        # Get number of bands (depends on sensor)
        no_bands = gdal.Open(self.ms_image).RasterCount

        # If mask is not provided then make one
        if not self.mask:

            print 'Creating water mask'
            make_mask = True

            print '- compute extent in utm coordinates'
            img = gdal.Open(self.ms_image)
            ulx, xres, xskew, uly, yskew, yres = img.GetGeoTransform()
            lrx = ulx + (img.RasterXSize * xres)
            lry = uly + (img.RasterYSize * yres)
            utm_number, utm_proj4 = get_utm_info(self.ms_image)
            print '- UTM {}: ulx, uly, lrx, lry: {} {} {} {}'.format(
                utm_number, ulx, uly, lrx, lry)
            northern = (utm_number > 0)

            # Get extent in EPSG:4326
            y1, x1 = utm.to_latlon(ulx,
                                   uly,
                                   zone_number=abs(utm_number),
                                   northern=northern)
            y2, x2 = utm.to_latlon(lrx,
                                   uly,
                                   zone_number=abs(utm_number),
                                   northern=northern)
            y3, x3 = utm.to_latlon(lrx,
                                   lry,
                                   zone_number=abs(utm_number),
                                   northern=northern)
            y4, x4 = utm.to_latlon(ulx,
                                   lry,
                                   zone_number=abs(utm_number),
                                   northern=northern)

            print '- clip water polygons to raster extent and reproject clipped shapefile to UTM'
            buffer_min, buffer_max = 0.99, 1.01
            command = 'ogr2ogr {} {} -spat {} {} {} {} -clipsrc spat_extent'.format(
                '/water-polygons/water.shp',
                '/water-polygons/water_polygons.shp', buffer_min * min(x1, x4),
                buffer_min * min(y3, y4), buffer_max * max(x2, x3),
                buffer_max * max(y1, y2))
            out, err = execute_this(command)
            command = """ogr2ogr {} {} -s_srs EPSG:4326 -t_srs '{}'""".format(
                '/water-polygons/water-utm.shp', '/water-polygons/water.shp',
                utm_proj4)
            out, err = execute_this(command)

            print '- burn mask'
            command = 'gdal_rasterize -ot Byte -burn 255 -te {} {} {} {} -tr {} {} {} {}'.format(
                ulx, lry, lrx, uly, xres, yres,
                '/water-polygons/water-utm.shp', 'mask.tif')
            out, err = execute_this(command)

            # Copy mask to output folder
            shutil.copy('mask.tif', self.output_mask_dir)

        # If mask is provided then use the provided one
        elif self.mask:
            make_mask = False
            shutil.copy(join(self.mask_path, self.mask), 'mask.tif')

        # Compute band dissimilarity map with radex
        print 'Compute dissimilarity map'
        rbd = protogen.Interface('radex_scalar', 'band_dissimilarity')
        rbd.radex_scalar.band_dissimilarity.type = 'max'
        rbd.radex_scalar.band_dissimilarity.threshold = 1
        rbd.image = self.ms_image
        rbd.image_config.bands = range(1, no_bands + 1)
        rbd.execute()

        # Apply erosion to water mask
        print 'Eroding water mask'
        msd = protogen.Interface('morphology', 'structural')
        msd.morphology.structural.operator = 'erosion'
        msd.morphology.structural.structuring_element = 'disk'
        msd.morphology.structural.radius1 = self.erosion
        msd.image = 'mask.tif'
        msd.image_config.bands = [1]
        msd.execute()

        # Apply the mask on the dissimilarity map
        print 'Apply mask on dissimilarity map'
        im = protogen.Interface('image_processor', 'masking')
        im.image_processor.masking.method = 'inclusion'
        im.image_processor.masking.tree_type = 'raw'
        im.image = rbd.output
        im.image_config.bands = [1]
        if not make_mask:
            print 'Match mask and image'
            # Match the dimensions of the external mask to the dissimilarity map
            # (in case there are minor differences which will mess up the masking)
            ipm = protogen.Interface('image_processor', 'match')
            ipm.image = msd.output
            ipm.image_config.bands = [1]
            ipm.slave = rbd.output
            ipm.slave_config.bands = [1]
            ipm.execute()
            im.mask = ipm.output
        else:
            im.mask = msd.output
        im.mask_config.bands = [1]
        im.execute()

        # Min-tree filtering to find objects that conform to boat geometric characteristics
        print 'Find boat candidates with min-tree filtering'
        mf = protogen.Interface('max_tree', 'filter')
        mf.maxtree.filter.filtering_rule = 'subtractive'
        mf.maxtree.filter.spatial_connectivity = 4
        mf.maxtree.filter.tree_type = 'min_tree'
        mf.athos.dimensions = 2
        mf.athos.tree_type = 'max_tree'
        mf.athos.area.usage = ['remove if outside']
        mf.athos.area.min = [self.min_size]
        mf.athos.area.max = [self.max_size]
        mf.athos.linearity2.usage = ['remove if outside']
        mf.athos.linearity2.min = [self.min_linearity]
        mf.athos.linearity2.max = [self.max_linearity]
        mf.image = im.output
        mf.image_config.bands = [1]
        mf.execute()

        # Produce binary image with thresholding
        print 'Threshold min-tree output'
        mot = protogen.Interface('morphology', 'threshold')
        mot.morphology.threshold.algorithm = 'brute_force'
        mot.morphology.threshold.threshold = 100
        mot.morphology.threshold.new_min_value = 0
        mot.morphology.threshold.new_max_value = 255
        mot.image = mf.output
        mot.image_config.bands = [1]
        mot.execute()

        # Generate bounding boxes
        print 'Generate vectors'
        vbb = protogen.Interface('vectorizer', 'bounding_box')
        vbb.vectorizer.bounding_box.filetype = 'geojson'
        vbb.athos.tree_type = 'union-find'
        vbb.athos.dimensions = 2
        vbb.athos.area.export = [1]
        vbb.image = mot.output
        vbb.image_config.bands = [1]
        vbb.execute()

        # Rename geojson and copy it to candidates folder
        shutil.move(vbb.output, 'candidates.geojson')
        shutil.copy('candidates.geojson', self.candidates_dir)

        # Return to home dir
        os.chdir('/')