parameters: (options, imageFolder, cameraFolder, lidarFolder, orthoFolder,
                           processedFolder, isSouth, logger)
docstring: Create a camera model with optimized intrinsics. By now we
      processed a bunch of images and created bundle-adjusted and
      pc_aligned cameras and DEMs while using a camera model with
      distortion implemented using RPC coefficients which was obtained
      from the photometrics model. We now use the obtained cameras as
      inputs to a bundle adjust problem where we will optimize the
      intrinsics, including the distortion RPC coefficients, using the
      lidar as an external constraint, and many dense IP pairs and
      triplets (no quadruplets yet, even if 4 images overlap).
docstring_summary: Create a camera model with optimized intrinsics. By now we
      processed a bunch of images and created bundle-adjusted and
      pc_aligned cameras and DEMs while using a camera model with
      distortion implemented using RPC coefficients which was obtained
      from the photometrics model. We now use the obtained cameras as
      inputs to a bundle adjust problem where we will optimize the
      intrinsics, including the distortion RPC coefficients, using the
      lidar as an external constraint, and many dense IP pairs and
      triplets (no quadruplets yet, even if 4 images overlap).
docstring_tokens: Create a camera model with optimized intrinsics . By now we processed a bunch of images and created bundle - adjusted and pc_aligned cameras and DEMs while using a camera model with distortion implemented using RPC coefficients which was obtained from the photometrics model . We now use the obtained cameras as inputs to a bundle adjust problem where we will optimize the intrinsics including the distortion RPC coefficients using the lidar as an external constraint and many dense IP pairs and triplets ( no quadruplets yet even if 4 images overlap ) .
function: def solveIntrinsics_Part2(options, imageFolder, cameraFolder, lidarFolder, orthoFolder,
                           processedFolder, isSouth, logger):
      
      '''Create a camera model with optimized intrinsics. By now we
      processed a bunch of images and created bundle-adjusted and
      pc_aligned cameras and DEMs while using a camera model with
      distortion implemented using RPC coefficients which was obtained
      from the photometrics model. We now use the obtained cameras as
      inputs to a bundle adjust problem where we will optimize the
      intrinsics, including the distortion RPC coefficients, using the
      lidar as an external constraint, and many dense IP pairs and
      triplets (no quadruplets yet, even if 4 images overlap).'''
  
      # Get a list of all the input files
      imageCameraPairs = icebridge_common.getImageCameraPairs(imageFolder, cameraFolder, 
                                                              options.startFrame, options.stopFrame,
                                                              logger)
      
      # The paired lidar file for the first image should be huge enough to contain
      # all images.
      lidarFile = icebridge_common.findMatchingLidarFile(imageCameraPairs[0][0], lidarFolder)
      logger.info('Found matching lidar file ' + lidarFile)
      lidarCsvFormatString = icebridge_common.getLidarCsvFormat(lidarFile)
  
      numFiles = len(imageCameraPairs)
      if numFiles < 2:
          raise Exception('Failed to find any image camera pairs!')
      if numFiles % 2 != 0:
          raise Exception("When solving for intrinsics, must have an even number of frames to use.")
  
  
      # Collect pc_align-ed cameras, unaligned disparities, and dense match files
      images = []
      cameras = []
      for it in range(numFiles/2):
          begFrame = options.startFrame + 2*it
          endFrame = begFrame + 1
          batchFolderName  = icebridge_common.batchFolderName(begFrame, endFrame, options.bundleLength)
          thisOutputFolder = os.path.join(processedFolder, batchFolderName)
          
          # Find all the cameras after bundle adjustment and pc_align.
          pattern = icebridge_common.getAlignedBundlePrefix(thisOutputFolder) + '*.tsai'
          alignedCameras = glob.glob(pattern)
          if len(alignedCameras) != options.bundleLength:
              raise Exception("Expected " + str(options.bundleLength) + " cameras, here's what " +
                              " was obtained instead: " + " ".join(alignedCameras))
          img0 = ""; cam0 = ""; img1 = ""; cam1 = ""
          for cam in alignedCameras:
              frame = icebridge_common.getFrameNumberFromFilename(cam)
              if begFrame == frame:
                  img0 = imageCameraPairs[2*it][0]
                  cam0 = cam
              if endFrame == frame:
                  img1 = imageCameraPairs[2*it+1][0]
                  cam1 = cam
          images.append(img0);  images.append(img1)
          cameras.append(cam0); cameras.append(cam1)
  
      # Match files and disp files
      dispFiles = []
      matchFiles = []
      for it in range(numFiles-1):
          begFrame = options.startFrame + it
          endFrame = begFrame + 1
          batchFolderName  = icebridge_common.batchFolderName(begFrame, endFrame, options.bundleLength)
          thisOutputFolder = os.path.join(processedFolder, batchFolderName)
          stereoFolder = os.path.join(thisOutputFolder, 'stereo_pair_'+str(0))
          DISP_PREFIX = "disp-"
          currMatchFiles = glob.glob(os.path.join(stereoFolder, '*' + DISP_PREFIX + '*.match'))
          if len(currMatchFiles) != 1:
              raise Exception("Expecting a single dense match file in " + stereoFolder)
          matchFiles.append(currMatchFiles[0])
  
          currDispFiles = glob.glob(os.path.join(stereoFolder, '*unaligned-D.tif'))
          if len(currDispFiles) != 1:
              raise Exception("Expecting a single unaligned disparity file in " + stereoFolder)
          dispFiles.append(currDispFiles[0])
  
      # Create output directory for bundle adjustment and copy there the match files
      baDir = os.path.join(processedFolder, "bundle_intrinsics")
      baPrefix = os.path.join(baDir, "out")
      os.system("mkdir -p " + baDir)
      for matchFile in matchFiles:
          dstFile = os.path.basename(matchFile)
          dstFile = dstFile.replace(DISP_PREFIX, '')
          dstFile = os.path.join(baDir, dstFile)
          cmd = "cp -f " + matchFile + " " + dstFile
          logger.info(cmd)
          os.system(cmd)
  
      # The bundle adjustment
      solveIntr = ""
      if not options.skipSolvingIntrinsics:
          solveIntr = " --solve-intrinsics "
          
      cmd = "bundle_adjust " + " ".join(images) + " " +  " ".join(cameras) + \
              ' --reference-terrain ' + lidarFile + \
              ' --disparity-list "' + " ".join(dispFiles) + '"' + \
              ' --datum wgs84 -t nadirpinhole --inline-adjustments --robust-threshold 2' + \
              ' --camera-weight 0  --csv-format ' + lidarCsvFormatString + \
              ' --overlap-limit 1 --max-disp-error 50 --max-iterations 100 ' + \
              solveIntr + ' --parameter-tolerance 1e-12 -o ' + baPrefix
      logger.info(cmd)
      os.system(cmd)
  
      # Generate DEMs of residuals before and after optimization
      projString = icebridge_common.getEpsgCode(isSouth, asString=True)
      for val in ['initial', 'final']:
          cmd = 'point2dem --t_srs ' + projString + ' --tr 2'    + \
                ' --csv-format 1:lon,2:lat,4:height_above_datum' + \
                ' ' + baPrefix + '-' + val + '_residuals_.csv'
          logger.info(cmd)
          os.system(cmd)
          cmd = 'point2dem --t_srs ' + projString + ' --tr 2'    + \
                ' --csv-format 1:lon,2:lat,4:height_above_datum' + \
                ' ' + baPrefix + '-' + val +'_residuals_reference_terrain.txt'
          logger.info(cmd)
          os.system(cmd)
  
      # Look at the latest written tsai file, that will be the optimized distortion file.
      # Force the initial rotation and translation to be the identity, this is
      # expected by ortho2pinhole.
      outFiles = filter(os.path.isfile, glob.glob(baPrefix + '*.tsai'))
      outFiles.sort(key=lambda x: os.path.getmtime(x))
      optFile = outFiles[-1]
      logger.info("Reading optimized file: " + optFile)
      with open(optFile, 'r') as f:
          lines = f.readlines()
      for it in range(len(lines)):
          lines[it] = lines[it].strip()
          if re.match("^C\s*=\s*", lines[it]):
              lines[it] = "C = 0 0 0"
          if re.match("^R\s*=\s*", lines[it]):
              lines[it] = "R = 1 0 0 0 1 0 0 0 1"
  
      # Write the final desired optimized RPC file
      logger.info("Writing final optimized file: " + options.outputCalCamera)
      # Below is a bugfix, must take full path to find the dir, otherwise it may fail.
      os.system("mkdir -p " + os.path.dirname(os.path.abspath(options.outputCalCamera)))
      with open(options.outputCalCamera, 'w') as f:
          for line in lines:
              f.write(line + "\n")
function_tokens: def solveIntrinsics_Part2 ( options , imageFolder , cameraFolder , lidarFolder , orthoFolder , processedFolder , isSouth , logger ) : # Get a list of all the input files imageCameraPairs = icebridge_common . getImageCameraPairs ( imageFolder , cameraFolder , options . startFrame , options . stopFrame , logger ) # The paired lidar file for the first image should be huge enough to contain # all images. lidarFile = icebridge_common . findMatchingLidarFile ( imageCameraPairs [ 0 ] [ 0 ] , lidarFolder ) logger . info ( 'Found matching lidar file ' + lidarFile ) lidarCsvFormatString = icebridge_common . getLidarCsvFormat ( lidarFile ) numFiles = len ( imageCameraPairs ) if numFiles < 2 : raise Exception ( 'Failed to find any image camera pairs!' ) if numFiles % 2 != 0 : raise Exception ( "When solving for intrinsics, must have an even number of frames to use." ) # Collect pc_align-ed cameras, unaligned disparities, and dense match files images = [ ] cameras = [ ] for it in range ( numFiles / 2 ) : begFrame = options . startFrame + 2 * it endFrame = begFrame + 1 batchFolderName = icebridge_common . batchFolderName ( begFrame , endFrame , options . bundleLength ) thisOutputFolder = os . path . join ( processedFolder , batchFolderName ) # Find all the cameras after bundle adjustment and pc_align. pattern = icebridge_common . getAlignedBundlePrefix ( thisOutputFolder ) + '*.tsai' alignedCameras = glob . glob ( pattern ) if len ( alignedCameras ) != options . bundleLength : raise Exception ( "Expected " + str ( options . bundleLength ) + " cameras, here's what " + " was obtained instead: " + " " . join ( alignedCameras ) ) img0 = "" cam0 = "" img1 = "" cam1 = "" for cam in alignedCameras : frame = icebridge_common . getFrameNumberFromFilename ( cam ) if begFrame == frame : img0 = imageCameraPairs [ 2 * it ] [ 0 ] cam0 = cam if endFrame == frame : img1 = imageCameraPairs [ 2 * it + 1 ] [ 0 ] cam1 = cam images . append ( img0 ) images . append ( img1 ) cameras . append ( cam0 ) cameras . append ( cam1 ) # Match files and disp files dispFiles = [ ] matchFiles = [ ] for it in range ( numFiles - 1 ) : begFrame = options . startFrame + it endFrame = begFrame + 1 batchFolderName = icebridge_common . batchFolderName ( begFrame , endFrame , options . bundleLength ) thisOutputFolder = os . path . join ( processedFolder , batchFolderName ) stereoFolder = os . path . join ( thisOutputFolder , 'stereo_pair_' + str ( 0 ) ) DISP_PREFIX = "disp-" currMatchFiles = glob . glob ( os . path . join ( stereoFolder , '*' + DISP_PREFIX + '*.match' ) ) if len ( currMatchFiles ) != 1 : raise Exception ( "Expecting a single dense match file in " + stereoFolder ) matchFiles . append ( currMatchFiles [ 0 ] ) currDispFiles = glob . glob ( os . path . join ( stereoFolder , '*unaligned-D.tif' ) ) if len ( currDispFiles ) != 1 : raise Exception ( "Expecting a single unaligned disparity file in " + stereoFolder ) dispFiles . append ( currDispFiles [ 0 ] ) # Create output directory for bundle adjustment and copy there the match files baDir = os . path . join ( processedFolder , "bundle_intrinsics" ) baPrefix = os . path . join ( baDir , "out" ) os . system ( "mkdir -p " + baDir ) for matchFile in matchFiles : dstFile = os . path . basename ( matchFile ) dstFile = dstFile . replace ( DISP_PREFIX , '' ) dstFile = os . path . join ( baDir , dstFile ) cmd = "cp -f " + matchFile + " " + dstFile logger . info ( cmd ) os . system ( cmd ) # The bundle adjustment solveIntr = "" if not options . skipSolvingIntrinsics : solveIntr = " --solve-intrinsics " cmd = "bundle_adjust " + " " . join ( images ) + " " + " " . join ( cameras ) + ' --reference-terrain ' + lidarFile + ' --disparity-list "' + " " . join ( dispFiles ) + '"' + ' --datum wgs84 -t nadirpinhole --inline-adjustments --robust-threshold 2' + ' --camera-weight 0  --csv-format ' + lidarCsvFormatString + ' --overlap-limit 1 --max-disp-error 50 --max-iterations 100 ' + solveIntr + ' --parameter-tolerance 1e-12 -o ' + baPrefix logger . info ( cmd ) os . system ( cmd ) # Generate DEMs of residuals before and after optimization projString = icebridge_common . getEpsgCode ( isSouth , asString = True ) for val in [ 'initial' , 'final' ] : cmd = 'point2dem --t_srs ' + projString + ' --tr 2' + ' --csv-format 1:lon,2:lat,4:height_above_datum' + ' ' + baPrefix + '-' + val + '_residuals_.csv' logger . info ( cmd ) os . system ( cmd ) cmd = 'point2dem --t_srs ' + projString + ' --tr 2' + ' --csv-format 1:lon,2:lat,4:height_above_datum' + ' ' + baPrefix + '-' + val + '_residuals_reference_terrain.txt' logger . info ( cmd ) os . system ( cmd ) # Look at the latest written tsai file, that will be the optimized distortion file. # Force the initial rotation and translation to be the identity, this is # expected by ortho2pinhole. outFiles = filter ( os . path . isfile , glob . glob ( baPrefix + '*.tsai' ) ) outFiles . sort ( key = lambda x : os . path . getmtime ( x ) ) optFile = outFiles [ - 1 ] logger . info ( "Reading optimized file: " + optFile ) with open ( optFile , 'r' ) as f : lines = f . readlines ( ) for it in range ( len ( lines ) ) : lines [ it ] = lines [ it ] . strip ( ) if re . match ( "^C\s*=\s*" , lines [ it ] ) : lines [ it ] = "C = 0 0 0" if re . match ( "^R\s*=\s*" , lines [ it ] ) : lines [ it ] = "R = 1 0 0 0 1 0 0 0 1" # Write the final desired optimized RPC file logger . info ( "Writing final optimized file: " + options . outputCalCamera ) # Below is a bugfix, must take full path to find the dir, otherwise it may fail. os . system ( "mkdir -p " + os . path . dirname ( os . path . abspath ( options . outputCalCamera ) ) ) with open ( options . outputCalCamera , 'w' ) as f : for line in lines : f . write ( line + "\n" )