动态

详情 返回 返回

3D Gaussian splatting 04: 代碼閲讀-提取相機位姿和稀疏點雲 - 动态 详情

目錄

  • 3D Gaussian splatting 01: 環境搭建
  • 3D Gaussian splatting 02: 快速評估
  • 3D Gaussian splatting 03: 用户數據訓練和結果查看
  • 3D Gaussian splatting 04: 代碼閲讀-提取相機位姿和稀疏點雲
  • 3D Gaussian splatting 05: 代碼閲讀-訓練整體流程
  • 3D Gaussian splatting 06: 代碼閲讀-訓練參數
  • 3D Gaussian splatting 07: 代碼閲讀-訓練載入數據和保存結果
  • 3D Gaussian splatting 08: 自建模型展示網頁

代碼閲讀: 預處理階段

convert.py 用於從幀系列中提取相機參數, 相機位姿和對象特徵點的稀疏點雲, 從 convert.py 的代碼可以看到轉換階段的處理流程:

1. 3D稀疏點雲重建

## Feature extraction
feat_extracton_cmd = colmap_command + " feature_extractor "\
   "--database_path " + args.source_path + "/distorted/database.db \
   --image_path " + args.source_path + "/input \
   --ImageReader.single_camera 1 \
   --ImageReader.camera_model " + args.camera + " \
   --SiftExtraction.use_gpu " + str(use_gpu)
exit_code = os.system(feat_extracton_cmd)
if exit_code != 0:
   logging.error(f"Feature extraction failed with code {exit_code}. Exiting.")
   exit(exit_code)

## Feature matching
feat_matching_cmd = colmap_command + " exhaustive_matcher \
   --database_path " + args.source_path + "/distorted/database.db \
   --SiftMatching.use_gpu " + str(use_gpu)
exit_code = os.system(feat_matching_cmd)
if exit_code != 0:
   logging.error(f"Feature matching failed with code {exit_code}. Exiting.")
   exit(exit_code)

### Bundle adjustment
# The default Mapper tolerance is unnecessarily large,
# decreasing it speeds up bundle adjustment steps.
mapper_cmd = (colmap_command + " mapper \
   --database_path " + args.source_path + "/distorted/database.db \
   --image_path "  + args.source_path + "/input \
   --output_path "  + args.source_path + "/distorted/sparse \
   --Mapper.ba_global_function_tolerance=0.000001")
exit_code = os.system(mapper_cmd)
if exit_code != 0:
   logging.error(f"Mapper failed with code {exit_code}. Exiting.")
   exit(exit_code)

提取流程

  1. 特徵點提取 feature_extractor
    生成每一幀的特徵點
  2. 特徵匹配 exhaustive_matcher
    圖像間匹配的特徵點對, 建立2D-2D幾何約束
  3. 稀疏三維重建 mapper
    生成相機位姿 + 稀疏3D點雲, 通過SfM恢復3D結構和相機運動

説明

  • 相機模型參數camera_model, 默認使用的是OPENCV
  • skip_matching參數可以跳過這個步驟, 這個階段生成的數據會保存在 distorted 目錄下, 這是用 colmap 直接處理產生的結果

2. 圖像去畸變

### Image undistortion
## We need to undistort our images into ideal pinhole intrinsics.
img_undist_cmd = (colmap_command + " image_undistorter \
    --image_path " + args.source_path + "/input \
    --input_path " + args.source_path + "/distorted/sparse/0 \
    --output_path " + args.source_path + "\
    --output_type COLMAP")
exit_code = os.system(img_undist_cmd)
if exit_code != 0:
    logging.error(f"Mapper failed with code {exit_code}. Exiting.")
    exit(exit_code)

將上一步生成的文件, 使用colmap image_undistorter處理後輸出到 sparse 目錄, 最後移動到 sparse/0 目錄下.

image_undistorter 涉及的處理包含

  • 去畸變 Undistortion: 根據相機的內參和畸變係數(通常來自 database.dbcameras.txt), 對原始圖像進行去畸變處理, 在images目錄下生成無畸變的圖像
  • 圖像重投影: 將原始圖像重新投影到新的虛擬相機座標系下, 確保去畸變後的圖像儘可能保持直線性和幾何一致性, 新產生的稀疏重建數據輸出到 sparse 目錄下.
output/
├── images/               # 去畸變後的圖像, 文件名與原始圖像一致, 但內容已去除畸變
├── sparse/               # 稀疏重建數據(適配去畸變後的圖像)
│   ├── cameras.bin       # 更新後的相機內參(去除了畸變參數, 通常為 `SIMPLE_PINHOLE` 或 `PINHOLE` 模型)
│   ├── images.bin        # 更新後的圖像位姿
│   └── points3D.bin      # 3D點雲數據(與原始稀疏模型一致)

3. 生成小尺寸圖片

source_file = os.path.join(args.source_path, "images", file)

destination_file = os.path.join(args.source_path, "images_2", file)
shutil.copy2(source_file, destination_file)
exit_code = os.system(magick_command + " mogrify -resize 50% " + destination_file)

如果指定了resize參數, 則將images中的圖片序列按 1/2, 1/4, 1/8 大小壓縮後放到對應的 images_2, images_4, images_8 目錄下.

提取結果數據結構

在Convert階段, 使用Colmap處理輸入幀序列, 在3D場景的稀疏重建完成後, model 默認會被導出到 bin 文件中, 因為這樣比較緊湊, 節省空間, 在結果目錄中生成以下文件

  • cameras.bin: 相機內參(焦距、畸變係數等)
  • images.bin: 每張圖像的外參(旋轉矩陣、平移向量)
  • points3D.bin: 稀疏三維點雲(座標、顏色、關聯的圖像特徵)

二進制文件不能直接查看, 如果要查看需要先導出為文本形式

模型導出為文本

界面方式

  1. File -> Open Project, 選擇 distorted/sparse/0/project.ini
    project.ini 裏面有結果數據集 database_path, image_path 對應的路徑
  2. Import Model
    彈出窗口會顯示 cameras.bin, frames.bin, images.bin, points3D.bin 這些文件所在的目錄, 直接點Open
  3. Export Model as Text
    選擇目錄導出

界面方式需要先有個 project.ini 才能打開然後才能導出, 對於 image_undistorter 之後的數據, 可以直接用命令行

colmap model_converter --input_path ./sparse/0  --output_path ./export  --output_type TXT

相機參數 cameras.txt

分別將 distorted/sparse/0 和 sparse/0 下面的文件導出對比一下,

這個是 distorted 的

# Camera list with one line of data per camera:
#   CAMERA_ID, MODEL, WIDTH, HEIGHT, PARAMS[]
# Number of cameras: 1
1 OPENCV 1366 768 1293.8711353466817 1286.2774515116257 683 384 0.061212269737348043 -0.0680218 70521804764 0.0027510647480376441 -0.00096792591781855999

從參數可以看到, 只有1個相機, 類型為 OPENCV, 寬1366, 高768, 後面的對應OPENCV的參數為fx, fy, cx, cy, k1, k2, p1, p2, 參數説明在這裏 sensor models opencv camera_calibration_and_3d_reconstruction

這個是 sparse 的,

# Camera list with one line of data per camera:
#   CAMERA_ID, MODEL, WIDTH, HEIGHT, PARAMS[]
# Number of cameras: 1
1 PINHOLE 1342 753 1293.8711353466817 1286.2774515116257 671 376.5

可以看到 image_undistorter 處理後, 將相機類型簡化為 PINHOLE 了. 寬1342, 高753, 後面對應PINHOLE參數fx, fy, cx, cy.

稀疏三維點雲 points3D.txt

每一行代表3D世界座標系中的一個點, 每一行的數據記錄的是每個特徵點的編號, 在世界座標系中的三軸座標, 顏色, 誤差, 對應的幀ID(有多個)等

# 3D point list with one line of data per point:
#   POINT3D_ID, X, Y, Z, R, G, B, ERROR, TRACK[] as (IMAGE_ID, POINT2D_IDX)
# Number of points: 95681, mean track length: 6.0265674480826918
1 -4.6429054040200315 -0.12682166809568018 5.4170983660932128 163 177 139 0.36651172613355359 91 228 97 1097  1 1084  2 1041  3 1098
2 -2.8858762120805075 -0.14464560656096839 9.1629341058577598 151 128 96  0.39002500983496419 91 963 97 1371 94 6903 93 6795 92 1260 1 1467 98 7488 90 847 89 938 86 1686
3 -2.0084821657841556 -0.081920789643777775 8.8585159154051105 138 105 91 0.41792357452137563 91 1080 97 1389 95 1376 94 1289 93 1292 92 1327 99 1553 100 1585 103 935 104 972 106 1279
 105 1269

幀位姿信息信息 frames.txt

每行記錄對應一幀, 用於描述每一幀圖像的相機姿態, 即相機在世界座標系下的位置和旋轉.

# Frame list with one line of data per frame:
#   FRAME_ID, RIG_ID, RIG_FROM_WORLD[QW, QX, QY, QZ, TX, TY, TZ], NUM_DATA_IDS, DATA_IDS[] as (SENSOR_TYPE, SENSOR_ID, DATA_ID)
# Number of frames: 106
1 1 0.99836533904705349 0.04193352296417753 0.038821862334836317 0.0010452014780679608 -0.25128396315431845 -1.2152713376026862 3.0253864464155615 1 CAMERA 1 1
2 1 0.99835087534385147 0.042428195611485663 0.038620024616921315 -0.00196764222042955 -0.13775248425073805 -1.2180580685699627 3.0103416379580277 1 CAMERA 1 2
3 1 0.99855111805603081 0.043597372641527229 0.024544817561746674 -0.019811250810262224 -0.040750492657603658 -1.2271622331366634 3.0046993738476142 1 CAMERA 1 3

其中

  • FRAME_ID: 幀ID,
  • RIG_ID: 相機系統ID, 單相機時為 1
  • RIG_FROM_WORLD: 此相機相對於世界座標系的位姿(旋轉 + 平移)
    • [QW, QX, QY, QZ]: 四元數(Quaternion)表示從世界座標系 到 相機座標系 的旋轉
    • [TX, TY, TZ]: 平移向量, 表示相機在世界座標系中的位置
  • NUM_DATA_IDS: 關聯的數據條目數量(1 表示單相機)
  • DATA_IDS[]
    • SENSOR_TYPE: 傳感器類型
    • SENSOR_ID: 傳感器ID
    • DATA_ID: 數據ID, 與 FRAME_ID 一致

如果要將世界座標系中的點轉換到相機座標系, 公式為如下, 其中 \(R\) 是四元數對應的旋轉矩陣, \(T\) 是平移向量

\[P_camera = R * P_world + T \]

幀位姿和 2D 到 3D 的點對應關係 images.txt

從一開始的註釋可以看到, 總共有106幀, 平均每幀有 5439.9 個特徵點. 每一幀對應兩行數據, 因為第二行數據特別長, 這裏只選了第一幀, 且第二行只複製了一部分

# Image list with two lines of data per image:
#   IMAGE_ID, QW, QX, QY, QZ, TX, TY, TZ, CAMERA_ID, NAME
#   POINTS2D[] as (X, Y, POINT3D_ID)
# Number of images: 106, mean observations per image: 5439.8867924528304
1 0.99836533904705349 0.04193352296417753 0.038821862334836317 0.0010452014780679608 -0.25128396315431845 -1.2152713376026862 3.0253864464155615 1 00001.png
825.15373304728928 -5.6413415027986957 -1 164.01311518616183 -3.143878378690431 -1 234.84114206197438 -3.2774780931266605 -1 410.44616170102927 -4.4760000788289176 -1 410.44616170102927 -4.4760000788289176 -1 498.88078573599353 -4.4877569648373878 -1 569.35841783248441 -5.1971020964857075 -1 100.7993779156044 -2.2199628505093756 -1 356.56707555817059 -3.3454093456278997 -1 448.63533653913873 -3.8738229730629996 -1 448.63533653913873 -3.8738229730629996 -1 3.8371802816758418 -1.3898702174245159 -1 14.528644520511875 -1.3897672966739947 -1 14.528644520511875 -1.3897672966739947 -1 58.303840482829514 -1.6884535247444319 -1 183.3108855651688 -2.0632513592141777 -1 225.6034102754262 -2.3950756662687809 -1 225.6034102754262 -2.3950756662687809 -1 379.73286273610427 -3.4805414725628907 -1 379.73286273610427 -3.4805414725628907 -1 19.916327860588694 -1.2292769819643468 -1 19.916327860588694 -1.2292769819643468 10907 79.77255155967282 -1.4162716901826116 -1 238.963680618659 -2.0952003476307937 -1 247.31417122505815 -1.9649340021943544 -1 284.2464937295465 -2.3623328654380202 -1 306.65943761573396 -2.2745898954538575 -1 542.61914847275943 -3.5028586005029183 -1 581.95785661473622 -3.3856713839217605 -1 581.95785661473622 -3.3856713839217605 -1 815.63607208237715 -3.4239040200370709 -1 288.53829875350897 -1.9195248965336305 -1 1166.9736271841496 -1.7695890660907594 ...

第一行是圖像位姿和元信息, 和 frames.txt 中的數據是一致的

  • IMAGE_ID: 幀ID
  • QW, QX, QY, QZ, TX, TY, TZ: 四元數旋轉向量和平移向量, 參考上面 frames.txt 的説明
  • CAMERA_ID**:相機ID, 對應cameras.txt中的相機數據
  • NAME: 幀對應的文件名, 00001.png

第二行是 2D 特徵點與 3D 點的對應關係

POINTS2D[] as (X, Y, POINT3D_ID)
  • X, Y: 特徵點在圖像中的 歸一化座標, 通常以相機光心為原點, 可能與像素座標不同
  • POINT3D_ID: 關聯的 3D 點 ID, 對應 points3D.txt中的點, -1表示該 2D 點未關聯到任何 3D 點, 可能是由於匹配失敗或三角化置信度低

Add a new 评论

Some HTML is okay.