kopia lustrzana https://github.com/OpenDroneMap/ODM
rodzic
e6e62aae36
commit
3b4bcb09e4
tests
|
@ -0,0 +1,72 @@
|
|||
import os, json
|
||||
from opendm import log
|
||||
|
||||
def get_cameras_from_opensfm(reconstruction_file):
|
||||
"""
|
||||
Extract the cameras from OpenSfM's reconstruction.json
|
||||
"""
|
||||
if os.path.exists(reconstruction_file):
|
||||
with open(reconstruction_file, 'r') as fin:
|
||||
reconstructions = json.loads(fin.read())
|
||||
|
||||
result = {}
|
||||
for recon in reconstructions:
|
||||
if 'cameras' in recon:
|
||||
for camera_id in recon['cameras']:
|
||||
# Strip "v2" from OpenSfM camera IDs
|
||||
new_camera_id = camera_id
|
||||
if new_camera_id.startswith("v2 "):
|
||||
new_camera_id = new_camera_id[3:]
|
||||
|
||||
result[new_camera_id] = recon['cameras'][camera_id]
|
||||
|
||||
# Remove "_prior" keys
|
||||
keys = list(result[new_camera_id].keys())
|
||||
for k in keys:
|
||||
if k.endswith('_prior'):
|
||||
result[new_camera_id].pop(k)
|
||||
return result
|
||||
else:
|
||||
raise RuntimeError("%s does not exist." % reconstruction_file)
|
||||
|
||||
|
||||
def get_opensfm_camera_models(cameras):
|
||||
"""
|
||||
Convert cameras to a format OpenSfM can understand
|
||||
(opposite of get_cameras_from_opensfm)
|
||||
"""
|
||||
if isinstance(cameras, dict):
|
||||
result = {}
|
||||
for camera_id in cameras:
|
||||
# Quick check on IDs
|
||||
if len(camera_id.split(" ")) < 6:
|
||||
raise RuntimeError("Invalid cameraID: %s" % camera_id)
|
||||
|
||||
# Add "v2" to camera ID
|
||||
if not camera_id.startswith("v2 "):
|
||||
osfm_camera_id = "v2 " + camera_id
|
||||
else:
|
||||
osfm_camera_id = camera_id
|
||||
|
||||
# Add "_prior" keys
|
||||
camera = cameras[camera_id]
|
||||
prior_fields = ["focal","focal_x","focal_y","c_x","c_y","k1","k2","p1","p2","k3"]
|
||||
valid_fields = ["id","width","height","projection_type"] + prior_fields + [f + "_prior" for f in prior_fields]
|
||||
|
||||
keys = list(camera.keys())
|
||||
for param in keys:
|
||||
param_prior = param + "_prior"
|
||||
if param in prior_fields and not param_prior in camera:
|
||||
camera[param_prior] = camera[param]
|
||||
|
||||
# Remove invalid keys
|
||||
keys = list(camera.keys())
|
||||
for k in keys:
|
||||
if not k in valid_fields:
|
||||
camera.pop(k)
|
||||
log.ODM_WARNING("Invalid camera key ignored: %s" % k)
|
||||
|
||||
result[osfm_camera_id] = camera
|
||||
return result
|
||||
else:
|
||||
raise RuntimeError("Invalid cameras format: %s. Expected dict." % str(cameras))
|
|
@ -1,4 +1,5 @@
|
|||
import argparse
|
||||
import json
|
||||
from opendm import context
|
||||
from opendm import io
|
||||
from opendm import log
|
||||
|
@ -23,6 +24,25 @@ def alphanumeric_string(string):
|
|||
raise argparse.ArgumentTypeError(msg)
|
||||
return string
|
||||
|
||||
def path_or_json_string(string):
|
||||
if string == "":
|
||||
return {}
|
||||
|
||||
if string.startswith("[") or string.startswith("{"):
|
||||
try:
|
||||
return json.loads(string)
|
||||
except:
|
||||
raise argparse.ArgumentTypeError("{0} is not a valid JSON string.".format(string))
|
||||
elif io.file_exists(string):
|
||||
try:
|
||||
with open(string, 'r') as f:
|
||||
return json.loads(f.read())
|
||||
except:
|
||||
raise argparse.ArgumentTypeError("{0} is not a valid JSON file.".format(string))
|
||||
else:
|
||||
raise argparse.ArgumentTypeError("{0} is not a valid JSON file or string.".format(string))
|
||||
|
||||
|
||||
# Django URL validation regex
|
||||
def url_string(string):
|
||||
import re
|
||||
|
@ -137,6 +157,16 @@ def config():
|
|||
default=False,
|
||||
help='Turn off camera parameter optimization during bundler')
|
||||
|
||||
parser.add_argument('--cameras',
|
||||
default='',
|
||||
metavar='<string>',
|
||||
type=path_or_json_string,
|
||||
help='Use the camera parameters computed from '
|
||||
'another dataset instead of calculating them. '
|
||||
'Can be specified either as path to a cameras.json file or as a '
|
||||
'JSON string representing the contents of a '
|
||||
'cameras.json file. Default: %(default)s')
|
||||
|
||||
parser.add_argument('--max-concurrency',
|
||||
metavar='<positive integer>',
|
||||
default=context.num_cores,
|
||||
|
@ -556,6 +586,8 @@ def config():
|
|||
'%(default)s'))
|
||||
|
||||
args = parser.parse_args()
|
||||
print(args.cameras)
|
||||
exit(1)
|
||||
|
||||
# check that the project path setting has been set properly
|
||||
if not args.project_path:
|
||||
|
|
|
@ -8,6 +8,7 @@ from opendm import io
|
|||
from opendm import log
|
||||
from opendm import system
|
||||
from opendm import context
|
||||
from opendm import camera
|
||||
from opensfm.large import metadataset
|
||||
from opensfm.large import tools
|
||||
|
||||
|
@ -85,13 +86,14 @@ class OSFMContext:
|
|||
log.ODM_DEBUG("Copied image_groups.txt to OpenSfM directory")
|
||||
io.copy(image_groups_file, os.path.join(self.opensfm_project_path, "image_groups.txt"))
|
||||
|
||||
# check for cameras.json
|
||||
# TODO: use config.cameras
|
||||
camera_models_file = os.path.join(args.project_path, "cameras.json")
|
||||
has_camera_calibration = io.file_exists(camera_models_file)
|
||||
if has_camera_calibration:
|
||||
log.ODM_DEBUG("Copied cameras.json to OpenSfM directory (camera_models_overrides.json)")
|
||||
io.copy(camera_models_file, os.path.join(self.opensfm_project_path, "camera_models_overrides.json"))
|
||||
# check for cameras
|
||||
if args.cameras:
|
||||
try:
|
||||
with open(os.path.join(self.opensfm_project_path, "camera_models_overrides.json"), 'r') as f:
|
||||
f.write(json.dumps(camera.get_opensfm_camera_models(args.cameras)))
|
||||
log.ODM_DEBUG("Wrote camera_models_overrides.json to OpenSfM directory (camera_models_overrides.json)")
|
||||
except Exception as e:
|
||||
log.ODM_WARNING("Cannot set camera_models_overrides.json: %s" % str(e))
|
||||
|
||||
# create config file for OpenSfM
|
||||
config = [
|
||||
|
@ -196,30 +198,11 @@ class OSFMContext:
|
|||
def extract_cameras(self, output, rerun=False):
|
||||
reconstruction_file = self.path("reconstruction.json")
|
||||
if not os.path.exists(output) or rerun:
|
||||
if os.path.exists(reconstruction_file):
|
||||
result = {}
|
||||
with open(reconstruction_file, 'r') as fin:
|
||||
json_f = json.loads(fin.read())
|
||||
for recon in json_f:
|
||||
if 'cameras' in recon:
|
||||
for camera_id in recon['cameras']:
|
||||
# Strip "v2" from OpenSfM camera IDs
|
||||
new_camera_id = camera_id
|
||||
if new_camera_id.startswith("v2 "):
|
||||
new_camera_id = new_camera_id[3:]
|
||||
|
||||
result[new_camera_id] = recon['cameras'][camera_id]
|
||||
|
||||
# Remove "_prior" keys
|
||||
keys = list(result[new_camera_id].keys())
|
||||
for k in keys:
|
||||
if k.endswith('_prior'):
|
||||
result[new_camera_id].pop(k)
|
||||
|
||||
try:
|
||||
with open(output, 'w') as fout:
|
||||
fout.write(json.dumps(result))
|
||||
else:
|
||||
log.ODM_WARNING("Cannot export cameras to %s. reconstruction.json does not exist." % output)
|
||||
fout.write(json.dumps(camera.get_cameras_from_opensfm(reconstruction_file)))
|
||||
except Exception as e:
|
||||
log.ODM_WARNING("Cannot export cameras to %s. %s." % (output, str(e)))
|
||||
else:
|
||||
log.ODM_INFO("Already extracted cameras")
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
[
|
||||
{
|
||||
"reference_lla": {
|
||||
"latitude": 46.84265666666667,
|
||||
"altitude": 0,
|
||||
"longitude": -91.99400802469134
|
||||
},
|
||||
"cameras": {
|
||||
"v2 dji fc300s 4000 2250 perspective 0.5555": {
|
||||
"focal_prior": 0.5555555555555556,
|
||||
"width": 4000,
|
||||
"k1": 0.0052219633739416784,
|
||||
"k2": 0.015202301516716735,
|
||||
"k1_prior": 0.0,
|
||||
"k2_prior": 0.0,
|
||||
"projection_type": "perspective",
|
||||
"focal": 0.5614307793062748,
|
||||
"height": 2250
|
||||
}
|
||||
},
|
||||
"shots": {}
|
||||
}
|
||||
]
|
|
@ -0,0 +1,41 @@
|
|||
import time
|
||||
import unittest
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from opendm import camera
|
||||
|
||||
|
||||
class TestCamera(unittest.TestCase):
|
||||
def setUp(self):
|
||||
if os.path.exists("tests/assets/output"):
|
||||
shutil.rmtree("tests/assets/output")
|
||||
os.makedirs("tests/assets/output")
|
||||
|
||||
def test_camera(self):
|
||||
c = camera.get_cameras_from_opensfm("tests/assets/reconstruction.json")
|
||||
self.assertEqual(len(c.keys()), 1)
|
||||
camera_id = c.keys()[0]
|
||||
self.assertTrue('v2 ' not in camera_id)
|
||||
|
||||
self.assertRaises(RuntimeError, camera.get_cameras_from_opensfm, 'tests/assets/nonexistant.json')
|
||||
self.assertRaises(ValueError, camera.get_cameras_from_opensfm, 'tests/assets/gcp_extras.txt')
|
||||
self.assertFalse('k1_prior' in c[camera_id])
|
||||
|
||||
# Add bogus field
|
||||
c[camera_id]['test'] = 0
|
||||
|
||||
osfm_c = camera.get_opensfm_camera_models(c)
|
||||
self.assertEqual(len(osfm_c.keys()), 1)
|
||||
c1 = osfm_c[osfm_c.keys()[0]]
|
||||
self.assertTrue('k1_prior' in c1)
|
||||
self.assertTrue('k2_prior' in c1)
|
||||
self.assertFalse('test' in c1)
|
||||
self.assertEqual(c1['k1'], c1['k1_prior'])
|
||||
self.assertEqual(c1['k2'], c1['k2_prior'])
|
||||
self.assertEqual(c1['focal'], c1['focal_prior'])
|
||||
self.assertTrue('width_prior' not in c1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Ładowanie…
Reference in New Issue