Exemplo n.º 1
0
    def _fusion(self, L8_HLS, S2_HLS_img, S2_HLS_plus_img, mask_filename=None):

        log.info('fusion')
        # read array
        L8_HLS_img = L8_HLS.array

        # resize low res to high res
        L8_HLS_plus_BILINEAR_img = skit_resize(
            L8_HLS_img.clip(min=-1.0, max=1.0),
            S2_HLS_plus_img.shape).astype(np.float32)
        S2_HLS_plus_LOWPASS_img = S2_HLS_img

        # high pass of high res
        S2_HLS_plus_HIGHPASS_img = S2_HLS_plus_img - S2_HLS_plus_LOWPASS_img

        # fusion
        L8_HLS_plus_FUSION_img = L8_HLS_plus_BILINEAR_img + S2_HLS_plus_HIGHPASS_img

        # masking
        if mask_filename:
            mask_file = S2L_ImageFile(mask_filename)
            msk = mask_file.array
            if msk.shape != L8_HLS_plus_FUSION_img.shape:
                msk = skit_resize(msk.clip(min=-1.0, max=1.0),
                                  L8_HLS_plus_FUSION_img.shape,
                                  order=0,
                                  preserve_range=True).astype(np.uint8)
            L8_HLS_plus_FUSION_img[msk == 0] = 0

        return L8_HLS_plus_FUSION_img
Exemplo n.º 2
0
    def _composite(self, product, band_s2, output_shape):
        """
        Makes a composite from reference products (usually last S2 L2F/L2H products), with the most recent
        valid pixels (no predict), using validity masks.
        Returns 2 images, one high res (typically 10 or 20m), and one low resolution (typically 30m)
        resampled to high res.

        :param pd: L8 product (S2L_Product object)
        :param bandindex: band index
        :return: 2 composites (high res and low res upsampled to high res)
        """

        log.info('compositing with {} products'.format(
            len(self.reference_products)))

        array_L2H_compo = None
        array_L2F_compo = None

        for pd in self.reference_products:

            # image L2F
            image_file_L2F = pd.get_band_file(band_s2, plus=True)
            array_L2F = image_file_L2F.array.astype(np.float32) / 10000.

            # image L2H
            array_L2H = self.get_harmonized_product(pd, band_s2, output_shape,
                                                    False)

            # resample L2H to resolution of L2F (prepraring LOWPASS):
            array_L2H = skit_resize(array_L2H.clip(min=-1.0, max=1.0),
                                    output_shape,
                                    order=1).astype(np.float32)

            # read mask :
            mskfile = pd.getMaskFile()
            msk = mskfile.array

            # resample mask if needed
            if msk.shape != array_L2F.shape:
                msk = skit_resize(msk.clip(min=-1.0, max=1.0),
                                  output_shape,
                                  order=0,
                                  preserve_range=True).astype(np.uint8)

            # apply in composite
            if array_L2H_compo is None:
                array_L2H_compo = np.zeros(output_shape, np.float32)
                array_L2F_compo = np.zeros(output_shape, np.float32)
            array_L2H_compo = np.where(msk == 0, array_L2H_compo, array_L2H)
            array_L2F_compo = np.where(msk == 0, array_L2F_compo, array_L2F)

        return array_L2H_compo, array_L2F_compo
Exemplo n.º 3
0
def resample(imagein, res, filepath_out):
    # create output dir if not exist
    dirout = os.path.dirname(filepath_out)
    if not os.path.exists(dirout):
        os.makedirs(dirout)

    # get input resolutionresolution
    input_res = imagein.xRes
    dst_in = None

    # SCIKIT resampling
    fullRes = imagein.array

    # Method1: BLOCK REDUCE (10->30):
    if input_res == 10 and res % input_res == 0:
        R = int(res / input_res)  # resolution factor
        data = np.uint16(block_reduce(fullRes, block_size=(R, R), func=np.mean) + 0.5)  # source: sen2cor

    # Method2: SCIKIT RESIZE (20->30, 60->30)
    else:
        sizeUp = fullRes.shape[0] * input_res / res
        # order 3 is for cubic spline:
        data = (skit_resize(fullRes.astype(np.uint16), ([sizeUp, sizeUp]), order=3) * 65535.).round().astype(
            np.uint16)

    imageout = imagein.duplicate(filepath_out, array=data, res=res)

    return imageout
Exemplo n.º 4
0
    def _get_qa_band(self, shape):
        # Compute number of dates
        number_of_dates = len(self.reference_products)

        # Read first image :
        # Create an empty numpy n-d array :
        msk_qa = np.zeros(shape, dtype=np.uint8)

        # Read and save in a n-d numpy array the mask for each date
        # Create QA Band as output of this processing :
        for i in range(1, number_of_dates + 1, 1):
            pd = self.reference_products[i - 1]
            mskfile = pd.getMaskFile()
            log.debug(mskfile.filepath)
            msk = mskfile.array

            if msk.shape != shape:
                msk = skit_resize(msk.clip(min=-1.0, max=1.0),
                                  shape,
                                  order=0,
                                  preserve_range=True).astype(np.uint8)

            msk_qa += msk * np.power(2, i)

        return msk_qa
Exemplo n.º 5
0
def KLT_Tracker(reference, imagedata, mask, matching_winsize=25):
    ##

    log.info("extract_features")
    imagedata = extract_features(imagedata)
    reference = extract_features(reference)

    # check mask shape
    if mask.shape != imagedata.shape:
        log.info("resize mask")
        mask = skit_resize(mask.clip(min=-1.0, max=1.0), imagedata.shape, order=0, preserve_range=True).astype(
            np.uint8)

    # compute the initial point set
    # goodFeaturesToTrack input parameters
    feature_params = dict(maxCorners=20000, qualityLevel=0.1,
                          minDistance=10, blockSize=15)
    # goodFeaturesToTrack corner extraction-ShiThomasi Feature Detector
    log.info("goodFeaturesToTrack")
    p0 = cv2.goodFeaturesToTrack(
        reference, mask=mask, **feature_params)
    if p0 is None:
        log.error("No features extracted")
        return None, None, 0

    # define KLT parameters-for matching
    log.info("Using window of size {} for matching.".format(matching_winsize))
    # LSM input parameters - termination criteria for corner estimation/stopping criteria
    lk_params = dict(winSize=(matching_winsize, matching_winsize),
                     maxLevel=1,
                     criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 30, 0.03))

    p1, st, __ = cv2.calcOpticalFlowPyrLK(reference, imagedata, p0, None,
                                          **lk_params)  # LSM image matching- KLT tracker

    # Backward-check
    back_threshold = 0.01
    p0r, st, __ = cv2.calcOpticalFlowPyrLK(imagedata, reference, p1, None,
                                           **lk_params)  # LSM image matching- KLT tracker

    d = abs(p0 - p0r).reshape(-1, 2).max(-1)
    st = d < back_threshold

    logging.debug("Nb Bad Status: {}".format(len(st[st == 0])))

    p0 = p0[st]
    p1 = p1[st]

    x0 = p0[:, :, 0].ravel()
    y0 = p0[:, :, 1].ravel()
    x1 = p1[:, :, 0].ravel()
    y1 = p1[:, :, 1].ravel()

    # analyze points and remove outliers
    n_init = len(x0)
    x0, y0, x1, y1, dx, dy = pointcheck(x0, y0, x1, y1)

    return np.array(dx), np.array(dy), n_init
Exemplo n.º 6
0
    def get_harmonized_product(product, band_s2, output_shape, plus):
        image_file = product.get_band_file(band_s2, plus=plus)

        if image_file is None:
            log.info('Resampling to 30m: Start...')
            band_file = product.get_band_file(band_s2, plus=True)
            match = re.search(r'_(\d{2})m', band_file.filename)
            if match:
                resampled_file = band_file.filename.replace(
                    match.group(1), '30')
            else:
                resampled_file = band_file.filename.replace(
                    '.', '_resampled_30m.')
            image_file = mgrs_framing.resample(
                band_file, 30, os.path.join(band_file.dirpath, resampled_file))
            log.info('Resampling to 30m: End')
        array = image_file.array.astype(np.float32) / 10000.
        if output_shape != array.shape:
            array = skit_resize(array.clip(min=-1.0, max=1.0),
                                output_shape).astype(np.float32)
        return array
Exemplo n.º 7
0
    def importBand(self, bandIndex, filename):
        ''' convert JPEG-2000 input file to internal H5 file format.
        
            :param bandIndex: the band index.
            :type bandIndex: unsigned int
            :param filename: file name of JPEG-2000 input image.
            :type filename: str
            :return: false if error occurred during import.
            :rtype: boolean
            
        '''
        from skimage.transform import resize as skit_resize
        # convert JPEG-2000 input file to H5 file format
        self.verifyProductId(self._productLevel)
        warnings.filterwarnings("ignore")
        indataset = glymur.Jp2k(filename)
        ncols = indataset.shape[1]
        indataArr = indataset[:]
        # fix for SIIMPC-558.2, UMW:
        # update the geobox for own resolution:
        if (bandIndex == 0) | (bandIndex == 1) | (bandIndex == 5):
            self._geobox = indataset.box[3]
            # end fix for SIIMPC-558.2

        if self.config.resolution == 10:
            # upsampling is required, order 3 is for cubic spline:
            if (bandIndex == self.SCL) | (bandIndex == self.CLD):
                size = self.getBandSize('L3', self.B02)
                ncols = size[0]
                indataArr = (
                    skit_resize(indataArr.astype(uint8), size, order=1) *
                    255.).round().astype(uint8)

        indataset = None
        # Create new arrays:
        database = self._imageDatabase
        nodeStr = self._productLevel
        bandName = self.getBandNameFromIndex(bandIndex)
        try:
            if self.testBand(self._productLevel, bandIndex) == True:
                self.delBand(self._productLevel, bandIndex)
            h5file = open_file(database, mode='a')
            if not (h5file.__contains__('/' + nodeStr)):
                self.config.logger.fatal(
                    'table initialization, wrong node %s:' % nodeStr)
                self.config.exitError()
                return False

            if self._productLevel == 'L2A':
                locator = h5file.root.L2A
            elif self._productLevel == 'L3':
                locator = h5file.root.L3

            dtOut = self.mapDataType(indataArr.dtype)
            filters = Filters(complib="zlib", complevel=1)
            node = h5file.create_earray(locator,
                                        bandName,
                                        dtOut, (0, ncols),
                                        bandName,
                                        filters=filters)
            node.append(indataArr)
            self.config.timestamp('L3_Tables: Level ' + self._productLevel +
                                  ' band ' + bandName + ' imported')
            result = True
        except:
            indataArr = None
            self.config.logger.fatal(
                'error in import of band %s in productLevel %s.' %
                (bandName, self._productLevel))
            self.config.exitError()
            result = False

        indataArr = None
        h5file.close()
        return result
Exemplo n.º 8
0
    def get_valid_pixel_mask(self, mask_filename, res=20):
        """
        :param res:
        :param mask_filename:
        :return:
        """

        if self.scene_classif_band:
            log.info('Generating validity and nodata masks from SCL band')
            log.debug(f'Read SCL: {self.scene_classif_band}')
            scl = S2L_ImageFile(self.scene_classif_band)
            scl_array = scl.array

            valid_px_mask = np.zeros(scl_array.shape, np.uint8)
            # Consider as valid pixels :
            #                VEGETATION et NOT_VEGETATED (valeurs 4 et 5)
            #                UNCLASSIFIED (7) et SNOW (11) -
            valid_px_mask[scl_array == 4] = 1
            valid_px_mask[scl_array == 5] = 1
            valid_px_mask[scl_array == 7] = 1
            valid_px_mask[scl_array == 11] = 1

            mask = scl.duplicate(mask_filename, array=valid_px_mask)
            mask.write(creation_options=['COMPRESS=LZW'])
            self.mask_filename = mask_filename

            # nodata mask
            mask_filename = os.path.join(os.path.dirname(mask_filename),
                                         'nodata_pixel_mask.tif')
            nodata = np.ones(scl_array.shape, np.uint8)
            nodata[scl_array == 0] = 0
            mask = scl.duplicate(mask_filename, array=nodata)
            mask.write(creation_options=['COMPRESS=LZW'])
            self.nodata_mask_filename = mask_filename

            return True

        # L1C case for instance -> No SCL, but NODATA and CLD mask
        else:
            # Nodata Mask
            nodata_ref_band = 'B01'
            band_path = self.bands[nodata_ref_band]
            log.info(f'Generating nodata mask from band {nodata_ref_band}')
            log.debug(f'Read cloud mask: {band_path}')
            image = S2L_ImageFile(band_path)
            array = image.array
            nodata_mask_filename = os.path.join(
                os.path.dirname(mask_filename),
                f'nodata_pixel_mask_{nodata_ref_band}.tif')
            nodata = np.ones(array.shape, np.uint8)
            # shall be 0, but due to compression artefact, threshold increased to 4:
            nodata[array <= 4] = 0

            # resize nodata to output res
            shape = (int(nodata.shape[0] * -image.yRes / res),
                     int(nodata.shape[1] * image.xRes / res))
            log.debug(shape)
            nodata = skit_resize(nodata, shape, order=0,
                                 preserve_range=True).astype(np.uint8)

            # save to image
            mask = image.duplicate(nodata_mask_filename, array=nodata, res=res)
            mask.write(creation_options=['COMPRESS=LZW'], nodata_value=None)
            self.nodata_mask_filename = nodata_mask_filename

            if self.cloudmask:
                # Cloud mask
                rname, ext = os.path.splitext(self.cloudmask)
                if ext == '.gml':
                    log.info('Generating validity mask from cloud mask')
                    log.debug(f'Read cloud mask: {self.cloudmask}')
                    # Check if any cloud feature in gml
                    dom = minidom.parse(self.cloudmask)
                    nClouds = len(dom.getElementsByTagName('eop:MaskFeature'))

                    # rasterize
                    # make byte mask 0/1, LZW compression
                    if nClouds > 0:
                        outputBounds = [self.ULX, self.LRY, self.LRX, self.ULY]
                        if not os.path.exists(os.path.dirname(mask_filename)):
                            os.makedirs(os.path.dirname(mask_filename))
                        gdal.Rasterize(mask_filename,
                                       self.cloudmask,
                                       outputType=gdal.GDT_Byte,
                                       creationOptions=['COMPRESS=LZW'],
                                       burnValues=0,
                                       initValues=1,
                                       outputBounds=outputBounds,
                                       outputSRS=self.epsg,
                                       xRes=res,
                                       yRes=res)

                        # apply nodata to validity mask
                        dataset = gdal.Open(mask_filename, gdal.GA_Update)
                        array = dataset.GetRasterBand(1).ReadAsArray()
                        array[nodata == 0] = 0
                        dataset.GetRasterBand(1).WriteArray(array)
                        dataset = None
                    else:
                        # no cloud mask, copy nodata mask
                        shutil.copy(self.nodata_mask_filename, mask_filename)
                    log.info('Written: {}'.format(mask_filename))
                    self.mask_filename = mask_filename

            return True