Exemplo n.º 1
0
    def _calculateResidual(self,
                           downscaledScene,
                           originalScene,
                           originalSceneQuality=None):
        ''' Private function. Calculates residual between overlapping
            high-resolution and low-resolution images.
        '''

        # First subset and reproject original (low res) scene to fit with
        # downscaled (high res) scene
        subsetScene_LR = utils.reprojectSubsetLowResScene(
            downscaledScene,
            originalScene,
            resampleAlg=gdal.GRA_NearestNeighbour)
        data_LR = subsetScene_LR.GetRasterBand(1).ReadAsArray().astype(float)
        gt_LR = subsetScene_LR.GetGeoTransform()

        # If quality file for the low res scene is provided then mask out all
        # bad quality pixels in the subsetted LR scene. Otherwise assume that all
        # low res pixels are of good quality.
        if originalSceneQuality is not None:
            subsetQuality_LR = utils.reprojectSubsetLowResScene(
                downscaledScene,
                originalSceneQuality,
                resampleAlg=gdal.GRA_NearestNeighbour)
            goodPixMask_LR = subsetQuality_LR.GetRasterBand(1).ReadAsArray()
            goodPixMask_LR = np.in1d(goodPixMask_LR.ravel(),
                                     self.lowResGoodQualityFlags).reshape(
                                         goodPixMask_LR.shape)
            data_LR[~goodPixMask_LR] = np.nan

        # Then resample high res scene to low res pixel size
        if self.disaggregatingTemperature:
            # When working with tempratures they should be converted to
            # radiance values before aggregating to be physically accurate.
            radianceScene = utils.saveImg(
                downscaledScene.GetRasterBand(1).ReadAsArray()**4,
                downscaledScene.GetGeoTransform(),
                downscaledScene.GetProjection(),
                "MEM",
                noDataValue=np.nan)
            resMean, _ = utils.resampleHighResToLowRes(radianceScene,
                                                       subsetScene_LR)
            # Find the residual (difference) between the two)
            residual_LR = data_LR**4 - resMean[:, :, 0]
        else:
            resMean, _ = utils.resampleHighResToLowRes(downscaledScene,
                                                       subsetScene_LR)
            # Find the residual (difference) between the two
            residual_LR = data_LR - resMean[:, :, 0]

        # Smooth the residual and resample to high resolution
        residual = utils.binomialSmoother(residual_LR)
        residualDs = utils.saveImg(residual,
                                   subsetScene_LR.GetGeoTransform(),
                                   subsetScene_LR.GetProjection(),
                                   "MEM",
                                   noDataValue=np.nan)
        residualScene_BL = utils.resampleWithGdalWarp(residualDs,
                                                      downscaledScene,
                                                      resampleAlg="bilinear")
        residualDs = None

        residual = residualScene_BL.GetRasterBand(1).ReadAsArray()
        # Sometimes there can be 1 HR pixel NaN border arond LR invalid pixels due to resampling.
        # Fuction below fixes this. Image border pixels are excluded due to numba stencil
        # limitations.
        residual[1:-1, 1:-1] = utils.removeEdgeNaNs(residual)[1:-1, 1:-1]
        residualScene_BL = None

        # The residual array might be slightly smaller then the downscaled because
        # of the subsetting of the low resolution scene. In that case just pad
        # the missing values with neighbours.
        downscaled = downscaledScene.GetRasterBand(1).ReadAsArray()
        if downscaled.shape != residual.shape:
            temp = np.zeros(downscaled.shape)
            temp[:residual.shape[0], :residual.shape[1]] = residual
            temp[residual.shape[0]:, :] = \
                temp[2*(residual.shape[0] - downscaled.shape[0]):residual.shape[0] - downscaled.shape[0], :]
            temp[:, residual.shape[1]:] = \
                temp[:, 2*(residual.shape[1] - downscaled.shape[1]):residual.shape[1] - downscaled.shape[1]]

            residual = temp

        residualScene = None
        subsetScene_LR = None
        subsetQuality_LR = None

        return residual, residual_LR, gt_LR
Exemplo n.º 2
0
    def trainSharpener(self):
        ''' Train the sharpener using high- and low-resolution input files
        and settings specified in the constructor. Local (moving window) and
        global regression decision trees are trained with high-resolution data
        resampled to low resolution and low-resolution data. The training
        dataset is selected based on homogeneity of resampled high-resolution
        data being below specified threshold and quality mask (if given) of
        low resolution data. The homogeneity statistics are also used as weight
        factors for the training samples (more homogenous - higher weight).

        Parameters
        ----------
        None

        Returns
        -------
        None
        '''

        # Select good data (training samples) from low- and high-resolution
        # input images.
        fileNum = 0
        for highResFile, lowResFile in zip(self.highResFiles,
                                           self.lowResFiles):

            scene_HR = gdal.Open(highResFile)
            scene_LR = gdal.Open(lowResFile)

            # First subset and reproject low res scene to fit with
            # high res scene
            subsetScene_LR = utils.reprojectSubsetLowResScene(
                scene_HR, scene_LR)
            data_LR = subsetScene_LR.GetRasterBand(1).ReadAsArray()
            gt_LR = subsetScene_LR.GetGeoTransform()

            # Do the same with low res quality file (if provided) and flag
            # pixels which are considered to be of good quality
            if self.useQuality_LR:
                quality_LR = gdal.Open(self.lowResQualityFiles[fileNum])
                subsetQuality_LR = utils.reprojectSubsetLowResScene(
                    scene_HR, quality_LR)
                subsetQualityMask = subsetQuality_LR.GetRasterBand(
                    1).ReadAsArray()
                qualityPix = np.in1d(subsetQualityMask.ravel(),
                                     self.lowResGoodQualityFlags).reshape(
                                         subsetQualityMask.shape)
                quality_LR = None
            else:
                qualityPix = np.ones(data_LR.shape).astype(bool)

            # Low resolution pixels with NaN value are always of bad quality
            qualityPix = np.logical_and(qualityPix, ~np.isnan(data_LR))

            # Then resample high res scene to low res pixel size while
            # extracting sub-low-res-pixel homogeneity statistics
            resMean, resStd = utils.resampleHighResToLowRes(
                scene_HR, subsetScene_LR)
            resMean[resMean == 0] = 0.000001
            resCV = np.sum(resStd / resMean, 2) / resMean.shape[2]
            resCV[np.isnan(resCV)] = 1000

            # Resampled high resolution pixels where at least one "parameter"
            # is NaN are also of bad quality
            resNaN = np.any(np.isnan(resMean), -1)
            qualityPix = np.logical_and(qualityPix, ~resNaN)

            windows = []
            extents = []
            # If moving window approach is used (section 2.3 of Gao paper)
            # then calculate the extent of each sampling window in low
            # resolution pixels
            if self.movingWindowSize > 0:
                for y in range(
                        int(math.ceil(data_LR.shape[0] /
                                      self.movingWindowSize))):
                    for x in range(
                            int(
                                math.ceil(data_LR.shape[1] /
                                          self.movingWindowSize))):
                        windows.append([
                            int(
                                max(
                                    y * self.movingWindowSize -
                                    self.movingWindowExtension, 0)),
                            int(
                                min((y + 1) * self.movingWindowSize +
                                    self.movingWindowExtension,
                                    data_LR.shape[0])),
                            int(
                                max(
                                    x * self.movingWindowSize -
                                    self.movingWindowExtension, 0)),
                            int(
                                min((x + 1) * self.movingWindowSize +
                                    self.movingWindowExtension,
                                    data_LR.shape[1]))
                        ])
                        # Save the extents of this window in projection coordinates as
                        # UL and LR point coordinates
                        ul = utils.pix2point([
                            x * self.movingWindowSize,
                            y * self.movingWindowSize
                        ], gt_LR)
                        lr = utils.pix2point([(x + 1) * self.movingWindowSize,
                                              (y + 1) * self.movingWindowSize],
                                             gt_LR)
                        extents.append([ul, lr])

            # And always add the whole extent of low res image to also estimate
            # the regression tree for the whole image
            windows.append([0, data_LR.shape[0], 0, data_LR.shape[1]])

            goodData_LR = [None for _ in range(len(windows))]
            goodData_HR = [None for _ in range(len(windows))]
            weight = [None for _ in range(len(windows))]

            # For each window extract the good quality low res and high res pixels
            for i, window in enumerate(windows):
                rows = slice(window[0], window[1])
                cols = slice(window[2], window[3])
                qualityPixWindow = qualityPix[rows, cols]
                resCVWindow = resCV[rows, cols]

                # Good pixels are those where low res data quality is good and
                # high res data is homonogenous
                if self.autoAdjustCvThreshold:
                    g = np.logical_and.reduce(
                        (qualityPixWindow, resCVWindow < 1000,
                         resCVWindow > 0))
                    if ~np.any(g):
                        self.cvHomogeneityThreshold = 0
                    else:
                        self.cvHomogeneityThreshold = np.percentile(
                            resCVWindow[g], self.precentileThreshold)
                    print('Homogeneity CV threshold: %.2f' %
                          self.cvHomogeneityThreshold)
                homogenousPix = np.logical_and(
                    resCVWindow < self.cvHomogeneityThreshold, resCVWindow > 0)
                goodPix = np.logical_and(homogenousPix, qualityPixWindow)

                goodData_LR[i] = utils.appendNpArray(
                    goodData_LR[i], data_LR[rows, cols][goodPix])
                goodData_HR[i] = utils.appendNpArray(
                    goodData_HR[i], resMean[rows, cols, :][goodPix, :], axis=0)

                # Also estimate weight given to each pixel as the inverse of its
                # heterogeneity
                w = 1 / resCVWindow[goodPix]
                weight[i] = utils.appendNpArray(weight[i], w)

                # Print some stats
                if np.prod(data_LR[rows, cols][qualityPixWindow].shape) > 0:
                    percentageUsedPixels = int(
                        float(np.prod(goodData_LR[i].shape)) / float(
                            np.prod(data_LR[rows,
                                            cols][qualityPixWindow].shape)) *
                        100)
                    print('Number of training elements for is ' +
                          str(np.prod(goodData_LR[i].shape)) +
                          ' representing ' + str(percentageUsedPixels) +
                          '% of avaiable low-resolution data.')

            # Close all files
            scene_HR = None
            scene_LR = None
            subsetScene_LR = None
            if self.useQuality_LR:
                subsetQuality_LR = None
            fileNum = fileNum + 1

        self.windowExtents = extents
        windowsNum = len(windows)

        # Once all the samples have been picked fit all the local and global
        # regressions
        self.reg = [None for _ in range(windowsNum)]
        for i in range(windowsNum):
            if i < windowsNum - 1:
                local = True
            else:
                local = False
            if len(goodData_LR[i]) > 0:
                self.reg[i] = \
                    self._doFit(goodData_LR[i], goodData_HR[i], weight[i], local)