banner
Fr4nk

Hello! Fr4nk

瞎折腾第一名🥇

3DGSトレーニング用Blenderデータセット

3DGSは Blender データセットのトレーニングをサポートしており、主なデータ形式は以下の通りです:

<location>
|---images
|   |---<image 0>
|   |---<image 1>
|   |---...
|---transformers_train.json
|---point3d.ply

データ準備#

通常、私たちが収集するデータセットはレーザースキャン装置から来ており、las 形式の点群ファイル、json 形式のカメラポーズ、および画像を提供します。

まず、las 形式の点群ファイルを処理し、バイナリの ply ファイルに変換する必要があります。

次に、transformers_train.json ファイルを確認し、主に 3dgs コードファイルの /sence/dataset_readers.py を対象に修正します。

def readNerfSyntheticInfo(path, white_background, eval, extension=".jpg"):
    print("トレーニング変換を読み込み中")
    train_cam_infos = readCamerasFromTransforms(path, "transforms_train.json", white_background, extension)
    #print("テスト変換を読み込み中")
    #test_cam_infos = readCamerasFromTransforms(path, "transforms_test.json", white_background, extension)
    
    #if not eval:
    #    train_cam_infos.extend(test_cam_infos)
    #    test_cam_infos = []
    test_cam_infos = []
    nerf_normalization = getNerfppNorm(train_cam_infos)

    ply_path = os.path.join(path, "points3d.ply")
    if not os.path.exists(ply_path):
        # このデータセットにはcolmapデータがないため、ランダムポイントから始めます
        num_pts = 100_000
        print(f"ランダム点群を生成中 ({num_pts})...")
        
        # 合成Blenderシーンの範囲内にランダムポイントを作成します
        xyz = np.random.random((num_pts, 3)) * 2.6 - 1.3
        shs = np.random.random((num_pts, 3)) / 255.0
        pcd = BasicPointCloud(points=xyz, colors=SH2RGB(shs), normals=np.zeros((num_pts, 3)))

        storePly(ply_path, xyz, SH2RGB(shs) * 255)
    try:
        pcd = fetchPly(ply_path)
    except:
        pcd = None

    scene_info = SceneInfo(point_cloud=pcd,
                           train_cameras=train_cam_infos,
                           test_cameras=test_cam_infos,
                           nerf_normalization=nerf_normalization,
                           ply_path=ply_path)
    return scene_info

Test Transforms に関連する部分はコメントアウトされており、eval は行われないため、テストは不要です。extension を変更し、主に自分の画像入力形式を確認します。

def readCamerasFromTransforms(path, transformsfile, white_background, extension=".jpg"):
    cam_infos = []

    with open(os.path.join(path, transformsfile)) as json_file:
        contents = json.load(json_file)
        fovx = contents["camera_angle_x"]

        frames = contents["frames"]
        for idx, frame in enumerate(frames):
            cam_name = os.path.join(path,"images", frame["file_path"])

            # NeRFの'transform_matrix'はカメラから世界への変換です
            c2w = np.array(frame["transform_matrix"])
            # OpenGL/Blenderカメラ軸(Y上、Z後ろ)からCOLMAP(Y下、Z前)に変更します
            c2w[:3, 1:3] *= -1

            # 世界からカメラへの変換を取得し、R、Tを設定します
            w2c = np.linalg.inv(c2w)
            R = np.transpose(w2c[:3,:3])  # RはCUDAコードの'glm'のため転置されて保存されています
            T = w2c[:3, 3]

            image_path = os.path.join(path, cam_name)
            image_name = Path(cam_name).stem
            image = Image.open(image_path)

            im_data = np.array(image.convert("RGBA"))

            bg = np.array([1,1,1]) if white_background else np.array([0, 0, 0])

            norm_data = im_data / 255.0
            arr = norm_data[:,:,:3] * norm_data[:, :, 3:4] + bg * (1 - norm_data[:, :, 3:4])
            image = Image.fromarray(np.array(arr*255.0, dtype=np.byte), "RGB")

            fovy = focal2fov(fov2focal(fovx, image.size[0]), image.size[1])
            FovY = fovy 
            FovX = fovx

            cam_infos.append(CameraInfo(uid=idx, R=R, T=T, FovY=FovY, FovX=FovX, image=image,
                            image_path=image_path, image_name=image_name, width=image.size[0], height=image.size[1]))
            
    return cam_infos

ここでは通常、自分の json ファイルの内容に基づいて変更を行います。主に注意すべき点は以下の通りです:

  • fovx = contents["camera_angle_x"]
  • cam_name = os.path.join(path,"images", frame["file_path"])
def fetchPly(path):
    plydata = PlyData.read(path)
    vertices = plydata['vertex']
    positions = np.vstack([vertices['x'], vertices['y'], vertices['z']]).T
    colors = np.vstack([vertices['red'], vertices['green'], vertices['blue']]).T / 255.0
    normals = np.vstack([0,0,0]).T
    return BasicPointCloud(points=positions, colors=colors, normals=normals)

この部分は ply ファイルに関連しており、通常、自分で収集したデータセットには点群法線 normals がないため、colmap 部分のコードに基づいて 0 に設定します。

一般的に、このように修正を行えば、コードは正常に動作し、レーザーポイントクラウドと GPS 高精度カメラポーズを組み合わせることで、colmap がカメラポーズを取得できない問題を解決できます。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。