[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-80840":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":8,"htmlUrl":8,"language":9,"languages":8,"totalLinesOfCode":8,"stars":10,"forks":11,"watchers":12,"openIssues":13,"contributorsCount":14,"subscribersCount":14,"size":14,"stars1d":13,"stars7d":13,"stars30d":13,"stars90d":14,"forks30d":14,"starsTrendScore":15,"compositeScore":16,"rankGlobal":8,"rankLanguage":8,"license":17,"archived":18,"fork":18,"defaultBranch":19,"hasWiki":20,"hasPages":18,"topics":21,"createdAt":8,"pushedAt":8,"updatedAt":22,"readmeContent":23,"aiSummary":24,"trendingCount":14,"starSnapshotCount":14,"syncStatus":25,"lastSyncTime":26,"discoverSource":27},80840,"geo-register-plugin","dozeri83\u002Fgeo-register-plugin","dozeri83",null,"Python",37,6,36,1,0,3,42.14,"GNU General Public License v3.0",false,"main",true,[],"2026-06-12 04:01:30","# Geo Register Plugin\n\nRegisters a [LichtFeld Studio](https:\u002F\u002Fgithub.com\u002FMrNeRF\u002FLichtFeld-Studio\u002F) scene to real-world geographic coordinates (WGS-84 \u002F ECEF).\nOnce registered, clicking any point on the model returns its latitude, longitude, and altitude.\nThe plugin can also export geo-referenced splat models as **LAS\u002FLAZ** point clouds or\n**3D Tiles 1.1** datasets (ArcGIS Gaussian Splat Layer \u002F CesiumJS).\n\n![Geo Register Plugin in action](assets\u002Fplugin_example.jpg)\n\n---\n\n## How It Works\n\nThe plugin solves a **similarity transform** that maps scene-space coordinates to\nECEF (Earth-Centered Earth-Fixed) coordinates:\n\n```\nworld_ecef = scale * R @ p_scene + translation\n```\n\nWhere:\n- `scale` — uniform scale factor between scene units and metres\n- `R` — 3x3 rotation matrix\n- `translation` — 3D translation vector in metres\n\nThe transform is estimated using a robust RANSAC + IRLS solver (Umeyama 1991),\nwhich automatically rejects outlier correspondences.\n\n---\n\n## Source Modes\n\nUse the **Source** dropdown to choose how geographic reference data is provided.\n\n---\n\n### 1. EXIF\n\nAutomatically extracts GPS coordinates embedded in the original drone\u002Fcamera images,\nmatches them to the camera poses in the loaded scene, and solves the transform.\n\n**Steps:**\n1. Load your dataset in LichtFeld Studio.\n2. Select **EXIF** from the Source dropdown.\n3. Click **Calc Georeference From EXIF**.\n\nThe plugin scans the dataset folder for images with GPS EXIF tags, matches each image\nto its camera pose by filename stem, and runs the solver.\n\n> **Original images folder:**\n> If your dataset images no longer contain GPS EXIF data (e.g. they were undistorted\n> or re-encoded), click **Set Original Images Folder** to point the plugin at the\n> folder containing your original images. The plugin will scan that folder for GPS\n> tags instead.\n> The filename **stem** (name without extension) must match between the original\n> images and the dataset cameras — for example, `DJI_0001.jpg` (original) matches\n> `DJI_0001.JPG` or `DJI_0001.png` in the dataset.\n\n> **Note:** EXIF GPS readings can be imprecise, especially in the altitude direction. For more accurate results, use professional alignment tools with GCPs (ground control points).\n\n---\n\n### 2. Similarity File\n\nLoads a previously computed similarity transform from a JSON file.\nUseful when you already have a valid transform (e.g. exported by this plugin from a\ndifferent session or computed externally).\n\n**Steps:**\n1. Select **Similarity File** from the Source dropdown.\n2. Click **Load Similarity File** and pick a `.json` file.\n\n**Expected JSON format:**\n\n```json\n{\n  \"scale\": 0.999367,\n  \"rotation\": [\n    [ 0.9998,  0.0123, -0.0156],\n    [-0.0121,  0.9998,  0.0089],\n    [ 0.0157, -0.0087,  0.9998]\n  ],\n  \"translation\": [4052845.12, 617312.45, 4867891.78]\n}\n```\n\n**Matrix composition:**\n\nThe transform applies components in this order:\n\n1. **Scale** — multiply the scene point by `scale`\n2. **Rotate** — apply the 3x3 rotation matrix `R`\n3. **Translate** — add the `translation` vector\n\nIn matrix form as a 4x4 homogeneous transform:\n\n```\n| scale*R  translation |   @   | x |       | x_ecef |\n|    0          1      |       | y |   =   | y_ecef |\n                               | z |       | z_ecef |\n                               | 1 |       |   1    |\n```\n\nThe plugin exports this JSON automatically after every EXIF or CSV solve, to\n`\u003Coutput_dir>\u002Fgeo_register_plugin_data\u002Fsimilarity_transform.json`.\n\n---\n\n### 3. Image Positions CSV\n\nLoads image GPS positions from a CSV file and runs the same solver as the EXIF mode.\nUseful when GPS data is not embedded in the images (e.g. stored separately by the\ndrone flight controller, or sourced from a ground control point log).\n\n**Steps:**\n1. Select **Image Positions CSV** from the Source dropdown.\n2. Click **Load CSV File** and pick a `.csv` file.\n\n**Required CSV format:**\n\nThe file must have a header row with these column names (in any order):\n\n```\nimage_name,lat,lon,alt\nDJI_0001.JPG,32.08154321,34.78912345,48.250\nDJI_0002.JPG,32.08163897,34.78924561,48.431\nDJI_0003.JPG,32.08172450,34.78937812,48.619\nDJI_0004.JPG,32.08181023,34.78951034,48.802\n```\n\n- `image_name` — filename only, with extension (not a full path)\n- `lat` — latitude in decimal degrees (WGS-84)\n- `lon` — longitude in decimal degrees (WGS-84)\n- `alt` — ellipsoidal altitude in metres\n\nThe plugin exports this CSV automatically after every EXIF solve, to\n`\u003Coutput_dir>\u002Fgeo_register_plugin_data\u002Fimage_positions.csv`.\n\n---\n\n### 4. RealityScan Parameters CSV\n\n> **Recommended over EXIF when you aligned your data with RealityScan.**\n>\n> RealityScan performs bundle adjustment that refines each camera's position beyond\n> the raw GPS reading. Importing these adjusted positions instead of raw EXIF gives\n> significantly better geo-registration accuracy, because the plugin fits the\n> similarity transform to coordinates that are already internally consistent with\n> the reconstructed model. Expect a noticeably lower RMSE compared to EXIF mode.\n\n**How to export from RealityScan:**\n\n**Step 1 — Set the project output coordinate system to WGS 84:**\n\nGo to **Workflow → Settings → Coordinate System** and set the output coordinate\nsystem to **EPSG:4326 – GPS WGS 84**.\n\n![RealityScan project coordinate system setting](assets\u002Frs_project_setting.png)\n\n**Step 2 — Export Internal\u002FExternal Camera Parameters:**\n\nIn the export dialog, choose **Internal\u002FExternal Camera Parameters**.\nIn the export settings, set the coordinate system to **Project Output**.\n\n![RealityScan export settings](assets\u002Frs_export_settings.png)\n\n> **Important — Colmap export:** The output coordinate system setting is **global** for\n> all RealityScan exports. If you later export to **Colmap** format, you must change it\n> back to **Grid Plane \u002F Local Euclidean** — Colmap expects Euclidean (non-geographic)\n> coordinates, and leaving it set to EPSG:4326 will produce incorrect results.\n>\n> ![RealityScan Colmap export coordinate system setting](assets\u002Frc_export_colmap_settings.png)\n\n**Step 3 — Load in the plugin:**\n\n1. Select **RealityScan Parameters CSV** from the Source dropdown.\n2. Click **Load RealityScan CSV** and pick the exported `.csv` file.\n\n**CSV format (exported by RealityScan):**\n\n```\n#name,x,y,alt,yaw,pitch,roll,f_35mm,px_norm,py_norm,k1,k2,k3,k4,t1,t2\nDJI_0214.JPG,-34.82878738,7.16331052,86.94,131.99,...\n```\n\n- `name` — image filename\n- `x` — longitude (decimal degrees, WGS-84)\n- `y` — latitude (decimal degrees, WGS-84)\n- `alt` — ellipsoidal altitude in metres\n\nAll other columns (yaw, pitch, roll, lens parameters) are ignored by the plugin.\n\n---\n\n### 5. Metashape Cameras XML\n\nLoads camera GPS positions from an Agisoft Metashape camera XML export and runs\nthe same solver as the CSV modes.\n\n**How to export from Metashape:**\n\n1. In Metashape, make sure the chunk's **coordinate system** is set to **WGS 84 (EPSG:4326)**.\n2. Go to **File → Export → Export Cameras…** and save as XML.\n\n**Steps in the plugin:**\n\n1. Select **Metashape Cameras XML** from the Source dropdown.\n2. Click **Load Metashape Cameras XML** and pick the exported `.xml` file.\n\n**Requirements:**\n\n- The chunk CRS must be **GEOGCS \u002F EPSG:4326**. Chunks with any other CRS\n  (projected, geocentric, or local) are skipped with a warning.\n- Cameras with `enabled=\"0\"` on their `\u003Creference>` tag are skipped.\n- Multiple chunks in the same file are all processed and merged.\n\n> **Note — naive parsing:**\n> The parser reads GPS coordinates directly from the `\u003Creference>` attribute of each\n> `\u003Ccamera>` element. It assumes that this tag is present and populated with GPS data —\n> which is the case when cameras were imported with GPS coordinates in Metashape's\n> Reference pane. If a camera was added without GPS data, its `\u003Creference>` tag will\n> be absent and that camera will simply be skipped.\n>\n> Before loading, you can verify your file contains reference data by checking that\n> individual `\u003Ccamera>` entries include a `\u003Creference>` tag with `x`, `y`, `z`\n> attributes, for example:\n> ```xml\n> \u003Ccamera id=\"3\" sensor_id=\"0\" label=\"DJI_0003.JPG\" enabled=\"1\">\n>   \u003Ctransform>...\u003C\u002Ftransform>\n>   \u003Creference x=\"8.71105718333333\" y=\"50.1547084833333\" z=\"195.665\"\n>              yaw=\"...\" pitch=\"0\" roll=\"0\" enabled=\"1\"\u002F>\n> \u003C\u002Fcamera>\n> ```\n> Here `x` = longitude, `y` = latitude, `z` = altitude in metres (WGS-84).\n\n---\n\n## Output Files\n\nAfter a successful solve the plugin writes to `\u003Coutput_dir>\u002Fgeo_register_plugin_data\u002F`:\n\n| File | Description |\n|---|---|\n| `similarity_transform.json` | The solved transform (scale, R, t, RMSE, inlier counts) |\n| `similarity_transform_info.txt` | Human-readable explanation of the transform fields |\n| `image_positions.csv` | GPS positions of all matched images (EXIF and CSV modes) |\n\n---\n\n## Configuration\n\nThe plugin reads `config.json` from its root directory at runtime. All keys are optional;\nthe defaults below are used when a key is absent or the file does not exist.\n\n```json\n{\n  \"las_export_coordinates\": \"UTM\",\n\n  \"ransac_inlier_thr_m\": 10.0,\n  \"ransac_confidence\":    0.99,\n  \"ransac_max_iter\":      2000,\n  \"irls_huber_delta_m\":   2.0,\n  \"irls_max_iter\":        50\n}\n```\n\n| Key | Default | Description |\n|---|---|---|\n| `las_export_coordinates` | `\"UTM\"` | Output CRS for LAS\u002FLAZ export: `\"UTM\"` or `\"LLA\"` (EPSG:4326) |\n| `ransac_inlier_thr_m` | `10.0` | RANSAC inlier threshold in metres — correspondences with a larger residual are rejected as outliers |\n| `ransac_confidence` | `0.99` | Target probability that RANSAC finds the correct model; drives the adaptive iteration count |\n| `ransac_max_iter` | `2000` | Hard cap on RANSAC iterations regardless of the adaptive estimate |\n| `irls_huber_delta_m` | `2.0` | Huber loss delta (metres) for IRLS refinement — points below this residual receive full weight |\n| `irls_max_iter` | `50` | Maximum IRLS iterations |\n\n> **Tuning tips:**\n> - Increase `ransac_inlier_thr_m` if your GPS data is noisy (e.g. consumer-grade EXIF) and the solver rejects too many correspondences.\n> - Decrease it when you have RTK-quality GPS and want stricter outlier rejection.\n> - `irls_huber_delta_m` should be smaller than `ransac_inlier_thr_m` — a good rule of thumb is roughly ¼ of the inlier threshold.\n\n---\n\n## Export\n\nOnce geo-registration is complete, the plugin can export any splat model visible in the\nscene as a geo-referenced point cloud file.\n\nThe export section appears at the bottom of the panel. Use the **Splat Model** dropdown\nto select which model to export, choose the output format, then click **Export LAS\u002FLAZ**.\nA save dialog opens with the splat name pre-filled as the filename. The last exported\npath is shown in the panel for reference.\n\n### LAS — LASer file format\n\nLAS is the industry-standard binary format for point cloud data, maintained by the\n[ASPRS](https:\u002F\u002Fwww.asprs.org\u002Fdivisions-committees\u002Flidar-division\u002Flaser-las-file-format-exchange-activities).\nThe plugin writes **LAS 1.4, point format 7** (XYZ + RGB colour).\n\nThe output coordinate system is controlled by `las_export_coordinates` in `config.json`\n(see [Configuration](#configuration)):\n\n| Setting | CRS | X | Y | Z |\n|---|---|---|---|---|\n| `\"UTM\"` *(default)* | WGS-84 \u002F UTM zone auto-selected from point-cloud median | Easting (m) | Northing (m) | Ellipsoidal height (m) |\n| `\"LLA\"` | EPSG:4326 geographic | Longitude (°) | Latitude (°) | Ellipsoidal height (m) |\n\nWhen `UTM` is selected:\n- The UTM zone is determined from the **median latitude and longitude** of the exported\n  point cloud — a robust centroid that ignores outliers.\n- Northern\u002Fsouthern hemisphere is set automatically from the sign of the median latitude.\n- The EPSG code is derived accordingly (e.g. `EPSG:32636` for UTM zone 36N).\n\nFor both modes:\n- An **OGC WKT CRS record** is embedded in the file header so any compliant GIS tool\n  (QGIS, ArcGIS, CloudCompare, etc.) can read the coordinate system automatically.\n- Gaussian splat positions are transformed from scene space to ECEF using the solved\n  similarity transform, then converted to WGS-84 geodetic coordinates.\n- Colour is taken from the first spherical harmonics band (DC term), packed as\n  16-bit per channel RGB.\n\n### LAZ — Compressed LAS\n\nLAZ is a losslessly compressed variant of LAS. The point data and CRS metadata are\nidentical to LAS; only the storage is compressed using the\n[LASzip](https:\u002F\u002Flaszip.org\u002F) algorithm.\n\n- File sizes are typically **5–10× smaller** than the equivalent LAS file.\n- All major GIS tools that support LAS also support LAZ.\n- Requires the `lazrs` or `laszip` Python package in the plugin environment\n  (installed automatically with the plugin dependencies).\n\n### 3D Tiles\n\n![3D Tiles export in ArcGIS](assets\u002F3dtiles_example.png)\n\nThe plugin can export the splat model as a georeferenced **3D Tiles 1.1** dataset\nthat renders as full Gaussian splats (not a point cloud).\n\n**Output files:**\n\n```\nout_dir\u002F\n  tileset.json   # 3D Tiles 1.1 manifest\n  splats.glb     # Binary glTF — SPZ-compressed splat data in the BIN chunk\n```\n\n**Tileset structure:**\n\n```\nroot  (no transform — ECEF bounding volume only)\n└── child  (similarity transform: local → ECEF)\n      └── content: splats.glb\n```\n\nThe similarity transform computed by the geo-registration is embedded directly\nas the child tile's `transform`, placing the splat cloud at the correct ECEF\nposition on Earth.\n\n**Format details:**\n\n| Property | Value |\n|---|---|\n| 3D Tiles version | 1.1 |\n| glTF extension | `KHR_gaussian_splatting` + `KHR_gaussian_splatting_compression_spz_2` |\n| Compression | SPZ v3 (gzipped), ~17 bytes\u002Fsplat for SH degree 3 |\n| SH bands | Up to degree 3 (full view-dependent colour) |\n| Tested on | ArcGIS Maps SDK 5.0 — should also work on CesiumJS ≥ 1.139 and ArcGIS Pro ≥ 3.6 |\n\n**[`KHR_gaussian_splatting`](https:\u002F\u002Fgithub.com\u002FKhronosGroup\u002FglTF\u002Ftree\u002Fmain\u002Fextensions\u002F2.0\u002FKhronos\u002FKHR_gaussian_splatting)**\nis a ratified Khronos glTF 2.0 extension for embedding 3D Gaussian Splat data inside\na standard glTF\u002FGLB asset. It defines per-primitive attributes for position, rotation,\nscale, opacity, and spherical harmonic coefficients, with a companion compression\nextension (`KHR_gaussian_splatting_compression_spz_2`) that wraps the payload in an\nSPZ blob.\n\n**SPZ (Splat Zip) v3** is an open binary format for compact Gaussian splat storage,\ndeveloped by [Niantic Labs](https:\u002F\u002Fgithub.com\u002Fnianticlabs\u002Fspz) (MIT licence).\nIt encodes positions, rotations, scales, opacity, and spherical harmonic coefficients\ninto a single gzipped binary blob (~17 bytes\u002Fsplat at SH degree 3, roughly 14× smaller\nthan the source PLY). The encoder used here is a pure-Python implementation that mirrors\nthe Niantic reference byte-for-byte.\n\n---\n\n## No Scene Plugin Functionality\n\nWhen LichtFeld Studio is in **Edit Mode** (no scene loaded), geo-registration is not\npossible because there are no camera poses to fit the similarity transform against.\n\nHowever, the plugin remains useful: if you already have a **pre-calculated similarity\nmatrix** (computed during a previous session while a scene was loaded), you can still\nconvert any 3DGS PLY file to a geo-referenced export format without reloading the scene.\n\n> **Important:** the similarity matrix must have been calculated with a scene still\n> loaded in LichtFeld Studio. You cannot compute it in Edit Mode.\n\n**Steps:**\n\n1. Switch to **Edit Mode** in LichtFeld Studio (or open it without a scene).\n2. The Geo Register Plugin panel automatically switches to **PLY → Geo Export** mode.\n3. Click **Pick PLY File** and select your 3DGS `.ply` file.\n4. Click **Pick Similarity JSON** and select the pre-calculated `similarity_transform.json`.\n5. Once both files are selected, choose the output **Format** and export destination.\n6. Click **Export** — the plugin converts the PLY directly to the chosen format\n   (LAS, LAZ, or 3D Tiles) using the stored similarity transform.\n\nThe similarity JSON format is the same as described in the [Similarity File](#2-similarity-file)\nsource mode section above. The plugin exports this file automatically to\n`\u003Coutput_dir>\u002Fgeo_register_plugin_data\u002Fsimilarity_transform.json` after every successful solve.\n","Geo Register Plugin 是一个用于将LichtFeld Studio场景注册到真实世界地理坐标（WGS-84 \u002F ECEF）的插件。其核心功能包括通过相似变换将场景空间坐标映射到地球固定坐标系，支持从EXIF数据或预计算的相似性文件中获取地理参考信息，并能够导出为LAS\u002FLAZ点云或3D Tiles 1.1格式的数据集。该插件使用鲁棒的RANSAC+IRLS求解器来估计变换参数，自动排除异常对应关系。适用于需要将虚拟场景与现实地理位置精确对齐的应用场合，如地理信息系统开发、虚拟现实环境构建等。",2,"2026-06-11 04:02:31","CREATED_QUERY"]