Top-Tips#

PyProj#

If special transformation grids are included in the coordinate transformation use:

# PROJ activate network grid/data
pyproj.network.set_network_enabled(True)  # pyright: ignore[reportPrivateImportUsage]

Or specify data-dir via

pyproj.datadir.set_data_dir(proj_data_dir)

Results#

The most important functions, mapping(mapper.map_points, mapper.map_footprint, mapper.map_center_point) and coordinate projections (image.project) return MappingResult and ProjectionResult

  • MappingResult is either ResultFailure or MappingResultSuccess

  • ProjectionResult is either ResultFailure or ProjectionResultSuccess

You can test whether it’s Success or Failure be checking .ok. The results will always be in the same order as the input pixel/coordinates.

Always check for issues to catch reasons for invalid results

Tip

Most mapping functions return results with a CRS attached (res.crs). You can use that CRS to transform the mapped output (e.g. footprint coordinates) to another coordinate system via CoordinateTransformer.

from pyproj import CRS
from weitsicht.transform import CoordinateTransformer

res = image.map_footprint()
if res.ok and res.crs is not None:
    crs_target = CRS.from_epsg(4979) # WGS84 ell with ellipsoid heights
    transformer = CoordinateTransformer.from_crs(res.crs, crs_target)

    coords_src = res.coordinates[res.mask]
    # Always check that transfomer is not None which is the case if source and target crs are equal
    coords_target = coords_src if transformer is None else transformer.transform(coords_src)

Errors#

Most functions either raise a WeitsichtError (invalid inputs / missing state) or return a result object (MappingResult / ProjectionResult) that can be a ResultFailure.

from weitsicht import WeitsichtError

try:
    res = image.map_points([[200, 300], [50, 50]])
except WeitsichtError as err:
    print("weitsicht error:", err)
else:
    if not res.ok:
        print("mapping failed:", res.error, "issues:", res.issues)
    else:
        coords_valid = res.coordinates[res.mask]  # keep input order

See Error Handling for more patterns and the exception hierarchy.

Perspective Images#

Tip

For drone photos, prefer building your ImagePerspective from EXIF/XMP metadata (e.g. ExifTool -> PyExifToolTags -> image_from_meta()) or use ImageFromMetaBuilder if you want IOR/EOR separately. See Metadata for Camera and Pose Extraction and 04-01 - Digitize Dugongs.

‘’image_from_meta()’’ and other EOR related functions feature an input parameter to_utm=True which will convert EOR (position and orientation) to WGS84/UTM. Otherwise standard output of images loaded by meta builder are in WGS84 geocentric (EPG:4978) coordiantes

CRS quick reference#

CRS overview (rows) vs. weitsicht components (columns)#

CRS / units

Perspective Image (EOR)

Coordiantes for Projection

Orthophoto CRS

Mapper Horizontal

MapperRaster GeorefArray

Mapper Trimesh

None (local coordinates, no transforms)

OK

OK

OK

OK

OK (force_no_crs=True)

OK

Projected (e.g., UTM) (0)

OK

OK

OK

OK

OK

OK

Geocentric Cartesian (ECEF) (e.g. EPSG:4978)

OK

OK

Not possible - Rare (never seen such thing)

Limited (1)

Not possible - Rare (never seen such thing)

OK

Geodetic lon/lat (degrees) (e.g. EPSG:4326 / EPSG:4979)

Not working (2)

OK

Possible (but units for gsd/area are degrees)

Possible (3)

Possible (only with 3D CRS) (4)

Not working (would need transformation first)

(0) has to be 3D CRS or compound, meters (e.g. UTM / EPSG:25833+3855)
(1) ECEF and plane working mathematically but plane normal 0,0,1 makes no sense here. Will implement nonHorizontal plane soon.
(2) use as input CRS and transform to a metric CRS first, also orientation needs to be transformed
(3) using this a lot for sea-side EPSG:4326+3855 -> WGS84 (Lat/Lon) + EGM2008
(4) beware units/vertical datum, very large raster resolutions may lead to problems

Mapping#

For raster-based mapping you can trade disk IO for memory:

  • MappingRaster (default) keeps the raster on disk and reads only the needed values.

  • If you cache a window/full raster (preload_window, preload_full_raster or load_window), MappingRaster automatically uses an in-memory MappingGeorefArray backend.

Tip

With MappingRaster in default mode, you can use extremely large raster datasets (e.g. a DTM of your whole country) without loading the full raster into RAM.

from pyproj import CRS
from weitsicht import MappingRaster

mapper = MappingRaster(
    raster_path="dem.tif",
    crs=CRS.from_epsg(32633),
    preload_window=(600_000, 5_340_000, 602_000, 5_342_000),
)

# mapper.map_* now uses the cached backend
res = mapper.map_heights_from_coordinates([[601_000, 5_341_000]], crs_s=mapper.crs)

# Or cache later (returns MappingGeorefArray)
georef = mapper.load_window((600_000, 5_340_000, 602_000, 5_342_000))

Important

If you cache only a window, mapping is limited to that cached extent (outside points/rays will report Issue.OUTSIDE_RASTER).