3D Semantic Map Generation from CityGML and COLMAP

April 10, 2026 · View on GitHub

Introduction

This project provides a pipeline for generating semantic segmentation maps from CityGML models and COLMAP reconstruction results, as part of the GS4City project.

The main workflow includes:

  1. Converting CityGML to OBJ
  2. Extracting a subset COLMAP model from a full reconstruction
  3. Extracting semantic ID mappings
  4. Generating semantic maps by raycasting from OBJ and COLMAP cameras

Project Structure

Below is the required directory structure before running any scripts:

project/
├── data/
   ├── xxx/                          # full COLMAP parameter folder
   ├── undistorted/
   └── sparse/
       └── 0/
           ├── cameras.txt
           ├── images.txt
           └── points3D.txt

   └── scene_reference_frame.json
       # coordinate transform (geographic → COLMAP)
       # generated by Pix4Dmatic

   ├── model_xxx/                    # CityGML input folder
   └── *.gml                     # one or multiple CityGML files

   └── subset_xxx/
       └── undistorted/
           └── images/               # manually selected subset images
               ├── *.jpg / *.png

├── output/

├── prepare_model.py
├── prepare_colmap.py
├── prepare_gmltable.py
└── model2mask.py

Requirements

Core Software (install separately)

Python Dependencies

  • Python 3.9+
  • numpy
  • scikit-learn
  • plyfile
  • tqdm

Install Python dependencies:

pip install numpy scikit-learn plyfile tqdm

CityGML to OBJ Conversion

Script

prepare_model.py

Input

  • data/model_xxx/*.gml
  • data/xxx/scene_reference_frame.json

Function

  • merge multiple CityGML files
  • convert to CityJSON
  • apply coordinate transformation (to COLMAP system)
  • export OBJ
  • generate instance-to-CityJSON mapping

Usage

python prepare_model.py \
    --parameter_dir xxx \
    --model_dir model_xxx \
    --z_offset 45.66

Output (generated in model_xxx/)

merged.json
*.obj
id_mapping.json

Notes

  • scene_reference_frame.json is used to align CityGML to COLMAP coordinates
  • z_offset is empirically set and may require adjustment per dataset

COLMAP Sub-model Extraction

Script

prepare_colmap.py

Input

  • data/xxx/undistorted/sparse/0/
  • data/subset_xxx/undistorted/images/

Function

  • filter COLMAP model by subset images
  • keep related cameras and 3D points
  • convert to BIN format
  • export PLY point cloud
  • estimate normals

Usage

python prepare_colmap.py \
    --building_name subset_xxx \
    --parameter_dir xxx \
    --colmap_exe ".../Colmap/colmap.bat" \
    --neighbors 20

Output (generated in subset_xxx/undistorted/)

sparse_txt/
├── cameras.txt
├── images.txt
└── points3D.txt

sparse/
└── 0/
    ├── cameras.bin
    ├── images.bin
    ├── points3D.bin
    └── points3D.ply

CityJSON Semantic Extraction

Script

prepare_gmltable.py

Input

  • data/model_xxx/merged.json

Function

  • extract semantic hierarchy from CityJSON
  • flatten into a table (building / surface / part)

Usage

python prepare_gmltable.py \
    --model_dir model_xxx

Output (generated in model_xxx/)

city_semantics.json

Semantic Map Generation

Script

model2mask.py

Input

  • data/model_xxx/*.obj
  • data/subset_xxx/undistorted/sparse_txt/
  • data/subset_xxx/undistorted/images/

Function

  • load mesh + semantic labels
  • load COLMAP cameras
  • perform raycasting
  • generate semantic maps

Usage

python generate_maps.py \
    --building_name subset_xxx \
    --parameter_dir subset_xxx \
    --model_dir model_xxx \
    --level surface \
    --inst \
    --vis

Main arguments

  • --level: feature / surface / part
  • --inst: instance map or class map
  • --vis: save visualization
  • --scale: resolution scale

Output

output/<building_name>_<timestamp>/

Includes:

  • .npy semantic maps
  • .png visualization (optional)

Prerequisites

  • CityGML to OBJ Conversion
  • COLMAP Sub-model Extraction

must be completed before running this step.

Notes

  • Ensure OBJ and COLMAP are in the same coordinate system
  • Adjust z_offset if alignment is off
  • The program prints center differences for debugging
  • Semantic ID consistency is critical