def matchLocally(mission, roll, frame, cursor, georefDb, sourceImagePath):
    '''Performs image alignment to an already aligned ISS image'''

    # Load new frame info
    targetFrameData = source_database.FrameInfo()
    targetFrameData.loadFromDb(cursor, mission, roll, frame)
    targetFrameData = computeFrameInfoMetersPerPixel(targetFrameData)

    # Find candidate names to match to
    possibleNearbyMatches = findNearbyResults(targetFrameData, cursor, georefDb)
        
    if not possibleNearbyMatches:
        print 'Did not find any potential local matches!'
    
    for (otherFrame, ourResult) in possibleNearbyMatches:

        print 'Trying local match with frame: ' + str(otherFrame.frame)
        
        # Get path to other frame image
        otherImagePath, exifSourcePath = source_database.getSourceImage(otherFrame)
        source_database.clearExif(exifSourcePath)
        otherTransform = ourResult[0] # This is still in the google projected format
        
        #print 'otherTransform = ' + str(otherTransform.matrix)
        
        print 'New image mpp = ' + str(targetFrameData.metersPerPixel)
        print 'Local match image mpp = ' + str(otherFrame.metersPerPixel)
        # If we could not estimate the MPP value of the new image, guess that it is the same as
        #  the local reference image we are about to try.
        thisMpp = targetFrameData.metersPerPixel
        if not thisMpp:
            thisMpp = otherFrame.metersPerPixel
        
        print 'Attempting to register image...'
        (imageToProjectedTransform, imageToGdcTransform, confidence, imageInliers, gdcInliers, refMetersPerPixel) = \
            register_image.register_image(sourceImagePath,
                                          otherFrame.centerLon, otherFrame.centerLat,
                                          thisMpp, targetFrameData.date,
                                          refImagePath         =otherImagePath,
                                          referenceGeoTransform=otherTransform,
                                          refMetersPerPixelIn  =otherFrame.metersPerPixel,
                                          debug=options.debug, force=True, slowMethod=False)       
        if not options.debug:
            os.remove(otherImagePath) # Clean up the image we matched against

        # Quit once we get a good match
        if confidence == registration_common.CONFIDENCE_HIGH:
            print 'High confidence match!'
            # Convert from the image-to-image GCPs to the reference image GCPs
            #  located in the new image.
            refFrameGdcInliers = ourResult[3] # TODO: Clean this up!
            (width, height)    = IrgGeoFunctions.getImageSize(sourceImagePath)
            
            print '\n\n'
            print refFrameGdcInliers
            print '\n\n'
            
            (imageInliers, gdcInliers) = registration_common.convertGcps(refFrameGdcInliers,
                                                imageToProjectedTransform, width, height)
            
            print imageInliers
            print '\n\n'
            
            # If none of the original GCPs fall in the new image, don't use this alignment result.
            # - We could use this result, but we don't in order to maintain accuracy standards.
            if imageInliers:
                print 'Have inliers'
                print otherFrame
                return (imageToProjectedTransform, imageToGdcTransform, confidence,
                        imageInliers, gdcInliers, refMetersPerPixel, otherFrame)
            else:
                print 'Inliers out of bounds!'

    # Match failure, return junk values
    return (registration_common.getIdentityTransform(), registration_common.getIdentityTransform(),
            registration_common.CONFIDENCE_NONE, [], [], 9999, None)
def register_image(imagePath, centerLon, centerLat, metersPerPixel, imageDate,
                   refImagePath=None, referenceGeoTransform=None, refMetersPerPixelIn=None,
                   debug=False, force=False, slowMethod=False):
    '''Attempts to geo-register the provided image.
       Returns a transform from image coordinates to projected meters coordinates.
       Also returns an evaluation of how likely the registration is to be correct.'''

    if not (os.path.exists(imagePath)):
        raise Exception('Input image path does not exist!')

    with TemporaryDirectory() as myWorkDir:

        # Set up paths in a temporary directory
        if not debug:
            workDir = myWorkDir
        else: # In debug mode, create a more permanent work location.
            workDir = os.path.splitext(imagePath)[0]
        if not os.path.exists(workDir):
            os.mkdir(workDir)
        workPrefix = workDir + '/work'
        
        #print workDir
        
        if not refImagePath:
            # Fetch the reference image
            refImagePath    = os.path.join(workDir, 'ref_image.tif')
            refImageLogPath = os.path.join(workDir, 'ref_image_info.tif')
            if not os.path.exists(refImagePath):
                (percentValid, refMetersPerPixel) = ImageFetcher.fetchReferenceImage.fetchReferenceImage(
                                                        centerLon, centerLat,
                                                        metersPerPixel, imageDate, refImagePath)
                # Log the metadata
                handle = open(refImageLogPath, 'w')
                handle.write(str(percentValid) + '\n' + str(refMetersPerPixel))
                handle.close()
            else:
                # Load the reference image metadata that we logged earlier
                handle   = open(refImageLogPath, 'r')
                fileText = handle.read()
                handle.close()
                lines = fileText.split('\n')
                percentValid      = float(lines[0])
                refMetersPerPixel = float(lines[1])
        else: # The user provided a reference image
            refMetersPerPixel = refMetersPerPixelIn # In this case the user must provide an accurate value!
    
            if not os.path.exists(refImagePath):
                raise Exception('Provided reference image path does not exist!')
    
        # TODO: Reduce the input image to the resolution of the reference image!
        # The reference image may be lower resolution than the input image, in which case
        #  we will need to perform image alignment at the lower reference resolution.
        inputScaling = metersPerPixel / refMetersPerPixel
    
        print 'metersPerPixel    = ' + str(metersPerPixel)
        print 'refMetersPerPixel = ' + str(refMetersPerPixel)
        print 'inputScaling      = ' + str(inputScaling)
    
        # Try to align to the reference image
        # - The transform is from image to refImage
        (imageToRefImageTransform, confidence, imageInliers, refInliers) = \
                registration_common.alignScaledImages(imagePath, refImagePath, inputScaling, workPrefix, force, debug, slowMethod)
    
        # If we failed, just return dummy information with zero confidence.
        if (confidence == registration_common.CONFIDENCE_NONE):
            return (registration_common.getIdentityTransform(),
                    registration_common.getIdentityTransform(),
                    registration_common.CONFIDENCE_NONE, [], [], 0)
    
        # Convert the transform into a pixel-->Projected coordinate transform
        (imageToProjectedTransform, imageToGdcTransform, refImageToGdcTransform) = \
                convertTransformToGeo(imageToRefImageTransform, imagePath, refImagePath, referenceGeoTransform)
    
        # For each input image inlier, generate the world coordinate.
        
        gdcInliers = []
        for pix in refInliers:
            gdcCoordinate = refImageToGdcTransform.forward(pix)
            gdcInliers.append(gdcCoordinate)
    
        return (imageToProjectedTransform, imageToGdcTransform,
                confidence, imageInliers, gdcInliers, refMetersPerPixel)
def processFrame(options, frameDbData, searchNearby=False):
    '''Process a single specified frame.
       Returns True if we attempted to perform image alignment and did not hit an exception.'''
    try:
        georefDb = georefDbWrapper.DatabaseLogger()
        # Increase the error slightly for chained image transforms
        LOCAL_TRANSFORM_ERROR_ADJUST = 1.10
        sourceImagePath, exifSourcePath = source_database.getSourceImage(frameDbData, overwrite=True)
        if not options.debug:
            source_database.clearExif(exifSourcePath)
        try:
            # If requested, get nearby previously matched frames to compare to.
            if searchNearby:
                sourceDb = sqlite3.connect(settings.DB_PATH)
                sourceDbCursor = sourceDb.cursor()
                
                (imageToProjectedTransform, imageToGdcTransform, confidence, imageInliers, gdcInliers, refMetersPerPixel, otherFrame) = \
                    matchLocally(frameDbData.mission, frameDbData.roll, frameDbData.frame, sourceDbCursor, georefDb, sourceImagePath)
                if otherFrame:
                    matchedImageId = otherFrame.getIdString()
                else:
                    matchedImageId = 'None'
                sourceDb.close()
            else: # Try to register the image to Landsat
                print 'Attempting to register image...'
                (imageToProjectedTransform, imageToGdcTransform, confidence, imageInliers, gdcInliers, refMetersPerPixel) = \
                    register_image.register_image(sourceImagePath,
                                                  frameDbData.centerLon, frameDbData.centerLat,
                                                  frameDbData.metersPerPixel, frameDbData.date,
                                                  refImagePath=None,
                                                  debug=False, force=True, slowMethod=True)
                matchedImageId = 'Landsat'
        except Exception as e:
            print 'Computing transform for frame '+frameDbData.getIdString()+', caught exception: ' + str(e)
            print "".join(traceback.format_exception(*sys.exc_info()))
            print 'Logging the result as no-confidence.'
            confidence   = registration_common.CONFIDENCE_NONE
            imageInliers = []
            gdcInliers   = []
            matchedImageId    = 'NA'
            refMetersPerPixel = 999
            imageToProjectedTransform = registration_common.getIdentityTransform()
            imageToGdcTransform       = registration_common.getIdentityTransform()

        # A very rough estimation of localization error at the inlier locations!
        errorMeters = refMetersPerPixel * 1.5
        # Convert into format that our DB is looking for.
        sourceDateTime = frameDbData.getMySqlDateTime()
        if confidence > registration_common.CONFIDENCE_NONE:
            (centerLon, centerLat) = computeCenterGdcCoord(imageToGdcTransform, frameDbData)
        else:
            (centerLon, centerLat) = (-999, -999)
        # Log the results to our database
        centerPointSource = frameDbData.centerPointSource 
        georefDb.addResult(frameDbData.mission, frameDbData.roll, frameDbData.frame,
                           imageToProjectedTransform, imageToGdcTransform,
                           centerLon, centerLat, refMetersPerPixel,
                           confidence, imageInliers, gdcInliers,
                           matchedImageId, sourceDateTime, centerPointSource)
        # This tool just finds the interest points and computes the transform,
        # a different tool will actually write the output images.
        if not options.debug:
            os.remove(sourceImagePath) # Clean up the source image
        print ('Finished processing frame ' + frameDbData.getIdString()
               + ' with confidence ' + registration_common.CONFIDENCE_STRINGS[confidence])
        return confidence
    
    except Exception as e:
        print 'Processing frame '+frameDbData.getIdString()+', caught exception: ' + str(e)
        print "".join(traceback.format_exception(*sys.exc_info()))
        #raise Exception('FAIL')
        return 0