Claude commited on
Commit
87b6aef
·
unverified ·
1 Parent(s): ae30b20

Add SHARP 3D Gaussian Splats Generator for Hugging Face Spaces

Browse files

- Implement Gradio UI with SHARP inference
- Integrate Three.js PLY viewer for interactive 3D preview
- Add ZeroGPU support for dynamic GPU allocation
- Create Dockerfile for Python 3.13 environment
- Add GitHub Actions workflow for auto-sync to HF Spaces
- Include comprehensive Japanese README with HF metadata

Features:
- Single image to 3D Gaussian Splats conversion
- Real-time 3D preview using Three.js + PLYLoader
- PLY file download support
- Optimized for ZeroGPU (Nvidia H200)

Technical stack:
- Apple SHARP model
- Gradio 5.9
- Three.js for 3D rendering
- Python 3.13 (via Docker)

Files changed (6) hide show
  1. .github/workflows/sync-to-hub.yml +55 -0
  2. .gitignore +11 -0
  3. Dockerfile +44 -0
  4. README.md +197 -2
  5. app.py +404 -0
  6. requirements.txt +23 -0
.github/workflows/sync-to-hub.yml ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Sync to Hugging Face Spaces
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ - claude/**
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ sync-to-hub:
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - name: Checkout repository
16
+ uses: actions/checkout@v4
17
+ with:
18
+ fetch-depth: 0
19
+ lfs: true
20
+
21
+ - name: Set up Python
22
+ uses: actions/setup-python@v5
23
+ with:
24
+ python-version: '3.11'
25
+
26
+ - name: Install Hugging Face CLI
27
+ run: |
28
+ pip install --upgrade huggingface_hub
29
+
30
+ - name: Push to Hugging Face Spaces
31
+ env:
32
+ HF_TOKEN: ${{ secrets.HF_TOKEN }}
33
+ run: |
34
+ # Hugging Face にログイン
35
+ huggingface-cli login --token $HF_TOKEN --add-to-git-credential
36
+
37
+ # Spaces リポジトリのURL
38
+ SPACE_URL="https://huggingface.co/spaces/YUGOROU/ml-sharp_ZeroGPU"
39
+
40
+ # Git設定
41
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
42
+ git config --global user.name "github-actions[bot]"
43
+
44
+ # Hugging Face Spacesにpush
45
+ git remote add hf https://huggingface.co/spaces/YUGOROU/ml-sharp_ZeroGPU || true
46
+ git push hf main --force
47
+
48
+ echo "✅ Successfully synced to Hugging Face Spaces!"
49
+ echo "🚀 Space URL: $SPACE_URL"
50
+
51
+ - name: Comment on commit
52
+ if: success()
53
+ run: |
54
+ echo "🎉 Deployment successful!"
55
+ echo "View your Space at: https://huggingface.co/spaces/YUGOROU/ml-sharp_ZeroGPU"
.gitignore CHANGED
@@ -205,3 +205,14 @@ cython_debug/
205
  marimo/_static/
206
  marimo/_lsp/
207
  __marimo__/
 
 
 
 
 
 
 
 
 
 
 
 
205
  marimo/_static/
206
  marimo/_lsp/
207
  __marimo__/
208
+
209
+ # SHARP / Gradio specific
210
+ *.ply
211
+ *.splat
212
+ *.mp4
213
+ *.avi
214
+ *.mov
215
+ gradio_cached_examples/
216
+ flagged/
217
+ tmp/
218
+ temp/
Dockerfile ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM nvidia/cuda:12.4.0-cudnn-devel-ubuntu22.04
2
+
3
+ # 環境変数
4
+ ENV DEBIAN_FRONTEND=noninteractive \
5
+ PYTHONUNBUFFERED=1 \
6
+ GRADIO_SERVER_NAME=0.0.0.0 \
7
+ GRADIO_SERVER_PORT=7860
8
+
9
+ # システムパッケージの更新とPython 3.13のインストール
10
+ RUN apt-get update && apt-get install -y \
11
+ software-properties-common \
12
+ wget \
13
+ git \
14
+ && add-apt-repository ppa:deadsnakes/ppa \
15
+ && apt-get update \
16
+ && apt-get install -y \
17
+ python3.13 \
18
+ python3.13-dev \
19
+ python3.13-venv \
20
+ python3-pip \
21
+ && rm -rf /var/lib/apt/lists/*
22
+
23
+ # Python 3.13をデフォルトに設定
24
+ RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.13 1 \
25
+ && update-alternatives --install /usr/bin/python python /usr/bin/python3.13 1
26
+
27
+ # pipのアップグレード
28
+ RUN python3 -m pip install --upgrade pip setuptools wheel
29
+
30
+ # 作業ディレクトリ
31
+ WORKDIR /app
32
+
33
+ # 依存関係をコピーしてインストール
34
+ COPY requirements.txt .
35
+ RUN python3 -m pip install --no-cache-dir -r requirements.txt
36
+
37
+ # アプリケーションファイルをコピー
38
+ COPY . .
39
+
40
+ # ポート公開
41
+ EXPOSE 7860
42
+
43
+ # 起動コマンド
44
+ CMD ["python3", "app.py"]
README.md CHANGED
@@ -1,2 +1,197 @@
1
- # ml-sharp_ZeroGPU
2
- Appleの3DGS技術"ml-sharp"をHF Spaces(ZeroGPU)にデプロイします
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: SHARP 3D Gaussian Splats Generator
3
+ emoji: 🎨
4
+ colorFrom: blue
5
+ colorTo: purple
6
+ sdk: docker
7
+ pinned: false
8
+ license: mit
9
+ tags:
10
+ - 3d
11
+ - gaussian-splatting
12
+ - computer-vision
13
+ - apple
14
+ - sharp
15
+ - three.js
16
+ - zerogpu
17
+ ---
18
+
19
+ # 🎨 SHARP: 3D Gaussian Splats Generator
20
+
21
+ <div align="center">
22
+
23
+ [![GitHub](https://img.shields.io/badge/GitHub-ml--sharp-blue?logo=github)](https://github.com/apple/ml-sharp)
24
+ [![arXiv](https://img.shields.io/badge/arXiv-2512.10685-b31b1b.svg)](https://arxiv.org/abs/2512.10685)
25
+ [![Hugging Face](https://img.shields.io/badge/🤗-Model-yellow)](https://huggingface.co/apple/Sharp)
26
+ [![License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
27
+
28
+ **単一の画像から高品質な3D Gaussian Splatsを1秒以下で生成**
29
+
30
+ </div>
31
+
32
+ ---
33
+
34
+ ## 📋 概要
35
+
36
+ このSpaceは、Appleが開発した最新の単一画像3D再構成技術「**SHARP (Sharp Monocular View Synthesis)**」を使用して、1枚の写真から3D Gaussian Splatsを生成します。
37
+
38
+ 生成された3DモデルはThree.jsを使用してブラウザ上でインタラクティブにプレビューでき、PLY形式でダウンロードも可能です。
39
+
40
+ ### ✨ 主な特徴
41
+
42
+ - 🚀 **超高速処理**: 1秒以下で3D再構成(従来手法の300倍以上高速)
43
+ - 🎯 **高品質**: SOTA品質(LPIPS 25-34%改善、DISTS 21-43%改善)
44
+ - 🖼️ **簡単操作**: 画像をアップロードするだけで3D化
45
+ - 🎬 **リアルタイムプレビュー**: Three.jsによるインタラクティブな3D表示
46
+ - 📦 **PLYエクスポート**: 標準的なPLY形式でダウンロード可能
47
+ - ⚡ **ZeroGPU対応**: Nvidia H200による動的GPU割り当て
48
+
49
+ ---
50
+
51
+ ## 🎮 使い方
52
+
53
+ ### 1. 画像のアップロード
54
+ 左側のエリアに画像をアップロードまたはドラッグ&ドロップします。
55
+
56
+ ### 2. 生成開始
57
+ 「🚀 生成開始」ボタンをクリックします。ZeroGPU (Nvidia H200)で処理されます。
58
+
59
+ ### 3. 3Dプレビュー
60
+ 右側のビューアで生成された3D Gaussian Splatsをインタラクティブに確認できます。
61
+
62
+ **操作方法:**
63
+ - 🖱️ **ドラッグ**: 3Dモデルを回転
64
+ - 🔍 **スクロール**: ズームイン/アウト
65
+ - ⌨️ **右クリック+ドラッグ**: パン移動
66
+
67
+ ### 4. ダウンロード
68
+ PLYファイルをダウンロードして、Blender、CloudCompare、MeshLabなどの3Dソフトウェアで使用できます。
69
+
70
+ ---
71
+
72
+ ## 🔧 技術スタック
73
+
74
+ ### フレームワーク
75
+ - **モデル**: Apple SHARP
76
+ - **UI**: Gradio 5.9
77
+ - **3Dレンダリング**: Three.js + PLYLoader
78
+ - **GPU**: ZeroGPU (Nvidia H200)
79
+ - **言語**: Python 3.13
80
+
81
+ ### 主要ライブラリ
82
+ ```
83
+ torch==2.5.1
84
+ gsplat==1.5.3
85
+ gradio==5.9.1
86
+ timm==1.0.12
87
+ ```
88
+
89
+ ---
90
+
91
+ ## 📊 技術詳細
92
+
93
+ ### 入力仕様
94
+ - **対応形式**: JPEG, PNG, TIFF, HEIC
95
+ - **解像度**: 任意(内部で1536×1536にリサイズ)
96
+ - **推奨**: 明瞭な被写体、適切な照明
97
+
98
+ ### 出力仕様
99
+ - **形式**: PLY (Polygon File Format)
100
+ - **内容**: 3D Gaussian Splats
101
+ - 位置 (x, y, z)
102
+ - スケール (3軸)
103
+ - 回転 (クォータニオン)
104
+ - 不透明度
105
+ - 球面調和係数 (色情報)
106
+
107
+ ### パフォーマンス
108
+ - **推論時間**: 通常1秒以下
109
+ - **メモリ使用量**: ~4-8GB (GPU)
110
+ - **出力サイズ**: 数MB〜数十MB (画像により変動)
111
+
112
+ ---
113
+
114
+ ## 🌐 ローカル実行
115
+
116
+ ### 前提条件
117
+ - Python 3.13
118
+ - CUDA 12.4+ (GPU使用の場合)
119
+ - 8GB以上のVRAM推奨
120
+
121
+ ### インストール
122
+ ```bash
123
+ # リポジトリをクローン
124
+ git clone https://github.com/YUGOROU/ml-sharp_ZeroGPU.git
125
+ cd ml-sharp_ZeroGPU
126
+
127
+ # 依存関係をインストール
128
+ pip install -r requirements.txt
129
+
130
+ # アプリケーションを起動
131
+ python app.py
132
+ ```
133
+
134
+ ### Dockerで実行
135
+ ```bash
136
+ # Dockerイメージをビルド
137
+ docker build -t sharp-app .
138
+
139
+ # コンテナを起動
140
+ docker run -p 7860:7860 --gpus all sharp-app
141
+ ```
142
+
143
+ ブラウザで `http://localhost:7860` にアクセスします。
144
+
145
+ ---
146
+
147
+ ## 📚 リソース
148
+
149
+ ### 公式リンク
150
+ - **GitHub**: [apple/ml-sharp](https://github.com/apple/ml-sharp)
151
+ - **公式サイト**: [apple.github.io/ml-sharp](https://apple.github.io/ml-sharp/)
152
+ - **論文**: [arXiv:2512.10685](https://arxiv.org/abs/2512.10685)
153
+ - **モデル**: [Hugging Face](https://huggingface.co/apple/Sharp)
154
+
155
+ ### 関連プロジェクト
156
+ - [GaussianSplats3D](https://github.com/mkkellogg/GaussianSplats3D) - Three.js用3DGSレンダラー
157
+ - [gsplat.js](https://github.com/huggingface/gsplat.js) - Hugging Face公式ライブラリ
158
+ - [antimatter15/splat](https://antimatter15.com/splat/) - WebGL PLYビューア
159
+
160
+ ---
161
+
162
+ ## ⚠️ 制限事項
163
+
164
+ - **ZeroGPUタイムアウト**: 関数実行は最大60秒
165
+ - **同時処理**: 複数ユーザーが同時にアクセスすると待機時間が発生
166
+ - **メモリ制限**: 非常に大きな画像は処理���きない場合があります
167
+ - **3D品質**: 単一画像からの推測のため、見えない部分の精度は限定的
168
+
169
+ ---
170
+
171
+ ## 📄 ライセンス
172
+
173
+ このプロジェクトはMITライセンスの下で公開されています。
174
+
175
+ ただし、SHARPモデル自体はApple独自のライセンス(apple-amlr)に従います。詳細は[公式リポジトリ](https://github.com/apple/ml-sharp)を参照してください。
176
+
177
+ ---
178
+
179
+ ## 🙏 謝辞
180
+
181
+ - **Apple**: SHARPモデルの開発と公開
182
+ - **Hugging Face**: ZeroGPU Spacesの提供
183
+ - **Three.js Community**: 3Dレンダリングライブラリ
184
+
185
+ ---
186
+
187
+ ## 📧 お問い合わせ
188
+
189
+ 質問や問題がある場合は、[GitHub Issues](https://github.com/YUGOROU/ml-sharp_ZeroGPU/issues)でお知らせください。
190
+
191
+ ---
192
+
193
+ <div align="center">
194
+
195
+ **Made with ❤️ using Apple SHARP and Hugging Face Spaces**
196
+
197
+ </div>
app.py ADDED
@@ -0,0 +1,404 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import spaces
3
+ import torch
4
+ from pathlib import Path
5
+ import tempfile
6
+ import os
7
+ import base64
8
+ from typing import Optional
9
+ import json
10
+
11
+ # SHARP モデルのインポート (遅延読み込み)
12
+ try:
13
+ from sharp import Sharp
14
+ SHARP_AVAILABLE = True
15
+ except ImportError:
16
+ SHARP_AVAILABLE = False
17
+ print("Warning: SHARP not available. Using mock mode for development.")
18
+
19
+ # グローバルモデルインスタンス (メモリ効率のため)
20
+ _model = None
21
+
22
+ def get_model():
23
+ """モデルインスタンスを取得(キャッシング)"""
24
+ global _model
25
+ if _model is None and SHARP_AVAILABLE:
26
+ _model = Sharp()
27
+ return _model
28
+
29
+ @spaces.GPU(duration=60)
30
+ def process_image(image) -> tuple[Optional[str], str, str]:
31
+ """
32
+ 画像から3D Gaussian Splatsを生成
33
+
34
+ Args:
35
+ image: PIL Image or numpy array
36
+
37
+ Returns:
38
+ tuple: (PLYファイルパス, ステータスメッセージ, PLYデータ(base64))
39
+ """
40
+ if not SHARP_AVAILABLE:
41
+ return None, "❌ SHARPモデルが利用できません", ""
42
+
43
+ if image is None:
44
+ return None, "❌ 画像をアップロードしてください", ""
45
+
46
+ try:
47
+ # 一時ファイルとして保存
48
+ with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp_input:
49
+ input_path = Path(tmp_input.name)
50
+
51
+ # PIL Imageとして保存
52
+ if hasattr(image, 'save'):
53
+ image.save(input_path, format='JPEG')
54
+ else:
55
+ from PIL import Image
56
+ Image.fromarray(image).save(input_path, format='JPEG')
57
+
58
+ # モデルで推論
59
+ model = get_model()
60
+ print(f"🔄 Processing image: {input_path}")
61
+ gaussians = model.predict(input_path)
62
+
63
+ # PLYファイルとして保存
64
+ with tempfile.NamedTemporaryFile(suffix=".ply", delete=False) as tmp_output:
65
+ output_path = Path(tmp_output.name)
66
+
67
+ gaussians.save(str(output_path))
68
+
69
+ # PLYファイルをBase64エンコード (Three.jsで使用)
70
+ with open(output_path, 'rb') as f:
71
+ ply_data = f.read()
72
+ ply_base64 = base64.b64encode(ply_data).decode('utf-8')
73
+
74
+ # 統計情報を取得
75
+ file_size = output_path.stat().st_size / (1024 * 1024) # MB
76
+
77
+ # 入力ファイルを削除
78
+ if input_path.exists():
79
+ input_path.unlink()
80
+
81
+ status_msg = f"✅ 生成完了!\n📦 ファイルサイズ: {file_size:.2f} MB"
82
+
83
+ return str(output_path), status_msg, ply_base64
84
+
85
+ except Exception as e:
86
+ import traceback
87
+ error_msg = f"❌ エラーが発生しました:\n{str(e)}\n\n{traceback.format_exc()}"
88
+ print(error_msg)
89
+ return None, error_msg, ""
90
+
91
+ # Three.js ビューアのHTMLテンプレート
92
+ def create_viewer_html(ply_base64: str) -> str:
93
+ """Three.js + GaussianSplats3D ビューアのHTMLを生成"""
94
+
95
+ if not ply_base64:
96
+ return """
97
+ <div style="width: 100%; height: 600px; display: flex; align-items: center; justify-content: center; background: #1a1a1a; color: white; border-radius: 8px;">
98
+ <div style="text-align: center;">
99
+ <h2>🎨 3D Gaussian Splats ビューア</h2>
100
+ <p>左側で画像を処理すると、ここに3Dプレビューが表示されます</p>
101
+ </div>
102
+ </div>
103
+ """
104
+
105
+ html = f"""
106
+ <!DOCTYPE html>
107
+ <html lang="ja">
108
+ <head>
109
+ <meta charset="UTF-8">
110
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
111
+ <title>3D Gaussian Splats Viewer</title>
112
+ <style>
113
+ body {{
114
+ margin: 0;
115
+ padding: 0;
116
+ overflow: hidden;
117
+ background: #000;
118
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
119
+ }}
120
+ #container {{
121
+ width: 100%;
122
+ height: 600px;
123
+ position: relative;
124
+ }}
125
+ #loading {{
126
+ position: absolute;
127
+ top: 50%;
128
+ left: 50%;
129
+ transform: translate(-50%, -50%);
130
+ color: white;
131
+ font-size: 18px;
132
+ z-index: 1000;
133
+ }}
134
+ #controls {{
135
+ position: absolute;
136
+ top: 10px;
137
+ left: 10px;
138
+ background: rgba(0, 0, 0, 0.7);
139
+ color: white;
140
+ padding: 10px;
141
+ border-radius: 5px;
142
+ font-size: 12px;
143
+ z-index: 1000;
144
+ }}
145
+ </style>
146
+ </head>
147
+ <body>
148
+ <div id="container">
149
+ <div id="loading">🔄 3Dモデルを読み込み中...</div>
150
+ <div id="controls">
151
+ <div>🖱️ ドラッグ: 回転</div>
152
+ <div>🔍 スクロール: ズーム</div>
153
+ <div>⌨️ 右クリック: パン</div>
154
+ </div>
155
+ </div>
156
+
157
+ <script type="importmap">
158
+ {{
159
+ "imports": {{
160
+ "three": "https://cdn.jsdelivr.net/npm/three@0.168.0/build/three.module.js",
161
+ "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.168.0/examples/jsm/"
162
+ }}
163
+ }}
164
+ </script>
165
+
166
+ <script type="module">
167
+ import * as THREE from 'three';
168
+ import {{ OrbitControls }} from 'three/addons/controls/OrbitControls.js';
169
+
170
+ // シーンの初期化
171
+ const container = document.getElementById('container');
172
+ const loading = document.getElementById('loading');
173
+
174
+ const scene = new THREE.Scene();
175
+ scene.background = new THREE.Color(0x1a1a1a);
176
+
177
+ const camera = new THREE.PerspectiveCamera(
178
+ 75,
179
+ container.clientWidth / container.clientHeight,
180
+ 0.1,
181
+ 1000
182
+ );
183
+ camera.position.set(0, 0, 5);
184
+
185
+ const renderer = new THREE.WebGLRenderer({{ antialias: true }});
186
+ renderer.setSize(container.clientWidth, container.clientHeight);
187
+ renderer.setPixelRatio(window.devicePixelRatio);
188
+ container.appendChild(renderer.domElement);
189
+
190
+ // OrbitControls
191
+ const controls = new OrbitControls(camera, renderer.domElement);
192
+ controls.enableDamping = true;
193
+ controls.dampingFactor = 0.05;
194
+
195
+ // ライト
196
+ const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
197
+ scene.add(ambientLight);
198
+
199
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
200
+ directionalLight.position.set(5, 10, 7.5);
201
+ scene.add(directionalLight);
202
+
203
+ // グリッドヘルパー
204
+ const gridHelper = new THREE.GridHelper(10, 10);
205
+ scene.add(gridHelper);
206
+
207
+ // PLYローダー
208
+ async function loadPLY() {{
209
+ try {{
210
+ // Base64からArrayBufferに変換
211
+ const plyBase64 = '{ply_base64}';
212
+ const binaryString = atob(plyBase64);
213
+ const bytes = new Uint8Array(binaryString.length);
214
+ for (let i = 0; i < binaryString.length; i++) {{
215
+ bytes[i] = binaryString.charCodeAt(i);
216
+ }}
217
+
218
+ // PLYLoaderを動的にインポート
219
+ const {{ PLYLoader }} = await import('three/addons/loaders/PLYLoader.js');
220
+ const loader = new PLYLoader();
221
+
222
+ // ArrayBufferをBlob経由でロード
223
+ const blob = new Blob([bytes], {{ type: 'application/octet-stream' }});
224
+ const url = URL.createObjectURL(blob);
225
+
226
+ loader.load(
227
+ url,
228
+ function (geometry) {{
229
+ loading.style.display = 'none';
230
+
231
+ // ポイントクラウドとしてレンダリング
232
+ geometry.computeVertexNormals();
233
+
234
+ // カラー情報があるか確認
235
+ const hasColors = geometry.attributes.color !== undefined;
236
+
237
+ const material = new THREE.PointsMaterial({{
238
+ size: 0.01,
239
+ vertexColors: hasColors,
240
+ color: hasColors ? undefined : 0x00ff00,
241
+ sizeAttenuation: true
242
+ }});
243
+
244
+ const points = new THREE.Points(geometry, material);
245
+ scene.add(points);
246
+
247
+ // カメラ位置を調整
248
+ geometry.computeBoundingBox();
249
+ const bbox = geometry.boundingBox;
250
+ const center = new THREE.Vector3();
251
+ bbox.getCenter(center);
252
+
253
+ const size = new THREE.Vector3();
254
+ bbox.getSize(size);
255
+ const maxDim = Math.max(size.x, size.y, size.z);
256
+ const fov = camera.fov * (Math.PI / 180);
257
+ let cameraZ = Math.abs(maxDim / Math.tan(fov / 2));
258
+ cameraZ *= 1.5;
259
+
260
+ camera.position.set(center.x, center.y, center.z + cameraZ);
261
+ camera.lookAt(center);
262
+ controls.target.copy(center);
263
+ controls.update();
264
+
265
+ URL.revokeObjectURL(url);
266
+
267
+ console.log('✅ PLYファイルの読み込み完了');
268
+ }},
269
+ function (xhr) {{
270
+ const percent = (xhr.loaded / xhr.total * 100).toFixed(0);
271
+ loading.textContent = `🔄 読み込み中... ${{percent}}%`;
272
+ }},
273
+ function (error) {{
274
+ console.error('❌ PLY読み込みエラー:', error);
275
+ loading.textContent = '❌ 読み込みエラー';
276
+ loading.style.color = 'red';
277
+ }}
278
+ );
279
+ }} catch (error) {{
280
+ console.error('❌ エラー:', error);
281
+ loading.textContent = '❌ エラーが発生しました';
282
+ loading.style.color = 'red';
283
+ }}
284
+ }}
285
+
286
+ // アニメーションループ
287
+ function animate() {{
288
+ requestAnimationFrame(animate);
289
+ controls.update();
290
+ renderer.render(scene, camera);
291
+ }}
292
+
293
+ // リサイズ対応
294
+ window.addEventListener('resize', () => {{
295
+ camera.aspect = container.clientWidth / container.clientHeight;
296
+ camera.updateProjectionMatrix();
297
+ renderer.setSize(container.clientWidth, container.clientHeight);
298
+ }});
299
+
300
+ // PLYを読み込んで開始
301
+ loadPLY();
302
+ animate();
303
+ </script>
304
+ </body>
305
+ </html>
306
+ """
307
+ return html
308
+
309
+ def update_viewer(ply_base64: str) -> str:
310
+ """ビューアを更新"""
311
+ return create_viewer_html(ply_base64)
312
+
313
+ # Gradio UI
314
+ with gr.Blocks(
315
+ theme=gr.themes.Soft(primary_hue="blue", secondary_hue="purple"),
316
+ title="SHARP: 3D Gaussian Splats Generator"
317
+ ) as demo:
318
+ gr.Markdown("""
319
+ # 🎨 SHARP: 単一画像から3D Gaussian Splatsを生成
320
+
321
+ Appleの最新技術「SHARP」を使用して、1枚の画像から高品質な3D Gaussian Splatsを生成します。
322
+ 生成された3DモデルはThree.jsで右側にリアルタイムプレビューされます。
323
+
324
+ ### 使い方
325
+ 1. 左側のエリアに画像をアップロード
326
+ 2. 「生成開始」ボタンをクリック
327
+ 3. 右側で3Dモデルをインタラクティブに確認
328
+ 4. PLYファイルをダウンロード可能
329
+
330
+ **ZeroGPU (Nvidia H200)** で高速に処理されます 🚀
331
+ """)
332
+
333
+ with gr.Row():
334
+ with gr.Column(scale=1):
335
+ gr.Markdown("### 📸 入力画像")
336
+ input_image = gr.Image(
337
+ label="画像をアップロード",
338
+ type="pil",
339
+ sources=["upload", "clipboard"],
340
+ height=400
341
+ )
342
+
343
+ generate_btn = gr.Button(
344
+ "🚀 生成開始",
345
+ variant="primary",
346
+ size="lg"
347
+ )
348
+
349
+ status_box = gr.Textbox(
350
+ label="ステータス",
351
+ lines=3,
352
+ interactive=False
353
+ )
354
+
355
+ output_file = gr.File(
356
+ label="📦 PLYファイルをダウンロード",
357
+ interactive=False
358
+ )
359
+
360
+ with gr.Column(scale=1):
361
+ gr.Markdown("### 🎬 3Dプレビュー (Three.js)")
362
+ viewer_html = gr.HTML(
363
+ create_viewer_html(""),
364
+ label="3D Viewer"
365
+ )
366
+
367
+ # 非表示のステート (PLY Base64データ)
368
+ ply_data_state = gr.State("")
369
+
370
+ # イベントハンドラ
371
+ def on_generate(image):
372
+ ply_path, status, ply_base64 = process_image(image)
373
+ viewer = create_viewer_html(ply_base64)
374
+ return ply_path, status, ply_base64, viewer
375
+
376
+ generate_btn.click(
377
+ fn=on_generate,
378
+ inputs=[input_image],
379
+ outputs=[output_file, status_box, ply_data_state, viewer_html]
380
+ )
381
+
382
+ gr.Markdown("""
383
+ ---
384
+ ### ℹ️ 技術情報
385
+
386
+ - **モデル**: Apple SHARP (Sharp Monocular View Synthesis)
387
+ - **出力形式**: PLY (Polygon File Format)
388
+ - **レンダリング**: Three.js + PLYLoader
389
+ - **GPU**: ZeroGPU (Nvidia H200, 動的割り当て)
390
+ - **処理時間**: 通常1秒以下
391
+
392
+ ### 📚 リソース
393
+ - [SHARP GitHub](https://github.com/apple/ml-sharp)
394
+ - [論文 (arXiv)](https://arxiv.org/abs/2512.10685)
395
+ - [Hugging Face Model](https://huggingface.co/apple/Sharp)
396
+
397
+ ### ⚠️ 注意事項
398
+ - 処理にはGPUを使用するため、待機時間が発生する場合があります
399
+ - ZeroGPUは60秒のタイムアウトがあります
400
+ - 大きな画像は自動的にリサイズされます
401
+ """)
402
+
403
+ if __name__ == "__main__":
404
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Core dependencies for SHARP
2
+ torch==2.5.1
3
+ torchvision==0.20.1
4
+ timm==1.0.12
5
+ gsplat==1.5.3
6
+ scipy==1.14.1
7
+ numpy==2.1.3
8
+ pillow==11.0.0
9
+ pillow-heif==0.20.0
10
+ imageio==2.37.0
11
+ imageio-ffmpeg==0.6.0
12
+ click==8.1.8
13
+ plyfile==1.1.2
14
+ huggingface-hub==0.27.0
15
+
16
+ # Gradio for UI
17
+ gradio==5.9.1
18
+
19
+ # Spaces GPU support
20
+ spaces
21
+
22
+ # SHARP package from GitHub
23
+ git+https://github.com/apple/ml-sharp.git