Пример #1
0
def packAndSendCameraFolder(run, logger):
    '''Archive the camera folder for later use'''
    
    logger.info('Archiving camera folder for run ' + str(run))

    # Tar up the camera files and send them at the same time using the shiftc command
    cameraFolder = run.getCameraFolder()
    fileName     = run.getCameraTarName()
    lfePath      = os.path.join(REMOTE_CAMERA_FOLDER, fileName)

    # First remove any existing tar file. Use 2>/dev/null to not print
    # NASA's "You have no expecation of privacy."
    cmd      = "ssh lfe 'rm -f " + stripHost(lfePath) + "' 2>/dev/null"
    logger.info(cmd)
    os.system(cmd)

    # Do the new file. Save the projection bounds, we will need that for later
    # as that file is very time consuming to create.
    cwd = os.getcwd()
    os.chdir(run.parentFolder)
    
    runFolder = str(run)
    cmd = 'shiftc --wait -d -r --include=\'^.*?(' + \
          os.path.basename(icebridge_common.projectionBoundsFile(runFolder)) + \
          '|' + icebridge_common.validFilesPrefix() + '.*|' + \
          os.path.basename(cameraFolder) + '.*?\.tsai)$\' --create-tar ' + runFolder + \
          ' ' + lfePath
    
    robust_shiftc(cmd, logger)

    logger.info("Finished archiving cameras.")
    
    os.chdir(cwd)
def getImageSpacing(orthoFolder, availableFrames, startFrame, stopFrame, forceAllFramesInRange):
    '''Find a good image stereo spacing interval that gives us a good
       balance between coverage and baseline width.
       Also detect all frames where this is a large break after the current frame.'''

    logger.info('Computing optimal image stereo interval...')

    ## With very few cameras this is the only possible way to process them
    #if len(availableFrames) < 3 and not forceAllFramesInRange:
    #    return ([], {}) # No skip, no breaks

    # Retrieve a list of the ortho files
    orthoIndexPath = icebridge_common.csvIndexFile(orthoFolder)
    if not os.path.exists(orthoIndexPath):
        raise Exception("Error: Missing ortho index file: " + orthoIndexPath + ".")
    (orthoFrameDict, orthoUrlDict) = icebridge_common.readIndexFile(orthoIndexPath,
                                                                    prependFolder = True)

    # From the dictionary create a sorted list of ortho files in the frame range
    breaks     = []
    largeSkips = {}
    orthoFiles = []
    for frame in sorted(orthoFrameDict.keys()):

        # Only process frames within the range
        if not ( (frame >= startFrame) and (frame <= stopFrame) ):
            continue

        orthoPath = orthoFrameDict[frame]
        frame     = icebridge_common.getFrameNumberFromFilename(orthoPath)
        
        if not forceAllFramesInRange:
            if frame not in availableFrames: # Skip frames we did not compute a camera for
                continue
        
        orthoFiles.append(orthoPath)
        
    orthoFiles.sort()
    numOrthos = len(orthoFiles)

    # First load whatever boxes are there
    projectionIndexFile = icebridge_common.projectionBoundsFile(os.path.dirname(orthoFolder))
    logger.info("Reading: " + projectionIndexFile)
    boundsDict = icebridge_common.readProjectionBounds(projectionIndexFile)
    
    # Get the bounding box and frame number of each ortho image
    logger.info('Loading bounding boxes...')
    frames = []
    updatedBounds = False # will be true if some computation got done
    count = 0
    for i in range(0, numOrthos):

        # This can be slow, so add a progress dialong
        count = count + 1
        if (count - 1) % 1000 == 0:
            logger.info('Progress: ' + str(count) + '/' + str(numOrthos))

        thisFrame    = icebridge_common.getFrameNumberFromFilename(orthoFiles[i])
        if thisFrame not in boundsDict:
            imageGeoInfo   = asp_geo_utils.getImageGeoInfo(orthoFiles[i], getStats=False)
            thisBox        = imageGeoInfo['projection_bounds']
            boundsDict[thisFrame] = thisBox
            updatedBounds = True
            
        frames.append(thisFrame)

    # Read this file again, in case some other process modified it in the meantime.
    # This won't happen in production mode, but can during testing with partial sequences.
    boundsDictRecent = icebridge_common.readProjectionBounds(projectionIndexFile)
    for frame in sorted(boundsDictRecent.keys()):
        if not frame in boundsDict.keys():
            boundsDict[frame] = boundsDictRecent[frame]
            updatedBounds = True

    # Save the bounds. There is always the danger that two processes will
    # do that at the same time, but this is rare, as hopefully we get here
    # only once from the manager. It is not a big loss if this file gets messed up.
    if updatedBounds:
        logger.info("Writing: " + projectionIndexFile)
        icebridge_common.writeProjectionBounds(projectionIndexFile, boundsDict)
        
    # Since we are only comparing the image bounding boxes, not their exact corners,
    #  these ratios are only estimates.
    MAX_RATIO   = 0.85    # Increase skip until we get below this...
    MIN_RATIO   = 0.75    # ... but don't go below this value!
    NOTRY_RATIO = 0.0001  # Don't bother with overlap amounts less than this (small on purpose)

    def getBboxArea(bbox):
        '''Return the area of a bounding box in form of (minX, maxX, minY, maxY)'''
        width  = bbox[1] - bbox[0]
        height = bbox[3] - bbox[2]
        if (width < 0) or (height < 0):
            return 0
        return width*height

    # Iterate over the frames and find the best stereo frame for each    
    for i in range(0, numOrthos-1):
    
        thisFrame = frames[i]
        thisBox   = boundsDict[thisFrame]
        thisArea  = getBboxArea(thisBox)
        interval  = 1
        
        while(True):
            
            # Compute intersection area between this and next image

            nextFrame = frames[i+interval]
            nextBox   = boundsDict[nextFrame]
            intersect = [max(thisBox[0], nextBox[0]), # Min X
                         min(thisBox[1], nextBox[1]), # Max X
                         max(thisBox[2], nextBox[2]), # Min Y
                         min(thisBox[3], nextBox[3])] # Max Y
            area      = getBboxArea(intersect)
            ratio = 0
            if area > 0:
                ratio = area / thisArea
            
            if interval == 1: # Cases for the smallest interval...
                if ratio < NOTRY_RATIO:
                    breaks.append(thisFrame) # No match for this frame
                    logger.info('Detected large break after frame ' + str(thisFrame))
                    break
                if ratio < MIN_RATIO:
                    break # No reason to try increasing skip amounts for this frame
            else: # interval > 1
                if ratio < MIN_RATIO: # Went too small, walk back the interval.
                    interval = interval - 1
                    break
                    
            if ratio > MAX_RATIO: # Too much overlap, increase interval
                interval = interval + 1
            else: # Overlap is fine, keep this interval.
                break

            # Handle the case where we go past the end of frames looking for a match.
            if i+interval >= len(frames):
                interval = interval - 1
                break
        
        if interval > 1: # Only record larger than normal intervals.
            largeSkips[thisFrame] = interval

    logger.info('Detected ' + str(len(breaks)) + ' breaks in image coverage.')
    logger.info('Detected ' + str(len(largeSkips)) + ' images with interval > 1.')

    return (breaks, largeSkips)