Porównaj commity

...

56 Commity

Autor SHA1 Wiadomość Data
Piero Toffanin 633116e8b5
Merge pull request #1856 from sbonaime/split_overlap_doc
doc improvement for split_overlap
2025-04-12 00:53:42 -04:00
bonaime 9300c37f1e doc improvment for split_overlap 2025-04-11 13:55:58 +02:00
Piero Toffanin 465b66a9ae
Merge pull request #1855 from sanmit99/patch-1.1
Fallback gdal_proximity command to native path
2025-04-08 22:27:37 -04:00
Piero Toffanin 25bb7b4487 Define gdal_proximity function fallback for GDAL 3.0 2025-04-08 22:24:33 -04:00
Piero Toffanin 415656a9b0
Merge pull request #1854 from sanmit99/patch-1
Declare gdal_proximity to handle nullcheck
2025-04-06 14:02:04 -04:00
sanmit99 22aafb04d7
Fallback gdal_proximity command to native path 2025-04-06 21:25:52 +05:30
sanmit99 17c98a15af
Declare gdal_proximity to handle nullcheck 2025-04-06 20:46:39 +05:30
Piero Toffanin 6114e5e934 Fix missing cv2 import 2025-03-19 11:43:07 -04:00
Piero Toffanin 831d4a26b4
Merge pull request #1842 from pierotofy/skyfilt
Fix invalid variable name
2025-03-12 11:53:08 -04:00
Piero Toffanin cdd4647300 Fix invalid variable name 2025-03-12 04:58:28 -04:00
Piero Toffanin 75e1be5b66
Merge pull request #1840 from pierotofy/omvsmin
Pass --min-resolution parameter to OpenMVS
2025-03-10 15:17:38 -04:00
Piero Toffanin 5552dcc09f Pass --min-resolution parameter 2025-03-10 15:11:44 -04:00
Piero Toffanin ebe0ced583
Merge pull request #1837 from lucadelu/worldfile
added wld file to png and tfw file to geotiff
2025-03-05 21:34:15 -05:00
Piero Toffanin cd9631b039 Simplify generate_extent_polygon 2025-03-05 13:29:35 -05:00
Piero Toffanin e4e1eca5d5 Refactor generate_tfw, add exception handling 2025-03-05 13:18:50 -05:00
Piero Toffanin db14127e05
Merge pull request #1838 from pierotofy/misslog
Add missing log import
2025-03-05 05:09:26 -05:00
Piero Toffanin 83d636a52a Add missing log import 2025-03-05 04:53:41 -05:00
Luca Delucchi b965aef6b6 added wld file to png and tfw file to geotiff 2025-03-05 06:39:00 +01:00
Piero Toffanin 85d34c52f9
Merge pull request #1835 from kikislater/patch-6
Fix #1834 Update generate_png function
2025-03-03 12:30:58 -05:00
Sylvain POULAIN 5e685d63a2
Update generate_png function 2025-03-03 15:17:23 +04:00
Piero Toffanin b2668ca738
Merge pull request #1828 from lucadelu/ortho_extent
added capability to generate vector polygon in DXF format to be used in AutoCAD LT
2025-03-01 22:08:50 -05:00
Piero Toffanin 131b29c3f3 Add try/catch, minor tweaks 2025-02-27 01:31:06 -05:00
Luca Delucchi ece421faec keep only DXF to support AutoCAD users to see correctly the output geotiff 2025-02-27 06:08:40 +01:00
Piero Toffanin ce839d439a
Merge pull request #1833 from pierotofy/dng
DNG/RAW/NEF file support
2025-02-24 23:26:46 -05:00
Piero Toffanin a68bfe319c Revert mvstex max_texture_size decrease 2025-02-24 21:15:58 +00:00
Piero Toffanin ade17cc957 Bump OpenMVS 2025-02-24 14:25:03 -05:00
Piero Toffanin 50add9bed5 Use camera white balance 2025-02-24 08:56:34 +00:00
Piero Toffanin a788cd3f73 Use odmrawpy 2025-02-24 03:18:12 -05:00
Piero Toffanin 6d1e800a0f Refactor generate_png, fix alpha 2025-02-23 16:49:46 -05:00
Piero Toffanin b47c6ef2f9 Better error message on ms filename match fail 2025-02-23 21:19:38 +00:00
Piero Toffanin 6f7c533552 Sky/bg filter support for DNGs 2025-02-23 20:38:42 +00:00
Piero Toffanin f5869777ed Disable bg/sky removal with DNGs 2025-02-23 20:29:38 +00:00
Piero Toffanin 2190a5dfa0 Improve PNG ortho creation with non-8bit files 2025-02-23 19:45:04 +00:00
Piero Toffanin 175d141ea7 PoC DNG file support 2025-02-23 19:22:38 +00:00
Luca Delucchi 2215e7ab7a added creation also of a dxf file 2025-02-19 22:17:38 +01:00
Luca Delucchi 9c740cbf1b added capability to generate vector polygon of the raster extent 2025-02-18 15:49:21 +01:00
Saijin-Naib 0333e08ce0
Merge pull request #1824 from ManuelPopp/master 2025-02-14 10:06:02 -05:00
Manuel Richard Popp cbe8ed7580 Fix typo; add docker pull 2025-02-14 11:11:42 +01:00
Piero Toffanin 75b9b92bbc
Merge pull request #1813 from fri-K/master
Cannot initialize CUDA even if nvidia-smi detected
2025-01-13 10:52:02 -05:00
Piero Toffanin df0c58574f update issue triage 2024-12-03 15:00:55 -05:00
fri.K 36897fc0e9
Cannot initialize CUDA even if nvidia-smi detected
CUDA can't be properly initialized if cuda-compat on host and docker mismatches. Removing cuda-compat-11-2 package fixes the issue

Issue discussion:
https://community.opendronemap.org/t/opendronemap-nodeodm-gpu-nvidia-smi-detected-cannot-initialize-cuda/21124
[INFO] nvidia-smi detected
[INFO] Using CPU for feature extraction: Cannot initialize CUDA
2024-11-19 14:01:33 +01:00
Piero Toffanin e615914914
Merge pull request #1811 from HeDo88TH/fix-external-build
Aligned the arm64 release name
2024-11-06 16:57:06 -05:00
Luca Di Leo 5aca98ba1e
Changed Obj2Tiles version to v1.0.13 2024-11-06 18:01:17 +01:00
Luca Di Leo d58835bfdf
Aligned the arm64 release name 2024-11-06 16:06:04 +01:00
Piero Toffanin 12e5b63b6f
Merge pull request #1808 from pierotofy/airsrt
Fix RST parsing for DJI air 2
2024-10-21 12:32:47 -04:00
Piero Toffanin 5de1ff0258 Fix RST parsing for DJI air 2 2024-10-21 12:30:48 -04:00
Piero Toffanin e3a11fd727
Merge pull request #1807 from smathermather/split_merge_cleanup
remove unused imports in split-merge
2024-10-18 12:43:55 -04:00
Stephen Mather 4022d38219 remove unused imports 2024-10-14 11:06:10 -04:00
Stephen Mather 5e1c9dd483
clean up unused imports in contrib (#1806) 2024-10-14 10:56:47 -04:00
Piero Toffanin 65fad52506
Merge pull request #1802 from smathermather/euclidean_merge_contrib
Make euclidean merge available in contrib directory
2024-09-17 20:15:40 -04:00
Stephen Mather d87fff3aa2 add readme 2024-09-17 20:08:19 -04:00
Stephen Mather 9d7c1a2be5 fix output dem 2024-09-17 20:02:00 -04:00
Stephen Mather 08d351bd00 add list of tiff files from directory 2024-09-17 14:57:48 -04:00
Stephen Mather 9f1bed5aaa initial draft of dem-blend 2024-09-17 10:44:29 -04:00
Piero Toffanin af552c15e7
Merge pull request #1801 from mark-stevens/master
Fix incorrect file name in ODM_WARNING
2024-09-16 12:42:22 -04:00
mark-stevens 16ffec9034 Fix incorrect file name in ODM_WARNING 2024-09-16 09:31:19 -07:00
29 zmienionych plików z 249 dodań i 86 usunięć

Wyświetl plik

@ -13,6 +13,7 @@ jobs:
with:
ghToken: ${{ secrets.GITHUB_TOKEN }}
openAI: ${{ secrets.OPENAI_TOKEN }}
model: gpt-4o-2024-08-06
filter: |
- "#"
variables: |

Wyświetl plik

@ -15,7 +15,13 @@ If you would rather not type commands in a shell and are looking for a friendly
## Quickstart
The easiest way to run ODM on is via docker. To install docker, see [docs.docker.com](https://docs.docker.com). Once you have docker installed and [working](https://docs.docker.com/get-started/#test-docker-installation), you can run ODM by placing some images (JPEGs or TIFFs) in a folder named “images” (for example `C:\Users\youruser\datasets\project\images` or `/home/youruser/datasets/project/images`) and simply run from a Command Prompt / Terminal:
The easiest way to run ODM is via docker. To install docker, see [docs.docker.com](https://docs.docker.com). Once you have docker installed and [working](https://docs.docker.com/get-started/#test-docker-installation), you can get ODM by running from a Command Prompt / Terminal:
```bash
docker pull opendronemap/odm
```
Run ODM by placing some images (JPEGs, TIFFs or DNGs) in a folder named “images” (for example `C:\Users\youruser\datasets\project\images` or `/home/youruser/datasets/project/images`) and simply run from a Command Prompt / Terminal:
```bash
# Windows

Wyświetl plik

@ -244,7 +244,7 @@ externalproject_add(dem2points
externalproject_add(odm_orthophoto
DEPENDS opencv
GIT_REPOSITORY https://github.com/OpenDroneMap/odm_orthophoto.git
GIT_TAG 353
GIT_TAG 355
PREFIX ${SB_BINARY_DIR}/odm_orthophoto
SOURCE_DIR ${SB_SOURCE_DIR}/odm_orthophoto
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${SB_INSTALL_DIR}

Wyświetl plik

@ -1,7 +1,7 @@
set(_proj_name obj2tiles)
set(_SB_BINARY_DIR "${SB_BINARY_DIR}/${_proj_name}")
set(OBJ2TILES_VERSION v1.0.12)
set(OBJ2TILES_VERSION v1.0.13)
set(OBJ2TILES_EXT "")
set(OBJ2TILES_ARCH "Linux64")
@ -9,7 +9,7 @@ if (WIN32)
set(OBJ2TILES_ARCH "Win64")
set(OBJ2TILES_EXT ".exe")
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
set(OBJ2TILES_ARCH "LinuxArm")
set(OBJ2TILES_ARCH "LinuxArm64")
elseif(APPLE)
set(OBJ2TILES_ARCH "Osx64")
endif()

Wyświetl plik

@ -53,7 +53,7 @@ ExternalProject_Add(${_proj_name}
#--Download step--------------
DOWNLOAD_DIR ${SB_DOWNLOAD_DIR}
GIT_REPOSITORY https://github.com/OpenDroneMap/openMVS
GIT_TAG 320
GIT_TAG 355
#--Update/Patch step----------
UPDATE_COMMAND ""
#--Configure step-------------

Wyświetl plik

@ -25,7 +25,7 @@ ExternalProject_Add(${_proj_name}
#--Download step--------------
DOWNLOAD_DIR ${SB_DOWNLOAD_DIR}
GIT_REPOSITORY https://github.com/OpenDroneMap/OpenSfM/
GIT_TAG 352
GIT_TAG 355
#--Update/Patch step----------
UPDATE_COMMAND git submodule update --init --recursive
#--Configure step-------------

Wyświetl plik

@ -1 +1 @@
3.5.4
3.5.5

Wyświetl plik

@ -1,5 +1,4 @@
import bpy
import materials_utils
def loadMesh(file):

Wyświetl plik

@ -0,0 +1,13 @@
# DEM Blending
Blend sets of DEMs by calculating euclidean distance to null values and weighting the combination of elevation models. Based on the split-merge tool within ODM.
Requirements:
* Directory full of images to blend together
* NoData should be coded as a value of -9999
## Usage
```BASH
docker run -ti --rm -v /home/youruser/folder_with_dems:/input --entrypoint /code/contrib/dem-blend/dem-blend.py opendronemap/odm /input
```

Wyświetl plik

@ -0,0 +1,30 @@
#!/usr/bin/env python3
# Authors: Piero Toffanin, Stephen Mather
# License: AGPLv3
import os
import glob
import sys
sys.path.insert(0, os.path.join("..", "..", os.path.dirname(__file__)))
import argparse
from opendm.dem import merge
parser = argparse.ArgumentParser(description='Merge and blend DEMs using OpenDroneMap\'s approach.')
parser.add_argument('input_dems',
type=str,
help='Path to input dems (.tif)')
args = parser.parse_args()
if not os.path.exists(args.input_dems):
print("%s does not exist" % args.input_dems)
exit(1)
output_dem = os.path.join(args.input_dems, 'merged_blended_dem.tif')
input_dem_path = os.path.join(args.input_dems, '*.tif')
input_dems = glob.glob(input_dem_path)
merge.euclidean_merge_dems(input_dems
,output_dem=output_dem
)

Wyświetl plik

@ -4,7 +4,7 @@ import os
import PIL
from PIL import Image, ExifTags
from PIL import Image
import shutil

Wyświetl plik

@ -12,7 +12,6 @@ import numpy as np
import numpy.ma as ma
import multiprocessing
import argparse
import functools
from skimage.draw import line
from opensfm import dataset

Wyświetl plik

@ -38,6 +38,7 @@ COPY --from=builder /code /code
# Copy the Python libraries installed via pip from the builder
COPY --from=builder /usr/local /usr/local
#COPY --from=builder /usr/lib/x86_64-linux-gnu/libavcodec.so.58 /usr/lib/x86_64-linux-gnu/libavcodec.so.58
RUN dpkg --remove cuda-compat-11-2
RUN apt-get update -y \
&& apt-get install -y ffmpeg libtbb2
# Install shared libraries that we depend on via APT, but *not*

Wyświetl plik

@ -4,6 +4,25 @@ from opendm import log
import zipfile
import time
import sys
import rawpy
import cv2
def read_image(img_path):
if img_path[-4:].lower() in [".dng", ".raw", ".nef"]:
try:
with rawpy.imread(img_path) as r:
img = r.postprocess(output_bps=8, use_camera_wb=True, use_auto_wb=False)
except:
return None
else:
img = cv2.imread(img_path, cv2.IMREAD_COLOR)
if img is None:
return None
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
return img
def get_model(namespace, url, version, name = "model.onnx"):
version = version.replace(".", "_")

Wyświetl plik

@ -5,6 +5,7 @@ import cv2
import os
import onnxruntime as ort
from opendm import log
from opendm.ai import read_image
from threading import Lock
mutex = Lock()
@ -73,11 +74,7 @@ class BgFilter():
return output
def run_img(self, img_path, dest):
img = cv2.imread(img_path, cv2.IMREAD_COLOR)
if img is None:
return None
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = read_image(img_path)
mask = self.get_mask(img)
img_name = os.path.basename(img_path)

Wyświetl plik

@ -127,7 +127,7 @@ def url_string(string):
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
r'(?::\d+)?' # optional port
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
if re.match(regex, string) is None:
raise argparse.ArgumentTypeError("%s is not a valid URL. The URL must be in the format: http(s)://host[:port]/[?token=]" % string)
return string
@ -164,7 +164,7 @@ def config(argv=None, parser=None):
parser = SettingsParser(description='ODM is a command line toolkit to generate maps, point clouds, 3D models and DEMs from drone, balloon or kite images.',
usage='%s [options] <dataset name>' % usage_bin,
yaml_file=open(context.settings_path))
parser.add_argument('--project-path',
metavar='<path>',
action=StoreValue,
@ -213,7 +213,7 @@ def config(argv=None, parser=None):
'More features can be useful for finding more matches between images, '
'potentially allowing the reconstruction of areas with little overlap or insufficient features. '
'More features also slow down processing. Default: %(default)s'))
parser.add_argument('--feature-type',
metavar='<string>',
action=StoreValue,
@ -222,7 +222,7 @@ def config(argv=None, parser=None):
help=('Choose the algorithm for extracting keypoints and computing descriptors. '
'Can be one of: %(choices)s. Default: '
'%(default)s'))
parser.add_argument('--feature-quality',
metavar='<string>',
action=StoreValue,
@ -231,7 +231,7 @@ def config(argv=None, parser=None):
help=('Set feature extraction quality. Higher quality generates better features, but requires more memory and takes longer. '
'Can be one of: %(choices)s. Default: '
'%(default)s'))
parser.add_argument('--matcher-type',
metavar='<string>',
action=StoreValue,
@ -247,7 +247,7 @@ def config(argv=None, parser=None):
default=0,
type=int,
help='Perform image matching with the nearest images based on GPS exif data. Set to 0 to match by triangulation. Default: %(default)s')
parser.add_argument('--matcher-order',
metavar='<positive integer>',
action=StoreValue,
@ -331,7 +331,7 @@ def config(argv=None, parser=None):
nargs=0,
default=False,
help='Automatically compute image masks using AI to remove the sky. Experimental. Default: %(default)s')
parser.add_argument('--bg-removal',
action=StoreTrue,
nargs=0,
@ -349,19 +349,19 @@ def config(argv=None, parser=None):
nargs=0,
default=False,
help='Skip generation of a full 3D model. This can save time if you only need 2D results such as orthophotos and DEMs. Default: %(default)s')
parser.add_argument('--skip-report',
action=StoreTrue,
nargs=0,
default=False,
help='Skip generation of PDF report. This can save time if you don\'t need a report. Default: %(default)s')
parser.add_argument('--skip-orthophoto',
action=StoreTrue,
nargs=0,
default=False,
help='Skip generation of the orthophoto. This can save time if you only need 3D results or DEMs. Default: %(default)s')
parser.add_argument('--ignore-gsd',
action=StoreTrue,
nargs=0,
@ -371,13 +371,13 @@ def config(argv=None, parser=None):
'Ordinarily, GSD estimates are used to cap the maximum resolution of image outputs and resizes images when necessary, resulting in faster processing and lower memory usage. '
'Since GSD is an estimate, sometimes ignoring it can result in slightly better image output quality. '
'Never set --ignore-gsd to true unless you are positive you need it, and even then: do not use it. Default: %(default)s')
parser.add_argument('--no-gpu',
action=StoreTrue,
nargs=0,
default=False,
help='Do not use GPU acceleration, even if it\'s available. Default: %(default)s')
parser.add_argument('--mesh-size',
metavar='<positive integer>',
action=StoreValue,
@ -462,7 +462,7 @@ def config(argv=None, parser=None):
nargs=0,
default=False,
help='Export the georeferenced point cloud in CSV format. Default: %(default)s')
parser.add_argument('--pc-las',
action=StoreTrue,
nargs=0,
@ -488,7 +488,7 @@ def config(argv=None, parser=None):
default=5,
help='Filters the point cloud by removing points that deviate more than N standard deviations from the local mean. Set to 0 to disable filtering. '
'Default: %(default)s')
parser.add_argument('--pc-sample',
metavar='<positive float>',
action=StoreValue,
@ -519,7 +519,7 @@ def config(argv=None, parser=None):
default=0.15,
help='Simple Morphological Filter slope parameter (rise over run). '
'Default: %(default)s')
parser.add_argument('--smrf-threshold',
metavar='<positive float>',
action=StoreValue,
@ -527,7 +527,7 @@ def config(argv=None, parser=None):
default=0.5,
help='Simple Morphological Filter elevation threshold parameter (meters). '
'Default: %(default)s')
parser.add_argument('--smrf-window',
metavar='<positive float>',
action=StoreValue,
@ -586,7 +586,7 @@ def config(argv=None, parser=None):
'EPSG:<code> or <+proj definition>\n'
'image_name geo_x geo_y geo_z [yaw (degrees)] [pitch (degrees)] [roll (degrees)] [horz accuracy (meters)] [vert accuracy (meters)]\n'
'Default: %(default)s'))
parser.add_argument('--align',
metavar='<path string>',
action=StoreValue,
@ -642,7 +642,7 @@ def config(argv=None, parser=None):
type=int,
help='Decimate the points before generating the DEM. 1 is no decimation (full quality). '
'100 decimates ~99%% of the points. Useful for speeding up generation of DEM results in very large datasets. Default: %(default)s')
parser.add_argument('--dem-euclidean-map',
action=StoreTrue,
nargs=0,
@ -675,13 +675,13 @@ def config(argv=None, parser=None):
default=False,
help='Set this parameter if you want to generate a PNG rendering of the orthophoto. '
'Default: %(default)s')
parser.add_argument('--orthophoto-kmz',
action=StoreTrue,
nargs=0,
default=False,
help='Set this parameter if you want to generate a Google Earth (KMZ) rendering of the orthophoto. '
'Default: %(default)s')
'Default: %(default)s')
parser.add_argument('--orthophoto-compression',
metavar='<string>',
@ -690,7 +690,7 @@ def config(argv=None, parser=None):
choices=['JPEG', 'LZW', 'PACKBITS', 'DEFLATE', 'LZMA', 'NONE'],
default='DEFLATE',
help='Set the compression to use for orthophotos. Can be one of: %(choices)s. Default: %(default)s')
parser.add_argument('--orthophoto-cutline',
action=StoreTrue,
nargs=0,
@ -729,7 +729,7 @@ def config(argv=None, parser=None):
action=StoreValue,
metavar='<positive integer>',
default=0,
help='Override the rolling shutter readout time for your camera sensor (in milliseconds), instead of using the rolling shutter readout database. '
help='Override the rolling shutter readout time for your camera sensor (in milliseconds), instead of using the rolling shutter readout database. '
'Note that not all cameras are present in the database. Set to 0 to use the database value. '
'Default: %(default)s')
@ -768,7 +768,7 @@ def config(argv=None, parser=None):
default=4000,
metavar='<positive integer>',
help='The maximum output resolution of extracted video frames in pixels. Default: %(default)s')
parser.add_argument('--split',
type=int,
action=StoreValue,
@ -785,11 +785,12 @@ def config(argv=None, parser=None):
action=StoreValue,
metavar='<positive integer>',
default=150,
help='Radius of the overlap between submodels. '
help='Radius of the overlap between submodels in meters. '
'After grouping images into clusters, images '
'that are closer than this radius to a cluster '
'are added to the cluster. This is done to ensure '
'that neighboring submodels overlap. Default: %(default)s')
'that neighboring submodels overlap. All images' \
'need GPS information. Default: %(default)s')
parser.add_argument('--split-image-groups',
metavar='<path string>',
@ -833,7 +834,7 @@ def config(argv=None, parser=None):
help=('Use images\' GPS exif data for reconstruction, even if there are GCPs present.'
'This flag is useful if you have high precision GPS measurements. '
'If there are no GCPs, this flag does nothing. Default: %(default)s'))
parser.add_argument('--gps-accuracy',
type=float,
action=StoreValue,
@ -868,7 +869,7 @@ def config(argv=None, parser=None):
default="auto",
type=str,
help=('When processing multispectral datasets, you can specify the name of the primary band that will be used for reconstruction. '
'It\'s recommended to choose a band which has sharp details and is in focus. '
'It\'s recommended to choose a band which has sharp details and is in focus. '
'Default: %(default)s'))
parser.add_argument('--skip-band-alignment',
@ -923,5 +924,5 @@ def config(argv=None, parser=None):
except exceptions.NodeConnectionError as e:
log.ODM_ERROR("Cluster node seems to be offline: %s" % str(e))
sys.exit(1)
return args

Wyświetl plik

@ -40,7 +40,7 @@ odm_orthophoto_path = os.path.join(superbuild_bin_path, "odm_orthophoto")
settings_path = os.path.join(root_path, 'settings.yaml')
# Define supported image extensions
supported_extensions = {'.jpg','.jpeg','.png', '.tif', '.tiff', '.bmp'}
supported_extensions = {'.jpg','.jpeg','.png', '.tif', '.tiff', '.bmp', '.raw', '.dng', '.nef'}
supported_video_extensions = {'.mp4', '.mov', '.lrv', '.ts'}
# Define the number of cores

Wyświetl plik

@ -1,4 +1,5 @@
import os
import subprocess
import sys
import rasterio
import numpy
@ -20,6 +21,8 @@ from opendm import log
from .ground_rectification.rectify import run_rectification
from . import pdal
gdal_proximity = None
try:
# GDAL >= 3.3
from osgeo_utils.gdal_proximity import main as gdal_proximity
@ -27,8 +30,13 @@ except ModuleNotFoundError:
# GDAL <= 3.2
try:
from osgeo.utils.gdal_proximity import main as gdal_proximity
except:
pass
except ModuleNotFoundError:
# GDAL <= 3.0
gdal_proximity_script = shutil.which("gdal_proximity.py")
if gdal_proximity_script is not None:
def gdal_proximity(args):
subprocess.run([gdal_proximity_script] + args[1:], check=True)
def classify(lasFile, scalar, slope, threshold, window):
start = datetime.now()
@ -263,4 +271,4 @@ def get_dem_radius_steps(stats_file, steps, resolution, multiplier = 1.0):
for _ in range(steps - 1):
radius_steps.append(radius_steps[-1] * math.sqrt(2))
return radius_steps
return radius_steps

Wyświetl plik

@ -1,6 +1,6 @@
from PIL import Image
import cv2
import rawpy
from opendm import log
Image.MAX_IMAGE_PIXELS = None
@ -9,12 +9,18 @@ def get_image_size(file_path, fallback_on_error=True):
"""
Return (width, height) for a given img file
"""
try:
with Image.open(file_path) as img:
width, height = img.size
if file_path[-4:].lower() in [".dng", ".raw", ".nef"]:
with rawpy.imread(file_path) as img:
s = img.sizes
width, height = s.raw_width, s.raw_height
else:
with Image.open(file_path) as img:
width, height = img.size
except Exception as e:
if fallback_on_error:
log.ODM_WARNING("Cannot read %s with PIL, fallback to cv2: %s" % (file_path, str(e)))
log.ODM_WARNING("Cannot read %s with image library, fallback to cv2: %s" % (file_path, str(e)))
img = cv2.imread(file_path)
width = img.shape[1]
height = img.shape[0]

Wyświetl plik

@ -6,6 +6,7 @@ import numpy as np
import pygltflib
from opendm import system
from opendm import io
from opendm import log
warnings.filterwarnings("ignore", category=rasterio.errors.NotGeoreferencedWarning)

Wyświetl plik

@ -273,7 +273,10 @@ def compute_band_maps(multi_camera, primary_band):
# Quick check
if filename_without_band == p.filename:
raise Exception("Cannot match bands by filename on %s, make sure to name your files [filename]_band[.ext] uniformly." % p.filename)
if not filename_without_band in filename_map:
raise Exception("Cannot match bands by filename on %s, make sure to name your files [filename]_band[.ext] uniformly, check that your images have the appropriate CaptureUUID XMP tag and that no images are missing." % p.filename)
s2p[p.filename] = filename_map[filename_without_band]
if band['name'] != band_name:

Wyświetl plik

@ -14,6 +14,7 @@ from opendm import io
from opendm.tiles.tiler import generate_orthophoto_tiles
from opendm.cogeo import convert_to_cogeo
from osgeo import gdal
from osgeo import ogr
def get_orthophoto_vars(args):
@ -43,33 +44,50 @@ def generate_png(orthophoto_file, output_file=None, outsize=None):
output_file = base + '.png'
# See if we need to select top three bands
bandparam = ""
params = []
gtif = gdal.Open(orthophoto_file)
if gtif.RasterCount > 4:
try:
gtif = gdal.Open(orthophoto_file)
bands = []
for idx in range(1, gtif.RasterCount+1):
bands.append(gtif.GetRasterBand(idx).GetColorInterpretation())
bands = dict(zip(bands, range(1, len(bands)+1)))
try:
if gtif.RasterCount >= 3:
red = bands.get(gdal.GCI_RedBand)
green = bands.get(gdal.GCI_GreenBand)
blue = bands.get(gdal.GCI_BlueBand)
if red is None or green is None or blue is None:
raise Exception("Cannot find bands")
params.append("-b 1 -b 2 -b 3")
else:
params.append("-b %s -b %s -b %s" % (red, green, blue))
elif gtif.RasterCount <= 2:
params.append("-b 1")
alpha = bands.get(gdal.GCI_AlphaBand)
if alpha is not None:
params.append("-b %s" % alpha)
else:
params.append("-a_nodata 0")
bandparam = "-b %s -b %s -b %s -a_nodata 0" % (red, green, blue)
except:
bandparam = "-b 1 -b 2 -b 3 -a_nodata 0"
gtif = None
dtype = gtif.GetRasterBand(1).DataType
if dtype != gdal.GDT_Byte:
params.append("-ot Byte")
if gtif.RasterCount >= 3:
params.append("-scale_1 -scale_2 -scale_3")
elif gtif.RasterCount <= 2:
params.append("-scale_1")
gtif = None
except Exception as e:
log.ODM_WARNING("Cannot read orthophoto information for PNG generation: %s" % str(e))
osparam = ""
if outsize is not None:
osparam = "-outsize %s 0" % outsize
params.append("-outsize %s 0" % outsize)
system.run('gdal_translate -of png "%s" "%s" %s %s '
'--config GDAL_CACHEMAX %s%% ' % (orthophoto_file, output_file, osparam, bandparam, get_max_memory()))
system.run('gdal_translate -of png "%s" "%s" %s '
'-co WORLDFILE=YES '
'--config GDAL_CACHEMAX %s%% ' % (orthophoto_file, output_file, " ".join(params), get_max_memory()))
def generate_kmz(orthophoto_file, output_file=None, outsize=None):
if output_file is None:
@ -84,7 +102,70 @@ def generate_kmz(orthophoto_file, output_file=None, outsize=None):
system.run('gdal_translate -of KMLSUPEROVERLAY -co FORMAT=PNG "%s" "%s" %s '
'--config GDAL_CACHEMAX %s%% ' % (orthophoto_file, output_file, bandparam, get_max_memory()))
def generate_extent_polygon(orthophoto_file):
"""Function to return the orthophoto extent as a polygon into a gpkg file
Args:
orthophoto_file (str): the path to orthophoto file
"""
base, ext = os.path.splitext(orthophoto_file)
output_file = base + '_extent.dxf'
try:
gtif = gdal.Open(orthophoto_file)
srs = gtif.GetSpatialRef()
geoTransform = gtif.GetGeoTransform()
# calculate the coordinates
minx = geoTransform[0]
maxy = geoTransform[3]
maxx = minx + geoTransform[1] * gtif.RasterXSize
miny = maxy + geoTransform[5] * gtif.RasterYSize
# create polygon in wkt format
poly_wkt = "POLYGON ((%s %s, %s %s, %s %s, %s %s, %s %s))" % (minx, miny, minx, maxy, maxx, maxy, maxx, miny, minx, miny)
# create vector file
# just the DXF to support AutoCAD users
# to load the geotiff raster correctly.
driver = ogr.GetDriverByName("DXF")
ds = driver.CreateDataSource(output_file)
layer = ds.CreateLayer("extent", srs, ogr.wkbPolygon)
# create the feature and set values
featureDefn = layer.GetLayerDefn()
feature = ogr.Feature(featureDefn)
feature.SetGeometry(ogr.CreateGeometryFromWkt(poly_wkt))
# add feature to layer
layer.CreateFeature(feature)
# save and close everything
feature = None
ds = None
gtif = None
log.ODM_INFO("Wrote %s" % output_file)
except Exception as e:
log.ODM_WARNING("Cannot create extent layer for %s: %s" % (orthophoto_file, str(e)))
def generate_tfw(orthophoto_file):
base, ext = os.path.splitext(orthophoto_file)
tfw_file = base + '.tfw'
try:
with rasterio.open(orthophoto_file) as ds:
t = ds.transform
with open(tfw_file, 'w') as f:
# rasterio affine values taken by
# https://mharty3.github.io/til/GIS/raster-affine-transforms/
f.write("\n".join([str(v) for v in [t.a, t.d, t.b, t.e, t.c, t.f]]) + "\n")
log.ODM_INFO("Wrote %s" % tfw_file)
except Exception as e:
log.ODM_WARNING("Cannot create .tfw for %s: %s" % (orthophoto_file, str(e)))
def post_orthophoto_steps(args, bounds_file_path, orthophoto_file, orthophoto_tiles_dir, resolution):
if args.crop > 0 or args.boundary:
Cropper.crop(bounds_file_path, orthophoto_file, get_orthophoto_vars(args), keep_original=not args.optimize_disk_space, warp_options=['-dstalpha'])
@ -104,6 +185,9 @@ def post_orthophoto_steps(args, bounds_file_path, orthophoto_file, orthophoto_ti
if args.cog:
convert_to_cogeo(orthophoto_file, max_workers=args.max_concurrency, compression=args.orthophoto_compression)
generate_extent_polygon(orthophoto_file)
generate_tfw(orthophoto_file)
def compute_mask_raster(input_raster, vector_mask, output_raster, blend_distance=20, only_max_coords_feature=False):
if not os.path.exists(input_raster):
log.ODM_WARNING("Cannot mask raster, %s does not exist" % input_raster)

Wyświetl plik

@ -327,7 +327,7 @@ def post_point_cloud_steps(args, tree, rerun=False):
tree.odm_georeferencing_model_laz,
tree.odm_georeferencing_model_las))
else:
log.ODM_WARNING("Found existing LAS file %s" % tree.odm_georeferencing_xyz_file)
log.ODM_WARNING("Found existing LAS file %s" % tree.odm_georeferencing_model_las)
# EPT point cloud output
if args.pc_ept:

Wyświetl plik

@ -6,6 +6,7 @@ import os
import onnxruntime as ort
from .guidedfilter import guided_filter
from opendm import log
from opendm.ai import read_image
from threading import Lock
mutex = Lock()
@ -72,11 +73,7 @@ class SkyFilter():
def run_img(self, img_path, dest):
img = cv2.imread(img_path, cv2.IMREAD_COLOR)
if img is None:
return None
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = read_image(img_path)
img = np.array(img / 255., dtype=np.float32)
mask = self.get_mask(img)

Wyświetl plik

@ -120,6 +120,7 @@ class SrtFileParser:
# <font size="36">SrtCnt : 1, DiffTime : 16ms
# 2023-01-06 18:56:48,380,821
# [iso : 3200] [shutter : 1/60.0] [fnum : 280] [ev : 0] [ct : 3925] [color_md : default] [focal_len : 240] [latitude: 0.000000] [longitude: 0.000000] [altitude: 0.000000] </font>
# </font>
# DJI Mavic Mini
# 1
@ -164,9 +165,10 @@ class SrtFileParser:
end = None
for line in f:
# Remove html tags, spaces
line = re.sub('<[^<]+?>', '', line).strip()
# Check if line is empty
if not line.strip():
if not line:
if start is not None:
self.data.append({
"start": start,
@ -193,9 +195,6 @@ class SrtFileParser:
continue
# Remove html tags
line = re.sub('<[^<]+?>', '', line)
# Search this "00:00:00,000 --> 00:00:00,016"
match = re.search("(\d{2}:\d{2}:\d{2},\d+) --> (\d{2}:\d{2}:\d{2},\d+)", line)
if match:
@ -225,14 +224,14 @@ class SrtFileParser:
("GPS \([\d\.\-]+,? ([\d\.\-]+),? [\d\.\-]+\)", lambda v: float(v) if v != 0 else None),
("RTK \([-+]?\d+\.\d+, (-?\d+\.\d+), -?\d+\)", lambda v: float(v) if v != 0 else None),
], line)
longitude = match_single([
("longitude: ([\d\.\-]+)", lambda v: float(v) if v != 0 else None),
("longtitude : ([\d\.\-]+)", lambda v: float(v) if v != 0 else None),
("GPS \(([\d\.\-]+),? [\d\.\-]+,? [\d\.\-]+\)", lambda v: float(v) if v != 0 else None),
("RTK \((-?\d+\.\d+), [-+]?\d+\.\d+, -?\d+\)", lambda v: float(v) if v != 0 else None),
], line)
altitude = match_single([
("altitude: ([\d\.\-]+)", lambda v: float(v) if v != 0 else None),
("GPS \([\d\.\-]+,? [\d\.\-]+,? ([\d\.\-]+)\)", lambda v: float(v) if v != 0 else None),

Wyświetl plik

@ -23,6 +23,7 @@ rasterio==1.2.3 ; sys_platform == 'linux'
rasterio==1.3.6 ; sys_platform == 'darwin'
https://github.com/OpenDroneMap/windows-deps/raw/main/rasterio-1.2.3-cp38-cp38-win_amd64.whl ; sys_platform == 'win32'
https://github.com/OpenDroneMap/windows-deps/raw/main/GDAL-3.2.3-cp38-cp38-win_amd64.whl ; sys_platform == 'win32'
odmrawpy==0.24.1
repoze.lru==0.7
scikit-learn==1.1.1
Pywavelets==1.3.0

Wyświetl plik

@ -234,9 +234,9 @@ class ODMLoadDatasetStage(types.ODM_Stage):
item['p'].set_mask(os.path.basename(mask_file))
log.ODM_INFO("Wrote %s" % os.path.basename(mask_file))
else:
log.ODM_WARNING("Cannot generate mask for %s" % img)
log.ODM_WARNING("Cannot generate mask for %s" % item['file'])
except Exception as e:
log.ODM_WARNING("Cannot generate mask for %s: %s" % (img, str(e)))
log.ODM_WARNING("Cannot generate mask for %s: %s" % (item['file'], str(e)))
parallel_map(parallel_sky_filter, sky_images, max_workers=args.max_concurrency)

Wyświetl plik

@ -63,11 +63,13 @@ class ODMOpenMVSStage(types.ODM_Stage):
densify_ini_file = os.path.join(tree.openmvs, 'Densify.ini')
subres_levels = 2 # The number of lower resolutions to process before estimating output resolution depthmap.
filter_point_th = -20
min_resolution = 320 if args.pc_quality in ["low", "lowest"] else 640
config = [
"--resolution-level %s" % int(resolution_level),
'--dense-config-file "%s"' % densify_ini_file,
"--max-resolution %s" % int(outputs['undist_image_max_size']),
"--min-resolution %s" % min_resolution,
"--max-threads %s" % args.max_concurrency,
"--number-views-fuse %s" % number_views_fuse,
"--sub-resolution-levels %s" % subres_levels,

Wyświetl plik

@ -1,19 +1,15 @@
import os
import shutil
import json
import yaml
from opendm import log
from opendm.osfm import OSFMContext, get_submodel_argv, get_submodel_paths, get_all_submodel_paths
from opendm import types
from opendm import io
from opendm import system
from opendm import orthophoto
from opendm.gcp import GCPFile
from opendm.dem import pdal, utils
from opendm.dem import utils
from opendm.dem.merge import euclidean_merge_dems
from opensfm.large import metadataset
from opendm.cropper import Cropper
from opendm.concurrency import get_max_memory
from opendm.remote import LocalRemoteExecutor
from opendm.shots import merge_geojson_shots, merge_cameras
from opendm import point_cloud