Porównaj commity

...

5 Commity

Autor SHA1 Wiadomość Data
Piero Toffanin b2374f71a8
Merge c5c3930b8a into 424d9e28a0 2024-04-22 10:14:45 +03:00
Piero Toffanin 424d9e28a0
Merge pull request #1756 from andrewharvey/patch-1
Fix PoissonRecon failed with n threads log message
2024-04-18 11:53:46 -04:00
Andrew Harvey a0fbd71d41
Fix PoissonRecon failed with n threads log message
The message was reporting failure with n threads and retrying with n // 2, however a few lines up threads was already set to n // 2 representing the next thread count to try.
2024-04-18 15:35:53 +10:00
Piero Toffanin c5c3930b8a Merge branch 'master' of https://github.com/OpenDroneMap/ODM into smartband 2024-01-19 15:37:30 -05:00
Piero Toffanin c424769cd7 PoC Mavic 3M RGB unwarping 2024-01-19 15:37:25 -05:00
5 zmienionych plików z 95 dodań i 13 usunięć

Wyświetl plik

@ -187,7 +187,7 @@ def screened_poisson_reconstruction(inPointCloud, outMesh, depth = 8, samples =
if threads < 1:
break
else:
log.ODM_WARNING("PoissonRecon failed with %s threads, let's retry with %s..." % (threads, threads // 2))
log.ODM_WARNING("PoissonRecon failed with %s threads, let's retry with %s..." % (threads * 2, threads))
# Cleanup and reduce vertex count if necessary

Wyświetl plik

@ -6,7 +6,8 @@ from opendm import dls
import numpy as np
from opendm import log
from opendm.concurrency import parallel_map
from opensfm.io import imread
from opendm.io import related_file_path
from opensfm.io import imread, imwrite
from skimage import exposure
from skimage.morphology import disk
@ -635,4 +636,60 @@ def resize_match(image, dimension):
fy=fx,
interpolation=(cv2.INTER_AREA if (fx < 1.0 and fy < 1.0) else cv2.INTER_LANCZOS4))
return image
return image
def dewarp_photos(photos, images_path, scale_factor=1.0):
# Caution! This will make changes to the photo objects' filename
for p in photos:
# This should never happen
if os.path.splitext(p.filename)[0].endswith("_dewarped"):
log.ODM_WARNING("Cannot dewarp %s, already dewarped?" % (p.filename))
continue
if p.dewarp_data is None:
log.ODM_WARNING("Cannot dewarp %s, dewarp data is missing" % p.filename)
continue
if p.dewarp_data.count(";") != 1:
log.ODM_WARNING("Cannot dewarp %s, cannot parse dewarp data" % p.filename)
continue
datestamp, params = p.dewarp_data.split(";")
try:
params = [float(p) for p in params.split(",")]
except ValueError as e:
log.ODM_WARNING("Cannot dewarp %s, failed to parse dewarp data" % p.filename)
continue
if len(params) != 9:
log.ODM_WARNING("Cannot dewarp %s, invalid dewarp data parameters (expected 9, got: %s)" % (p.filename, len(params)))
continue
dewarped_filename = related_file_path(p.filename, postfix="_dewarped")
dewarped_path = os.path.join(images_path, dewarped_filename)
if os.path.isfile(dewarped_path):
# Already dewarped
p.filename = dewarped_filename
else:
image = imread(os.path.join(images_path, p.filename), unchanged=True, anydepth=True)
w, h = image.shape[1], image.shape[0]
fx, fy, cx, cy, k1, k2, p1, p2, k3 = params
cam_m = np.array([[fx, 0, w / 2 - cx], [0, fy, h / 2 + cy], [0, 0, 1]])
dist_c = np.array([k1, k2, p1, p2, k3])
map1, map2 = cv2.initUndistortRectifyMap(cam_m, dist_c, None, cam_m, (w, h), cv2.CV_32FC1)
dewarped_image = cv2.remap(image, map1, map2, cv2.INTER_LINEAR)
if scale_factor > 1.0:
new_w = int(w * (1.0 / scale_factor))
new_h = int(h * (1.0 / scale_factor))
center_x, center_y = w // 2, h // 2
crop_x1 = max(0, center_x - new_w // 2)
crop_y1 = max(0, center_y - new_h // 2)
crop_x2 = min(w, center_x + new_w // 2)
crop_y2 = min(h, center_y + new_h // 2)
cropped = dewarped_image[crop_y1:crop_y2, crop_x1:crop_x2]
dewarped_image = cv2.resize(cropped, (w, h), interpolation=cv2.INTER_LANCZOS4)
imwrite(dewarped_path, dewarped_image)
log.ODM_INFO("Dewarped %s --> %s" % (p.filename, dewarped_filename))
p.filename = dewarped_filename

Wyświetl plik

@ -159,6 +159,9 @@ class ODM_Photo:
self.gps_xy_stddev = None # Dilution of Precision X/Y
self.gps_z_stddev = None # Dilution of Precision Z
# DJI
self.dewarp_data = None
# Misc SFM
self.camera_projection = 'brown'
self.focal_ratio = 0.85
@ -413,6 +416,12 @@ class ODM_Photo:
self.set_attr_from_xmp_tag('speed_z', xtags, [
'@drone-dji:FlightZSpeed',
], float)
# DJI dewarp data
if '@drone-dji:DewarpData' in xtags:
self.set_attr_from_xmp_tag('dewarp_data', xtags, [
'@drone-dji:DewarpData'
])
# Account for over-estimation
if self.gps_xy_stddev is not None:

Wyświetl plik

@ -22,12 +22,13 @@ from opendm.photo import ODM_Photo
warnings.filterwarnings("ignore")
class ODM_Reconstruction(object):
def __init__(self, photos):
def __init__(self, photos, images_path):
self.photos = photos
self.georef = None
self.gcp = None
self.multi_camera = self.detect_multi_camera()
self.filter_photos()
self.dewarp_photos(images_path)
def detect_multi_camera(self):
"""
@ -148,13 +149,7 @@ class ODM_Reconstruction(object):
if 'rgb' in bands or 'redgreenblue' in bands:
if 'red' in bands and 'green' in bands and 'blue' in bands:
bands_to_remove.append(bands['rgb'] if 'rgb' in bands else bands['redgreenblue'])
# Mavic 3M's RGB camera lens are too different than the multispectral ones
# so we drop the RGB channel instead
elif self.photos[0].is_make_model("DJI", "M3M") and 'red' in bands and 'green' in bands:
bands_to_remove.append(bands['rgb'] if 'rgb' in bands else bands['redgreenblue'])
bands_to_remove.append(bands['rgb'] if 'rgb' in bands else bands['redgreenblue'])
else:
for b in ['red', 'green', 'blue']:
if b in bands:
@ -285,6 +280,23 @@ class ODM_Reconstruction(object):
if p.filename == filename:
return p
def dewarp_photos(self, images_path):
if not self.multi_camera:
return # Nothing to do
else:
bands = {}
for b in self.multi_camera:
bands[b['name'].lower()] = b['photos']
# Mavic 3M's RGB camera lens are too different than the multispectral ones
# so we unwarp them before reconstruction when needed
if self.photos[0].is_make_model("DJI", "M3M") and 'nir' in bands and ('rgb' in bands or 'redgreenblue' in bands):
log.ODM_INFO("Dewarping RGB photos before processing")
rgb = 'rgb' if 'rgb' in bands else 'redgreenblue'
upscale = max(1.0, bands['nir'][0].focal_ratio / bands[rgb][0].focal_ratio)
if upscale != 1.0:
log.ODM_INFO("Adjusting focal distance of RGB images by %s" % upscale)
multispectral.dewarp_photos(bands['rgb'] if 'rgb' in bands else bands['redgreenblue'], images_path, upscale)
class ODM_GeoRef(object):
@staticmethod

Wyświetl plik

@ -61,7 +61,7 @@ class ODMLoadDatasetStage(types.ODM_Stage):
def valid_filename(filename, supported_extensions):
(pathfn, ext) = os.path.splitext(filename)
return ext.lower() in supported_extensions and pathfn[-5:] != "_mask"
return ext.lower() in supported_extensions and pathfn[-5:] != "_mask" and pathfn[-9:] != "_dewarped"
# Get supported images from dir
def get_images(in_dir):
@ -162,6 +162,10 @@ class ODMLoadDatasetStage(types.ODM_Stage):
(p, ext) = os.path.splitext(r)
if p[-5:] == "_mask" and ext.lower() in context.supported_extensions:
masks[p] = r
# Remove dewarped images on re-run
if p[-9:] == "_dewarped" and self.rerun():
os.unlink(os.path.join(images_dir, p + ext))
photos = []
with open(tree.dataset_list, 'w') as dataset_list:
@ -298,7 +302,7 @@ class ODMLoadDatasetStage(types.ODM_Stage):
log.logger.log_json_images(len(photos))
# Create reconstruction object
reconstruction = types.ODM_Reconstruction(photos)
reconstruction = types.ODM_Reconstruction(photos, tree.dataset_raw)
if tree.odm_georeferencing_gcp and not args.use_exif:
reconstruction.georeference_with_gcp(tree.odm_georeferencing_gcp,