2015-11-26 12:15:02 +00:00
import os
2018-11-24 17:56:17 +00:00
import json
2015-11-26 12:15:02 +00:00
from opendm import context
from opendm import io
from opendm import types
from opendm import log
2016-12-09 14:51:25 +00:00
from opendm import system
2020-09-14 18:33:39 +00:00
from opendm . geo import GeoFile
2016-12-09 14:51:25 +00:00
from shutil import copyfile
2019-05-15 21:04:09 +00:00
from opendm import progress
2015-11-26 12:15:02 +00:00
2020-03-18 19:29:43 +00:00
2018-11-24 17:56:17 +00:00
def save_images_database ( photos , database_file ) :
with open ( database_file , ' w ' ) as f :
2020-09-09 17:23:53 +00:00
f . write ( json . dumps ( [ p . __dict__ for p in photos ] ) )
2018-11-24 17:56:17 +00:00
log . ODM_INFO ( " Wrote images database: %s " % database_file )
def load_images_database ( database_file ) :
2018-11-24 18:00:22 +00:00
# Empty is used to create types.ODM_Photo class
# instances without calling __init__
2018-11-24 17:56:17 +00:00
class Empty :
pass
result = [ ]
log . ODM_INFO ( " Loading images database: %s " % database_file )
with open ( database_file , ' r ' ) as f :
photos_json = json . load ( f )
for photo_json in photos_json :
p = Empty ( )
for k in photo_json :
setattr ( p , k , photo_json [ k ] )
p . __class__ = types . ODM_Photo
result . append ( p )
return result
2016-09-30 09:42:10 +00:00
2019-04-22 19:14:39 +00:00
class ODMLoadDatasetStage ( types . ODM_Stage ) :
def process ( self , args , outputs ) :
2021-01-11 19:41:54 +00:00
outputs [ ' start_time ' ] = system . now_raw ( )
2020-09-14 18:33:39 +00:00
tree = types . ODM_Tree ( args . project_path , args . gcp , args . geo )
2019-04-22 19:14:39 +00:00
outputs [ ' tree ' ] = tree
if args . time and io . file_exists ( tree . benchmarking ) :
# Delete the previously made file
os . remove ( tree . benchmarking )
with open ( tree . benchmarking , ' a ' ) as b :
b . write ( ' ODM Benchmarking file created %s \n Number of Cores: %s \n \n ' % ( system . now ( ) , context . num_cores ) )
2020-09-15 17:57:36 +00:00
# check if the image filename is supported
def valid_image_filename ( filename ) :
( pathfn , ext ) = os . path . splitext ( filename )
return ext . lower ( ) in context . supported_extensions and pathfn [ - 5 : ] != " _mask "
2015-11-26 12:15:02 +00:00
2016-12-09 14:51:25 +00:00
# Get supported images from dir
def get_images ( in_dir ) :
log . ODM_DEBUG ( in_dir )
2020-09-16 13:18:12 +00:00
entries = os . listdir ( in_dir )
valid , rejects = [ ] , [ ]
for f in entries :
if valid_image_filename ( f ) :
valid . append ( f )
else :
rejects . append ( f )
return valid , rejects
def find_mask ( photo_path , masks ) :
( pathfn , ext ) = os . path . splitext ( os . path . basename ( photo_path ) )
k = " {} _mask " . format ( pathfn )
mask = masks . get ( k )
if mask :
# Spaces are not supported due to OpenSfM's mask_list.txt format reqs
if not " " in mask :
return mask
else :
log . ODM_WARNING ( " Image mask {} has a space. Spaces are currently not supported for image masks. " . format ( mask ) )
2016-12-09 14:51:25 +00:00
# get images directory
images_dir = tree . dataset_raw
2017-08-24 19:19:51 +00:00
2018-03-03 16:48:43 +00:00
# define paths and create working directories
system . mkdir_p ( tree . odm_georeferencing )
2019-06-28 15:10:08 +00:00
log . ODM_INFO ( ' Loading dataset from: %s ' % images_dir )
2015-11-26 12:15:02 +00:00
2018-11-24 17:56:17 +00:00
# check if we rerun cell or not
2020-10-28 14:05:01 +00:00
images_database_file = os . path . join ( tree . root_path , ' images.json ' )
2019-04-22 19:14:39 +00:00
if not io . file_exists ( images_database_file ) or self . rerun ( ) :
2021-04-30 19:45:48 +00:00
if not os . path . exists ( images_dir ) :
2021-06-09 15:46:56 +00:00
raise system . ExitException ( " There are no images in %s ! Make sure that your project path and dataset name is correct. The current is set to: %s " % ( images_dir , args . project_path ) )
2021-04-30 19:45:48 +00:00
2020-09-16 13:18:12 +00:00
files , rejects = get_images ( images_dir )
2018-11-24 17:56:17 +00:00
if files :
# create ODMPhoto list
2020-10-28 14:05:01 +00:00
path_files = [ os . path . join ( images_dir , f ) for f in files ]
2018-11-24 17:56:17 +00:00
2020-09-16 13:18:12 +00:00
# Lookup table for masks
masks = { }
for r in rejects :
( p , ext ) = os . path . splitext ( r )
2020-09-16 13:56:07 +00:00
if p [ - 5 : ] == " _mask " and ext . lower ( ) in context . supported_extensions :
2020-09-16 13:18:12 +00:00
masks [ p ] = r
2018-11-24 17:56:17 +00:00
photos = [ ]
with open ( tree . dataset_list , ' w ' ) as dataset_list :
2019-06-28 15:10:08 +00:00
log . ODM_INFO ( " Loading %s images " % len ( path_files ) )
2019-03-07 17:36:05 +00:00
for f in path_files :
2020-09-16 13:18:12 +00:00
p = types . ODM_Photo ( f )
p . set_mask ( find_mask ( f , masks ) )
photos + = [ p ]
2018-11-24 17:56:17 +00:00
dataset_list . write ( photos [ - 1 ] . filename + ' \n ' )
2020-10-28 18:13:34 +00:00
2020-09-14 18:33:39 +00:00
# Check if a geo file is available
2020-09-14 20:09:26 +00:00
if tree . odm_geo_file is not None and os . path . exists ( tree . odm_geo_file ) :
2020-09-14 18:33:39 +00:00
log . ODM_INFO ( " Found image geolocation file " )
gf = GeoFile ( tree . odm_geo_file )
updated = 0
for p in photos :
entry = gf . get_entry ( p . filename )
if entry :
p . update_with_geo_entry ( entry )
updated + = 1
log . ODM_INFO ( " Updated %s image positions " % updated )
2018-11-24 17:56:17 +00:00
# Save image database for faster restart
save_images_database ( photos , images_database_file )
else :
2021-06-09 15:46:56 +00:00
raise system . ExitException ( ' Not enough supported images in %s ' % images_dir )
2015-11-27 16:50:09 +00:00
else :
2018-11-24 17:56:17 +00:00
# We have an images database, just load it
photos = load_images_database ( images_database_file )
log . ODM_INFO ( ' Found %s usable images ' % len ( photos ) )
2021-06-09 15:46:56 +00:00
log . logger . log_json_images ( len ( photos ) )
2015-11-26 12:15:02 +00:00
2019-06-20 19:39:49 +00:00
# Create reconstruction object
reconstruction = types . ODM_Reconstruction ( photos )
2019-06-21 18:47:00 +00:00
2019-07-02 19:40:20 +00:00
if tree . odm_georeferencing_gcp and not args . use_exif :
2019-06-21 18:47:00 +00:00
reconstruction . georeference_with_gcp ( tree . odm_georeferencing_gcp ,
tree . odm_georeferencing_coords ,
tree . odm_georeferencing_gcp_utm ,
2021-02-24 20:11:16 +00:00
tree . odm_georeferencing_model_txt_geo ,
2019-06-21 18:47:00 +00:00
rerun = self . rerun ( ) )
2018-01-26 19:38:26 +00:00
else :
2019-06-21 18:47:00 +00:00
reconstruction . georeference_with_gps ( tree . dataset_raw ,
tree . odm_georeferencing_coords ,
2021-02-24 20:11:16 +00:00
tree . odm_georeferencing_model_txt_geo ,
2019-06-21 18:47:00 +00:00
rerun = self . rerun ( ) )
2021-02-24 20:11:16 +00:00
2020-10-28 14:05:01 +00:00
reconstruction . save_proj_srs ( os . path . join ( tree . odm_georeferencing , tree . odm_georeferencing_proj ) )
2019-06-20 19:39:49 +00:00
outputs [ ' reconstruction ' ] = reconstruction