def newBand(geoPicture1, geoPicture2):
  with RedirectStdStreams(stdout=sys.stderr, stderr=sys.stderr):

    geoPicture = geoPicture1

    imageIndices = {}

    for zi in numpy.array([1,2]):
        if zi==2:
            geoPicture = geoPicture2

        imageArray = FloodClassUtils.radianceCorrection(geoPicture)

        #Need to create a mask of locations where all pixels are nonzero.
        alphaBand = (geoPicture.picture[:,:,geoPicture.bands.index(geoPicture.bands[0])] > 0)
        for band in geoPicture.bands[1:]:
            numpy.logical_and(alphaBand, geoPicture.picture[:,:,geoPicture.bands.index(band)], alphaBand)

        #Find size of the image array
        rasterXsize = geoPicture.picture.shape[1]
        rasterYsize = geoPicture.picture.shape[0]

        rowIndex, colIndex = numpy.mgrid[0:rasterYsize,0:rasterXsize]

        #This is an array of the alphaBand offset by 1 in all directions surrounding a pixel.
        polygons = numpy.dstack((alphaBand[1:-1,1:-1],alphaBand[:-2,1:-1],alphaBand[:-2,2:],alphaBand[1:-1,2:],alphaBand[2:,2:], \
                                                     alphaBand[2:,1:-1],alphaBand[2:,:-2],alphaBand[1:-1,:-2],alphaBand[:-2,:-2]))

        #Polygons will be an array containing "1"s on the border of the image.
        polygons = numpy.array(numpy.logical_and(polygons.sum(2) > 0,polygons.sum(2) < 9),dtype=int) #The offset array is used to detect the outline
        polygons = numpy.hstack((numpy.zeros((polygons.shape[0]+2,1)),numpy.vstack((numpy.zeros((polygons.shape[1])),polygons,numpy.zeros((polygons.shape[1])))),numpy.zeros((polygons.shape[0]+2,1))))

        #There are too many points to calculate all lat/long.  Will calculate some, then interpolate.
        interpSize = 100j
        yy, xx = numpy.mgrid[0:(rasterYsize-1):(3*interpSize), 0:(rasterXsize-1):interpSize]
        yy = yy.reshape(-1,1)
        xx = xx.reshape(-1,1)
        yLat = numpy.zeros((yy.size,1))
        xLong = numpy.zeros((xx.size,1))
        for ij in numpy.arange(yy.size):
            yLat[ij], xLong[ij] = latLong(geoPicture,xx[ij,0],yy[ij,0])
        yLat = scipy.interpolate.griddata( numpy.hstack((xx,yy)), yLat, (colIndex.reshape(-1,1), rowIndex.reshape(-1,1)), method = 'cubic' )   #Use spline interpolation
        xLong = scipy.interpolate.griddata( numpy.hstack((xx,yy)), xLong, (colIndex.reshape(-1,1), rowIndex.reshape(-1,1)), method = 'cubic' ) #of calculated lat/long points
        boxLatMin, boxLongMin = latLong(geoPicture,0,rasterYsize-1)
        boxLatMax, boxLongMax = latLong(geoPicture,rasterXsize-1,0)
        yLat = yLat.reshape(rasterYsize,rasterXsize)
        xLong = xLong.reshape(rasterYsize,rasterXsize)

        imageIndices['image' + str(zi)] = numpy.dstack( (rowIndex, colIndex, yLat, xLong, alphaBand, polygons, imageArray) )
        imageIndices['bound' + str(zi)] = [boxLatMin,boxLatMax,boxLongMin,boxLongMax]
        imageIndices['bands' + str(zi)] = geoPicture.bands


        #clear some variables from memory
        imageArray = []
        presentBands = []
        presentBandsNum = []
        alphaBand = []
        rowIndex = []
        colIndex = []
        polygons = []
        p1 = []
        yy = []
        xx = []
        yLat = []
        xLong = []

    boundBox1 = imageIndices['bound1']
    boundBox2 = imageIndices['bound2']

    #Test whether there is any overlap, if not, don't do anything.
    crnr1 = int( (boundBox1[0] <= boundBox2[0] < boundBox1[1]) & (boundBox1[2] <= boundBox2[2] < boundBox1[3])  )
    crnr2 = int( (boundBox1[0] < boundBox2[1] <= boundBox1[1]) & (boundBox1[2] <= boundBox2[2] < boundBox1[3])  )
    crnr3 = int( (boundBox1[0] <= boundBox2[0] < boundBox1[1]) & (boundBox1[2] < boundBox2[3] <= boundBox1[3])  )
    crnr4 = int( (boundBox1[0] < boundBox2[1] <= boundBox1[1]) & (boundBox1[2] < boundBox2[3] <= boundBox1[3])  )

    chk_crnr = crnr1+crnr2+crnr3+crnr4

    if chk_crnr > 0:   #Is at least one corner from image two inside of image one

        polygon1 = imageIndices['image1']
        polygon2 = imageIndices['image2']

        presentBands1 = imageIndices['bands1']
        presentBands2 = imageIndices['bands2']

        #Only use bands common to both images for change detection
        presentBands = []
        for pB in presentBands1:
            if pB in presentBands2:
                presentBands.append([int(pB.lstrip('B')),int(presentBands1.index(pB)),int(presentBands2.index(pB))])
        presentBands = numpy.array(presentBands)
        polygon1 = numpy.dstack((polygon1[:,:,:6], polygon1[:,:,(6 + presentBands[:,1]) ] )) #Depth 6 is the beginning of the image bands. 
        polygon2 = numpy.dstack((polygon2[:,:,:6], polygon2[:,:,(6 + presentBands[:,2]) ] )) 

        imageIndices = []
        presentBands1 = []
        presentBands2 = []
        presentBands = []

        interBand1, pR2, pC2 = interpImage(polygon1,polygon2)
        interBand2, pR1, pC1 = interpImage(polygon2,polygon1)

        change_prob, imageArray1, imageArray2 = changeProb(polygon1, polygon2, interBand1,interBand2,2,1)

        #Find cloud pixels from both images to eliminate from change test
        nonCloudAddress1 = cloudFilter(imageArray1,[])
        nonCloudAddress2 = cloudFilter(imageArray2,nonCloudAddress1)

        change_prob[change_prob < 0 ] = 0
        change_prob[change_prob > 1 ] = 0
        change_prob[numpy.arange(change_prob.size)[numpy.array(1-nonCloudAddress2.reshape(-1,),dtype=bool)],:] = 0

        interBand = numpy.array(interBand1)
        #Create a rectangular array into which the parallelogram will be placed
        imageArrayFinal2 = numpy.zeros((polygon1[:,:,0].shape[0],polygon1[:,:,0].shape[1],3), dtype=numpy.float)
        for ij in numpy.arange(interBand.shape[0]):
            imageArrayFinal2[interBand[ij,0],interBand[ij,1],0] = 1 - change_prob[ij] #1
            imageArrayFinal2[interBand[ij,0],interBand[ij,1],1] = 1 - change_prob[ij] #1-.5*change_prob[ij]
            imageArrayFinal2[interBand[ij,0],interBand[ij,1],2] = 1 - change_prob[ij] #1-.75*change_prob[ij]

        imageArrayFinal2 = imageArrayFinal2 + polygon1[:,:,5].reshape(polygon1[:,:,0].shape[0],polygon1[:,:,0].shape[1],1)

        for i in numpy.arange(pR2.shape[0]):
            imageArrayFinal2[pR2[i],pC2[i],0:3] = 1

        geoPicture.bands.extend(["CHANGE_BAND"])
        geoPicture.picture = numpy.dstack((polygon1[:,:,6:],imageArrayFinal2))


    else:
        sys.stderr.write('These two images do not overlap.')
        imageArrayFinal2 = numpy.zeros((geoPicture.picture.shape[0],geoPicture.picture.shape[1],3), dtype=numpy.float)
        geoPicture.bands.extend(["CHANGE_BAND"])
        geoPicture.picture = imageArrayFinal2


    geoPictureOutput = GeoPictureSerializer.GeoPicture()
    geoPictureOutput.picture = geoPicture.picture
    geoPictureOutput.metadata = geoPicture.metadata
    geoPictureOutput.bands = geoPicture.bands

    return geoPictureOutput
Example #2
0
def main(trainingDirectory, landCoverList, band_list=[], band_weight_list=[]):

    # If bandList is empty, i.e., no band grouping list was input at command line. A default list, contained in FloodClassUtils.py,
    # will be used.
    # Note that if a "band_weight_list" is input, it should correspond with the band_list, and it should be known apriori that
    # all serialized files input to this code contain the required bands.

    if band_list == []:
        band_list = FloodClassUtils.bandList()

    landCoverTypesListLength = 10 ** 50
    landCoverTypes = {}

    flagTwo = True

    for landName in landCoverList:

        flagOne = True

        fileList = os.listdir(trainingDirectory + "/" + landName)
        for serialFile in fileList:

            # read in and deserialize
            geoPicture = GeoPictureSerializer.deserialize(open(trainingDirectory + "/" + landName + "/" + serialFile))

            # do radiance correction on bands
            geoPicture = FloodClassUtils.radianceCorrection(geoPicture)

            # find bands common to training set and requested set
            finalBandList, bandsPresent = FloodClassUtils.commonBand(geoPicture, band_list)

            # Combine bands
            geoPicture.picture = FloodClassUtils.bandSynth(geoPicture, finalBandList, band_weight_list)

            # The band list of common bands are added to the geoPicture to replace the original
            geoPicture.bands = bandsPresent

            missingBandList = []
            for i in numpy.arange(len(FloodClassUtils.bandList())):
                missingBandSet = set(FloodClassUtils.bandList()[i]) - set(finalBandList[i])
                missingBandList.append(list(missingBandSet))
            sys.stderr.write(
                "\nThe following requested bands are missing from serialized file "
                + str(serialFile)
                + ":\n"
                + str(missingBandList)
                + "\n"
            )

            # Need to create a mask of locations where all pixels are nonzero.
            alphaBand = geoPicture.picture[:, :, geoPicture.bands.index(geoPicture.bands[0])] > 0
            for band in geoPicture.bands[1:]:
                numpy.logical_and(alphaBand, geoPicture.picture[:, :, geoPicture.bands.index(band)], alphaBand)

            # Make bands into 2-d array
            # Find size of the image array
            rasterXsize = geoPicture.picture.shape[1]
            rasterYsize = geoPicture.picture.shape[0]
            rasterDepth = geoPicture.picture.shape[2]

            # Reshape all arrays
            geoPicture.picture = geoPicture.picture.reshape(rasterXsize * rasterYsize, rasterDepth)
            alphaBand = alphaBand.reshape(rasterXsize * rasterYsize)
            geoPicture.picture = geoPicture.picture[alphaBand, :]

            if flagOne == True:
                landCoverTypes[landName] = geoPicture.picture
                flagOne = False
            else:
                landCoverTypes[landName] = numpy.concatenate((landCoverTypes[landName], geoPicture.picture), axis=0)

        # Note that the classification digit is tied to the order of the landCoverList, i.e., classification digit = landCoverList_position + 1
        landCoverTypes[landName] = numpy.concatenate(
            (
                landCoverTypes[landName],
                (landCoverList.index(landName) + 1) * numpy.ones((landCoverTypes[landName].shape[0], 1), dtype=int),
            ),
            axis=1,
        )
        landCoverTypes[landName] = landCoverTypes[landName][
            numpy.random.permutation(landCoverTypes[landName].shape[0]), :
        ]
        landCoverTypesListLength = min(landCoverTypes[landName].shape[0], landCoverTypesListLength)

        if flagTwo == True:
            sampleLength = numpy.minimum(5000, landCoverTypesListLength)
            train = landCoverTypes[landName][:sampleLength, :]
            flagTwo = False
        else:
            train = numpy.concatenate((train, landCoverTypes[landName][:sampleLength, :]), axis=0)

    numpy.savetxt("trainingSet.txt", train, fmt=rasterDepth * "%-12.5f " + "%-d")