Exemple #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
Exemple #2
0
    def residualAnalysis(self,
                         disaggregatedFile,
                         lowResFilename,
                         lowResQualityFilename=None,
                         doCorrection=True):
        ''' Perform residual analysis and (optional) correction on the
        disaggregated file (see [Gao2012] 2.4).

        Parameters
        ----------
        disaggregatedFile: string or GDAL file object
            If string, path to the disaggregated image file; if gdal file
            object, the disaggregated image.

        lowResFilename: string
            Path to the low-resolution image file corresponding to the
            high-resolution disaggregated image.

        lowResQualityFilename: string (optional, default: None)
            Path to low-resolution quality image file. If provided then low
            quality values are masked out during residual analysis. Otherwise
            all values are considered to be of good quality.

        doCorrection: boolean (optional, default: True)
            Flag indication whether residual (bias) correction should be
            performed or not.


        Returns
        -------
        residualImage: GDAL memory file object
            The file object contains an in-memory, georeferenced residual image.

        correctedImage: GDAL memory file object
            The file object contains an in-memory, georeferenced residual
            corrected disaggregated image, or None if doCorrection was set to
            False.
        '''

        if not os.path.isfile(str(disaggregatedFile)):
            scene_HR = disaggregatedFile
        else:
            scene_HR = gdal.Open(disaggregatedFile)
        scene_LR = gdal.Open(lowResFilename)
        if lowResQualityFilename is not None:
            quality_LR = gdal.Open(lowResQualityFilename)
        else:
            quality_LR = None

        residual_HR, residual_LR, gt_res = self._calculateResidual(
            scene_HR, scene_LR, quality_LR)

        if self.disaggregatingTemperature:
            if doCorrection:
                corrected = (residual_HR +
                             scene_HR.GetRasterBand(1).ReadAsArray()**4)**0.25
                correctedImage = utils.saveImg(corrected,
                                               scene_HR.GetGeoTransform(),
                                               scene_HR.GetProjection(),
                                               "MEM",
                                               noDataValue=np.nan)
            else:
                correctedImage = None
            # Convert residual back to temperature for easier visualisation
            residual_LR = (residual_LR + 273.15**4)**0.25 - 273.15
        else:
            if doCorrection:
                corrected = residual_HR + scene_HR.GetRasterBand(
                    1).ReadAsArray()
                correctedImage = utils.saveImg(corrected,
                                               scene_HR.GetGeoTransform(),
                                               scene_HR.GetProjection(),
                                               "MEM",
                                               noDataValue=np.nan)
            else:
                correctedImage = None

        residualImage = utils.saveImg(residual_LR,
                                      gt_res,
                                      scene_HR.GetProjection(),
                                      "MEM",
                                      noDataValue=np.nan)

        print("LR residual bias: " + str(np.nanmean(residual_LR)))
        print("LR residual RMSD: " + str(np.nanmean(residual_LR**2)**0.5))

        scene_HR = None
        scene_LR = None
        quality_LR = None

        return residualImage, correctedImage
Exemple #3
0
    print("Training regressor...")
    disaggregator.trainSharpener()
    print("Sharpening...")
    downscaledFile = disaggregator.applySharpener(highResFilename,
                                                  lowResFilename)
    print("Residual analysis...")
    residualImage, correctedImage = disaggregator.residualAnalysis(
        downscaledFile, lowResFilename, lowResMaskFilename, doCorrection=True)
    print("Saving output...")
    highResFile = gdal.Open(highResFilename)
    if correctedImage is not None:
        outImage = correctedImage
    else:
        outImage = downscaledFile
    # outData = utils.binomialSmoother(outData)
    outFile = utils.saveImg(
        outImage.GetRasterBand(1).ReadAsArray(), outImage.GetGeoTransform(),
        outImage.GetProjection(), outputFilename)
    residualFile = utils.saveImg(
        residualImage.GetRasterBand(1).ReadAsArray(),
        residualImage.GetGeoTransform(), residualImage.GetProjection(),
        os.path.splitext(outputFilename)[0] + "_residual" +
        os.path.splitext(outputFilename)[1])

    outFile = None
    residualFile = None
    downsaceldFile = None
    highResFile = None

    print(time.time() - start_time, "seconds")
Exemple #4
0
    def applySharpener(self, highResFilename, lowResFilename=None):
        ''' Apply the trained sharpener to a given high-resolution image to
        derive corresponding disaggregated low-resolution image. If local
        regressions were used during training then they will only be applied
        where their moving window extent overlaps with the high resolution
        image passed to this function. Global regression will be applied to the
        whole high-resolution image wihtout geographic constraints.

        Parameters
        ----------
        highResFilename: string
            Path to the high-resolution image file do be used during
            disaggregation.

        lowResFilename: string (optional, default: None)
            Path to the low-resolution image file corresponding to the
            high-resolution input file. If local regressions
            were trained and low-resolution filename is given then the local
            and global regressions will be combined based on residual values of
            the different regressions to the low-resolution image (see [Gao2012]
            2.3). If local regressions were trained and low-resolution
            filename is not given then only the local regressions will be used.


        Returns
        -------
        outImage: GDAL memory file object
            The file object contains an in-memory, georeferenced disaggregator
            output.
        '''

        # Open and read the high resolution input file
        highResFile = gdal.Open(highResFilename)
        inData = np.zeros((highResFile.RasterYSize, highResFile.RasterXSize,
                           highResFile.RasterCount))
        for band in range(highResFile.RasterCount):
            data = highResFile.GetRasterBand(band +
                                             1).ReadAsArray().astype(float)
            no_data = highResFile.GetRasterBand(band + 1).GetNoDataValue()
            data[data == no_data] = np.nan
            inData[:, :, band] = data
        gt = highResFile.GetGeoTransform()

        shape = inData.shape
        ysize = shape[0]
        xsize = shape[1]

        # Temporarly get rid of NaN's
        nanInd = np.isnan(inData)
        inData[nanInd] = 0
        outWindowData = np.empty((ysize, xsize)) * np.nan

        # Do the downscailing on the moving windows if there are any
        for i, extent in enumerate(self.windowExtents):
            if self.reg[i] is not None:
                [minX, minY] = utils.point2pix(extent[0], gt)  # UL
                [minX, minY] = [max(minX, 0), max(minY, 0)]
                [maxX, maxY] = utils.point2pix(extent[1], gt)  # LR
                [maxX, maxY] = [min(maxX, xsize), min(maxY, ysize)]
                windowInData = inData[minY:maxY, minX:maxX, :]
                outWindowData[minY:maxY, minX:maxX] = \
                    self._doPredict(windowInData, self.reg[i])

        # Do the downscailing on the whole input image
        if self.reg[-1] is not None:
            outFullData = self._doPredict(inData, self.reg[-1])
        else:
            outFullData = np.empty((ysize, xsize)) * np.nan

        # Combine the windowed and whole image regressions
        # If there is no windowed regression just use the whole image regression
        if np.all(np.isnan(outWindowData)):
            outData = outFullData
        # If corresponding low resolution file is provided then combine the two
        # regressions based on residuals (see section 2.3 of Gao paper)
        elif lowResFilename is not None:
            lowResScene = gdal.Open(lowResFilename)
            outWindowScene = utils.saveImg(outWindowData,
                                           highResFile.GetGeoTransform(),
                                           highResFile.GetProjection(),
                                           "MEM",
                                           noDataValue=np.nan)
            windowedResidual, _, _ = self._calculateResidual(
                outWindowScene, lowResScene)
            outWindowScene = None
            outFullScene = utils.saveImg(outFullData,
                                         highResFile.GetGeoTransform(),
                                         highResFile.GetProjection(),
                                         "MEM",
                                         noDataValue=np.nan)
            fullResidual, _, _ = self._calculateResidual(
                outFullScene, lowResScene)
            outFullScene = None
            lowResScene = None
            # windowed weight
            ww = (1 / windowedResidual)**2 / ((1 / windowedResidual)**2 +
                                              (1 / fullResidual)**2)
            # full weight
            fw = 1 - ww
            outData = outWindowData * ww + outFullData * fw
        # Otherwised use just windowed regression
        else:
            outData = outWindowData

        # Fix NaN's
        nanInd = np.any(nanInd, -1)
        outData[nanInd] = np.nan

        outImage = utils.saveImg(outData,
                                 highResFile.GetGeoTransform(),
                                 highResFile.GetProjection(),
                                 "MEM",
                                 noDataValue=np.nan)

        highResFile = None
        inData = None
        return outImage
Exemple #5
0
def save_image(data, geotransform, projection, filename):
    return saveImg(data, geotransform, projection, filename)