A precise PPK + MRK-based geotagging tool for DJI RTK drones
This Python library enables centimetre-level camera geotagging by combining PPK .pos solutions, DJI .MRK gimbal offset corrections, and EXIF/XMP metadata from DJI RTK drone images. It is designed for photogrammetry and remote sensing workflows that require accurate EOPs.
- Batch process
.obsraw GNSS logs into RINEX and perform PPK with RTKLIB - Download precise ephemeris data (SP3/CLK) automatically
- Parse DJI
.MRKand interpolate correction vectors to camera center (ECEF) - Match images by GPS time, apply PPK + MRK correction with covariance propagation
- Export geotagged results in ECEF/ENU/UTM with estimated 3D precision
- Support for DJI P1, M300, and other RTK-enabled drones
git clone https://github.com/RayPan-UC/dji-geotagger.git
pip install dji-geotagger- Python ≥ 3.9
pillow,defusedxml,pandas,numpy,pyproj,tqdm- RTKLIB (
convbin.exe,rnx2rtkp.exe)
- Convert raw GNSS to RINEX Uses RTKLIB
convbinfor both base and rover logs. - Download precise IGS ephemeris Automatically fetch
.sp3and.clkbased on RINEX timestamps. - Run PPK Batch PPK processing using
rnx2rtkpwith optional override base coordinates from PPP.sumfile. - Parse image EXIF/XMP metadata Extracts capture time, attitude, and gimbal orientation.
- Parse MRK files Converts NED to ENU, then ENU to ECEF correction vectors.
- Interpolate camera centre Matches MRK by time, interpolates PPK positions, applies gimbal offset.
- Export results Generates a DataFrame (or CSV) of corrected positions and attitude per image.
from pathlib import Path
from pyproj import CRS
from dji_geotagger import *
# === User-defined project path ===
project_root = Path(r"/path/to/your/project/SynopticSite1")
# === Clean temporary directories ===
clean_temp_dirs()
# === Convert base and rover raw logs to RINEX ===
rover_dir = raw_to_rinex_batch(
keywords=['20250513', 'PPKRAW', '.bin'],
input_dir=project_root,
type="rover"
)
base_obs, base_nav = raw_to_rinex_batch(
keywords=['20250513', '0006', 'DRTK', '.dat'],
input_dir=project_root,
type="base",
)
# === Pause here to process base .sum file if available ===
ppp_sum_file = pause_for_PPP_sum_file()
# === Post-process PPK with base .sum file ===
process_ppk(
base_obs=base_obs,
base_nav=base_nav,
rover_dir=rover_dir,
override_base_from_sum_file=ppp_sum_file,
output_dir=Path("temp/ppk_result"),
)
# === Compute corrected camera positions ===
final_df = load_and_compute_camera_positions(
mrk_dir=project_root,
img_dir=project_root,
pos_dir=Path("temp/ppk_result"),
base_sum_file=ppp_sum_file
)
# === Transform to target coordinate system (e.g., WGS84/UTM) ===
target_crs = 32612
final_df = transform_coordinates(
final_df,
target_crs=CRS.from_user_input(target_crs),
out_x="Easting",
out_y="Northing",
out_z="Height_Ellp",
cov_ecef2enu=True,
drop_original=True
)
# === Save result as CSV ===
save_csv(final_df)The output CSV contains the following columns:
| Column Name | Description |
|---|---|
file_name |
Image file name |
gps_week |
GPS week number |
gps_time |
Seconds into the GPS week |
sd_x_ecef |
Standard deviation in ECEF X (metres) |
sd_y_ecef |
Standard deviation in ECEF Y (metres) |
sd_z_ecef |
Standard deviation in ECEF Z (metres) |
cov_ecef_flat |
Flattened 3×3 ECEF covariance matrix (row-major, space-separated) |
flight_roll |
Aircraft body roll (degrees) |
flight_pitch |
Aircraft body pitch (degrees) |
flight_yaw |
Aircraft body yaw (degrees) |
gimbal_roll |
Gimbal-reported roll (degrees) |
gimbal_pitch |
Gimbal-reported pitch (degrees) |
gimbal_yaw |
Gimbal-reported yaw (degrees) |
dji_geotagger_roll |
Corrected camera roll for photogrammetry (degrees), with gimbal lock handling |
dji_geotagger_pitch |
Corrected camera pitch for photogrammetry (degrees), computed as gimbal_pitch + 90 |
dji_geotagger_yaw |
Camera yaw for photogrammetry (degrees), taken directly from flight_yaw |
Easting |
Easting in WGS84 / UTM Zone 12N (metres) |
Northing |
Northing in WGS84 / UTM Zone 12N (metres) |
Height_Ellp |
Height in WGS84 ellipsoidal coordinates (metres) |
sd_E |
Standard deviation in Easting (ENU, metres) |
sd_N |
Standard deviation in Northing (ENU, metres) |
sd_U |
Standard deviation in Up (ENU, metres) |
cov_enu_flat |
Flattened 3×3 ENU covariance matrix (row-major, space-separated) |
Note: The projected coordinates (Easting, Northing, Height) are output in WGS84 / UTM Zone 12N by default. Users can customize the coordinate reference system (CRS) and output column formats according to their project requirements.
This project is licensed under the BSD 2-Clause (see LICENSE for details).
- Developed at the University of Calgary, Applied Geospatial Research Group (appliedgrg.ca)
- Inspired by real-world field workflows involving DJI Matrice 350 RTK + Zenmuse P1, Hemisphere base stations, and CSRS-PPP post-processing