Commit ·
8c08729
1
Parent(s): 8de0c20
feat: テンプレート選択機能の改善と手動更新方式の実装
Browse files- CLAUDE.md:
- テンプレート選択機能を改善し、ドロップダウンを「3頭身立ちポーズ」に集約
- 「🔄 ポーズ更新」ボタンを追加し、手動更新方式に変更
- 3heads.jsonファイルを直接活用するテンプレート読み込み機能を実装
- Python側でpeople形式とbodies形式のハイブリッドデータ構造を採用
- JavaScript側でテンプレート読み込み時の表示設定強制同期を実装
- 体・手・顔の全データが初期表示から正常に描画される仕組みを完成
- app.py:
- デバッグ用の手データ確認コードを削除し、コードをクリーンアップ
- pose_editor.js:
- 手データのデバッグログを削除し、コードをクリーンアップ
- CLAUDE.md +8 -0
- app.py +1 -33
- issues/039_テンプレート選択機能改善.md +23 -2
- static/pose_editor.js +4 -72
CLAUDE.md
CHANGED
|
@@ -192,6 +192,14 @@ Key Features:
|
|
| 192 |
* 詳細モードでは矩形を非表示にして、キーポイント直接操作を可能に
|
| 193 |
* ラジオボタン監視機能の追加で編集モード切り替えをリアルタイム反映
|
| 194 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 195 |
### 🔧 **Current Implementation Status**
|
| 196 |
**Phase 1 (Project Foundation)**: COMPLETED ✅
|
| 197 |
- Basic Gradio application structure ✅
|
|
|
|
| 192 |
* 詳細モードでは矩形を非表示にして、キーポイント直接操作を可能に
|
| 193 |
* ラジオボタン監視機能の追加で編集モード切り替えをリアルタイム反映
|
| 194 |
|
| 195 |
+
- **Issue #039**: テンプレート選択機能改善 (2025-01-15) 🎯
|
| 196 |
+
* テンプレートドロップダウンを1つの選択肢(「3頭身立ちポーズ」)に集約
|
| 197 |
+
* 「🔄 ポーズ更新」ボタンを追加し、手動更新方式に変更
|
| 198 |
+
* 3heads.jsonファイルを直接活用するテンプレート読み込み機能を実装
|
| 199 |
+
* Python側でpeople形式とbodies形式のハイブリッドデータ構造を採用
|
| 200 |
+
* JavaScript側でテンプレート読み込み時の表示設定強制同期を実装
|
| 201 |
+
* 体・手・顔の全データが初期表示から正常に描画される仕組みを完成
|
| 202 |
+
|
| 203 |
### 🔧 **Current Implementation Status**
|
| 204 |
**Phase 1 (Project Foundation)**: COMPLETED ✅
|
| 205 |
- Basic Gradio application structure ✅
|
app.py
CHANGED
|
@@ -325,40 +325,12 @@ def main():
|
|
| 325 |
"face_keypoints_2d": actual_pose_data.get('faces', [[]])[0] if actual_pose_data.get('faces') else []
|
| 326 |
}
|
| 327 |
|
| 328 |
-
# デバッグ:手データの変換確認
|
| 329 |
-
print(f"[DEBUG] 🫳 Hand data conversion:")
|
| 330 |
-
print(f" - hands in data: {bool(actual_pose_data.get('hands'))}")
|
| 331 |
-
print(f" - hands length: {len(actual_pose_data.get('hands', []))}")
|
| 332 |
-
if actual_pose_data.get('hands'):
|
| 333 |
-
print(f" - left hand length: {len(actual_pose_data['hands'][0]) if len(actual_pose_data['hands']) > 0 else 0}")
|
| 334 |
-
print(f" - right hand length: {len(actual_pose_data['hands'][1]) if len(actual_pose_data['hands']) > 1 else 0}")
|
| 335 |
-
print(f" - person_data left hand: {len(person_data['hand_left_keypoints_2d'])}")
|
| 336 |
-
print(f" - person_data right hand: {len(person_data['hand_right_keypoints_2d'])}")
|
| 337 |
-
|
| 338 |
-
# デバッグ:actual_pose_dataの構造確認
|
| 339 |
-
print(f"[DEBUG] 🔍 actual_pose_data structure check:")
|
| 340 |
-
print(f" - keys: {list(actual_pose_data.keys())}")
|
| 341 |
-
print(f" - has bodies: {'bodies' in actual_pose_data}")
|
| 342 |
-
if 'bodies' in actual_pose_data:
|
| 343 |
-
print(f" - bodies keys: {list(actual_pose_data['bodies'].keys())}")
|
| 344 |
-
print(f" - has candidate: {'candidate' in actual_pose_data['bodies']}")
|
| 345 |
-
|
| 346 |
# bodies.candidateからpose_keypoints_2d変換
|
| 347 |
if 'bodies' in actual_pose_data and 'candidate' in actual_pose_data['bodies']:
|
| 348 |
candidates = actual_pose_data['bodies']['candidate']
|
| 349 |
-
|
| 350 |
-
print(f" - bodies.candidate length: {len(candidates)}")
|
| 351 |
-
for i, candidate in enumerate(candidates):
|
| 352 |
if candidate and len(candidate) >= 2:
|
| 353 |
person_data["pose_keypoints_2d"].extend([candidate[0], candidate[1], candidate[2] if len(candidate) > 2 else 1.0])
|
| 354 |
-
if i < 3: # 最初の3つだけログ出力
|
| 355 |
-
print(f" - candidate {i}: {candidate[:3]}")
|
| 356 |
-
print(f" - final pose_keypoints_2d length: {len(person_data['pose_keypoints_2d'])}")
|
| 357 |
-
else:
|
| 358 |
-
print(f"[DEBUG] ❌ No bodies.candidate found in actual_pose_data!")
|
| 359 |
-
print(f" - has bodies: {bool(actual_pose_data.get('bodies'))}")
|
| 360 |
-
if actual_pose_data.get('bodies'):
|
| 361 |
-
print(f" - bodies keys: {list(actual_pose_data['bodies'].keys())}")
|
| 362 |
|
| 363 |
_current_poses = [{
|
| 364 |
'people': [person_data],
|
|
@@ -367,8 +339,6 @@ def main():
|
|
| 367 |
}
|
| 368 |
}]
|
| 369 |
_current_frame_index = 0
|
| 370 |
-
print(f"[DEBUG] ✅ グローバル変数更新完了(テンプレート読み込み・refs互換): {template_name}")
|
| 371 |
-
|
| 372 |
# people形式でデータを構築(元のbodies/hands/facesも保持)
|
| 373 |
people_format_data = {
|
| 374 |
'people': [person_data],
|
|
@@ -381,8 +351,6 @@ def main():
|
|
| 381 |
'is_template_load': True # テンプレート読み込みフラグ
|
| 382 |
}
|
| 383 |
|
| 384 |
-
print(f"[DEBUG] 🔄 Returning people format data with {len(person_data['hand_left_keypoints_2d'])} left hand points")
|
| 385 |
-
|
| 386 |
notify_success(f"{template_name}を読み込みました")
|
| 387 |
return people_format_data, people_format_data
|
| 388 |
else:
|
|
|
|
| 325 |
"face_keypoints_2d": actual_pose_data.get('faces', [[]])[0] if actual_pose_data.get('faces') else []
|
| 326 |
}
|
| 327 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 328 |
# bodies.candidateからpose_keypoints_2d変換
|
| 329 |
if 'bodies' in actual_pose_data and 'candidate' in actual_pose_data['bodies']:
|
| 330 |
candidates = actual_pose_data['bodies']['candidate']
|
| 331 |
+
for candidate in candidates:
|
|
|
|
|
|
|
| 332 |
if candidate and len(candidate) >= 2:
|
| 333 |
person_data["pose_keypoints_2d"].extend([candidate[0], candidate[1], candidate[2] if len(candidate) > 2 else 1.0])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 334 |
|
| 335 |
_current_poses = [{
|
| 336 |
'people': [person_data],
|
|
|
|
| 339 |
}
|
| 340 |
}]
|
| 341 |
_current_frame_index = 0
|
|
|
|
|
|
|
| 342 |
# people形式でデータを構築(元のbodies/hands/facesも保持)
|
| 343 |
people_format_data = {
|
| 344 |
'people': [person_data],
|
|
|
|
| 351 |
'is_template_load': True # テンプレート読み込みフラグ
|
| 352 |
}
|
| 353 |
|
|
|
|
|
|
|
| 354 |
notify_success(f"{template_name}を読み込みました")
|
| 355 |
return people_format_data, people_format_data
|
| 356 |
else:
|
issues/039_テンプレート選択機能改善.md
CHANGED
|
@@ -131,6 +131,27 @@ template_update_btn = gr.Button(
|
|
| 131 |
|
| 132 |
---
|
| 133 |
*Created: 2025-01-15*
|
| 134 |
-
*
|
|
|
|
| 135 |
*Assignee: Claude Code Agent*
|
| 136 |
-
*Tags: UI改善, テンプレート機能, ユーザビリティ*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
|
| 132 |
---
|
| 133 |
*Created: 2025-01-15*
|
| 134 |
+
*Completed: 2025-01-15*
|
| 135 |
+
*Status: ✅ 完了*
|
| 136 |
*Assignee: Claude Code Agent*
|
| 137 |
+
*Tags: UI改善, テンプレート機能, ユーザビリティ*
|
| 138 |
+
|
| 139 |
+
## 実装結果
|
| 140 |
+
|
| 141 |
+
### ✅ 完了した機能
|
| 142 |
+
1. **テンプレートUI改善**: ドロップダウンを「3頭身立ちポーズ」1つに集約
|
| 143 |
+
2. **手動更新ボタン**: 「🔄 ポーズ更新」ボタンの追加と手動更新方式への変更
|
| 144 |
+
3. **3heads.json活用**: 実際のテンプレートファイルを直接読み込む機能の実装
|
| 145 |
+
4. **ハイブリッドデータ構造**: people形式とbodies形式を両方含むデータ送信
|
| 146 |
+
5. **表示設定同期**: テンプレート読み込み時の表示設定強制同期機能
|
| 147 |
+
|
| 148 |
+
### 🛠️ 技術的解決策
|
| 149 |
+
- **Python側**: people形式とbodies/hands/faces形式のハイブリッド送信
|
| 150 |
+
- **JavaScript側**: テンプレート読み込み時の表示設定強制取得
|
| 151 |
+
- **初期表示問題解決**: 体・手・顔の全データが最初から正常描画される
|
| 152 |
+
|
| 153 |
+
### 📊 成果
|
| 154 |
+
- シンプルで分かりやすいUI(選択肢1つ)
|
| 155 |
+
- ユーザー制御可能な手動更新方式
|
| 156 |
+
- 3heads.jsonテンプレートファイルの有効活用
|
| 157 |
+
- 全ポーズデータの完全な初期表示
|
static/pose_editor.js
CHANGED
|
@@ -1876,23 +1876,14 @@ function drawPose(poseData, enableHands = true, enableFace = true, highlightInde
|
|
| 1876 |
person.hand_left_keypoints_2d || [],
|
| 1877 |
person.hand_right_keypoints_2d || []
|
| 1878 |
];
|
| 1879 |
-
console.log('🫳 [HANDS DEBUG] Hand data prepared:', {
|
| 1880 |
-
leftLength: handsDataForDrawing[0].length,
|
| 1881 |
-
rightLength: handsDataForDrawing[1].length,
|
| 1882 |
-
leftSample: handsDataForDrawing[0].slice(0, 9),
|
| 1883 |
-
rightSample: handsDataForDrawing[1].slice(0, 9)
|
| 1884 |
-
});
|
| 1885 |
// 💖 people形式のみサポート、古いhands形式は削除
|
| 1886 |
} else {
|
| 1887 |
handsDataForDrawing = [[], []]; // 空の手データ
|
| 1888 |
-
console.log('🫳 [HANDS DEBUG] No people data, using empty hands');
|
| 1889 |
}
|
| 1890 |
|
| 1891 |
if (handsDataForDrawing && handsDataForDrawing.length >= 2) {
|
| 1892 |
drawHands(handsDataForDrawing, originalRes, scaleX, scaleY);
|
| 1893 |
debugLog(`🫳 Hands drawn: left=${handsDataForDrawing[0].length}, right=${handsDataForDrawing[1].length}`);
|
| 1894 |
-
} else {
|
| 1895 |
-
console.log('🫳 [HANDS DEBUG] Invalid handsDataForDrawing structure');
|
| 1896 |
}
|
| 1897 |
} catch (error) {
|
| 1898 |
console.error("❌ Error drawing hands:", error);
|
|
@@ -2363,28 +2354,6 @@ window.gradioCanvasUpdate = function(pose_json_str) {
|
|
| 2363 |
}
|
| 2364 |
|
| 2365 |
// 💖 グローバルposeDataを更新(但し、people形式チェック付き)
|
| 2366 |
-
console.log('🔍 [gradioCanvasUpdate] Received poseData structure:', {
|
| 2367 |
-
hasPeople: !!poseData?.people,
|
| 2368 |
-
peopleCount: poseData?.people?.length || 0,
|
| 2369 |
-
hasHandLeft: !!poseData?.people?.[0]?.hand_left_keypoints_2d,
|
| 2370 |
-
hasHandRight: !!poseData?.people?.[0]?.hand_right_keypoints_2d,
|
| 2371 |
-
hasFace: !!poseData?.people?.[0]?.face_keypoints_2d,
|
| 2372 |
-
hasBodies: !!poseData?.bodies,
|
| 2373 |
-
hasHands: !!poseData?.hands,
|
| 2374 |
-
hasFaces: !!poseData?.faces,
|
| 2375 |
-
hasBackgroundImage: !!poseData?.background_image,
|
| 2376 |
-
handLeftLength: poseData?.people?.[0]?.hand_left_keypoints_2d?.length || 0,
|
| 2377 |
-
handRightLength: poseData?.people?.[0]?.hand_right_keypoints_2d?.length || 0,
|
| 2378 |
-
isTemplateLoad: !!poseData?.is_template_load
|
| 2379 |
-
});
|
| 2380 |
-
|
| 2381 |
-
// 🔍 テンプレート読み込み時の詳細ログ
|
| 2382 |
-
if (poseData?.is_template_load) {
|
| 2383 |
-
console.log('🔄 [TEMPLATE LOAD] Detailed hand data check:', {
|
| 2384 |
-
leftHandData: poseData?.people?.[0]?.hand_left_keypoints_2d?.slice(0, 9) || 'NO DATA',
|
| 2385 |
-
rightHandData: poseData?.people?.[0]?.hand_right_keypoints_2d?.slice(0, 9) || 'NO DATA'
|
| 2386 |
-
});
|
| 2387 |
-
}
|
| 2388 |
|
| 2389 |
// 🎨 背景画像が含まれている場合は設定
|
| 2390 |
if (poseData && poseData.background_image) {
|
|
@@ -2398,31 +2367,19 @@ window.gradioCanvasUpdate = function(pose_json_str) {
|
|
| 2398 |
const existingPoseData = window.poseEditorGlobals.poseData;
|
| 2399 |
|
| 2400 |
if (isTemplateLoad) {
|
| 2401 |
-
console.log('🔄 [gradioCanvasUpdate] Template load detected - complete replacement');
|
| 2402 |
// テンプレート読み込み時は完全置換
|
| 2403 |
window.poseEditorGlobals.poseData = poseData;
|
| 2404 |
// baseOriginalKeypointsもリセット(新しいテンプレート用)
|
| 2405 |
window.poseEditorGlobals.baseOriginalKeypoints = null;
|
| 2406 |
|
| 2407 |
-
//
|
| 2408 |
updateDisplaySettingsFromCheckbox();
|
| 2409 |
-
console.log('🔧 [TEMPLATE LOAD] Forced display settings update:', {
|
| 2410 |
-
enableHands: window.poseEditorGlobals.enableHands,
|
| 2411 |
-
enableFace: window.poseEditorGlobals.enableFace,
|
| 2412 |
-
editMode: window.poseEditorGlobals.editMode
|
| 2413 |
-
});
|
| 2414 |
|
| 2415 |
-
//
|
| 2416 |
setTimeout(() => setupGradioCheckboxListeners(), 100);
|
| 2417 |
} else if (existingPoseData && existingPoseData.people && existingPoseData.people[0] &&
|
| 2418 |
poseData && (!poseData.people || !poseData.people[0])) {
|
| 2419 |
|
| 2420 |
-
console.log('🛡️ [gradioCanvasUpdate] Protecting existing people data from overwrite');
|
| 2421 |
-
console.log('🔍 [gradioCanvasUpdate] Existing data:', {
|
| 2422 |
-
hasHandLeft: !!existingPoseData.people[0].hand_left_keypoints_2d,
|
| 2423 |
-
hasHandRight: !!existingPoseData.people[0].hand_right_keypoints_2d,
|
| 2424 |
-
hasFace: !!existingPoseData.people[0].face_keypoints_2d
|
| 2425 |
-
});
|
| 2426 |
|
| 2427 |
// Python側データを古い形式に変換してからマージ
|
| 2428 |
if (poseData.bodies || poseData.hands || poseData.faces) {
|
|
@@ -2441,7 +2398,6 @@ window.gradioCanvasUpdate = function(pose_json_str) {
|
|
| 2441 |
}
|
| 2442 |
|
| 2443 |
// 手と顔データは既存を保持(Python側で消失している可能性があるため)
|
| 2444 |
-
console.log('🔍 [gradioCanvasUpdate] Preserving hands/face data from existing poseData');
|
| 2445 |
|
| 2446 |
window.poseEditorGlobals.poseData = preservedPoseData;
|
| 2447 |
poseData = preservedPoseData; // 描画用も更新
|
|
@@ -2456,30 +2412,14 @@ window.gradioCanvasUpdate = function(pose_json_str) {
|
|
| 2456 |
|
| 2457 |
// 💖 originalKeypointsも設定(但し、baseOriginalKeypointsは保護)
|
| 2458 |
if (poseData && poseData.people && poseData.people[0]) {
|
| 2459 |
-
//
|
| 2460 |
if (!window.poseEditorGlobals.baseOriginalKeypoints) {
|
| 2461 |
window.poseEditorGlobals.baseOriginalKeypoints = JSON.parse(JSON.stringify(poseData));
|
| 2462 |
-
console.log("💖 [gradioCanvasUpdate] baseOriginalKeypoints set for FIRST time");
|
| 2463 |
-
} else {
|
| 2464 |
-
console.log("💖 [gradioCanvasUpdate] baseOriginalKeypoints PROTECTED from overwrite");
|
| 2465 |
}
|
| 2466 |
|
| 2467 |
// originalKeypointsは更新してOK(作業用)
|
| 2468 |
window.poseEditorGlobals.originalKeypoints = JSON.parse(JSON.stringify(poseData));
|
| 2469 |
-
console.log("🔧 [gradioCanvasUpdate] originalKeypoints set from gradioCanvasUpdate for template/upload");
|
| 2470 |
|
| 2471 |
-
// デバッグ:手のデータ確認
|
| 2472 |
-
const person = poseData.people[0];
|
| 2473 |
-
if (person.hand_left_keypoints_2d) {
|
| 2474 |
-
debugLog(`🫳 Left hand keypoints: ${person.hand_left_keypoints_2d.length} elements`);
|
| 2475 |
-
} else {
|
| 2476 |
-
debugLog("🫳 No left hand keypoints found");
|
| 2477 |
-
}
|
| 2478 |
-
if (person.hand_right_keypoints_2d) {
|
| 2479 |
-
debugLog(`🫳 Right hand keypoints: ${person.hand_right_keypoints_2d.length} elements`);
|
| 2480 |
-
} else {
|
| 2481 |
-
debugLog("🫳 No right hand keypoints found");
|
| 2482 |
-
}
|
| 2483 |
}
|
| 2484 |
|
| 2485 |
if (!isCanvasReady()) {
|
|
@@ -2498,16 +2438,8 @@ window.gradioCanvasUpdate = function(pose_json_str) {
|
|
| 2498 |
const ctx = window.poseEditorGlobals.ctx;
|
| 2499 |
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
| 2500 |
|
| 2501 |
-
//
|
| 2502 |
if (poseData && Object.keys(poseData).length > 0) {
|
| 2503 |
-
console.log('🎨 [DRAW CALL] About to call drawPose with settings:', {
|
| 2504 |
-
enableHands: window.poseEditorGlobals.enableHands,
|
| 2505 |
-
enableFace: window.poseEditorGlobals.enableFace,
|
| 2506 |
-
editMode: window.poseEditorGlobals.editMode,
|
| 2507 |
-
hasPeopleData: !!poseData.people,
|
| 2508 |
-
handDataAvailable: !!(poseData.people?.[0]?.hand_left_keypoints_2d?.length > 0)
|
| 2509 |
-
});
|
| 2510 |
-
|
| 2511 |
drawPose(
|
| 2512 |
poseData,
|
| 2513 |
window.poseEditorGlobals.enableHands,
|
|
|
|
| 1876 |
person.hand_left_keypoints_2d || [],
|
| 1877 |
person.hand_right_keypoints_2d || []
|
| 1878 |
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1879 |
// 💖 people形式のみサポート、古いhands形式は削除
|
| 1880 |
} else {
|
| 1881 |
handsDataForDrawing = [[], []]; // 空の手データ
|
|
|
|
| 1882 |
}
|
| 1883 |
|
| 1884 |
if (handsDataForDrawing && handsDataForDrawing.length >= 2) {
|
| 1885 |
drawHands(handsDataForDrawing, originalRes, scaleX, scaleY);
|
| 1886 |
debugLog(`🫳 Hands drawn: left=${handsDataForDrawing[0].length}, right=${handsDataForDrawing[1].length}`);
|
|
|
|
|
|
|
| 1887 |
}
|
| 1888 |
} catch (error) {
|
| 1889 |
console.error("❌ Error drawing hands:", error);
|
|
|
|
| 2354 |
}
|
| 2355 |
|
| 2356 |
// 💖 グローバルposeDataを更新(但し、people形式チェック付き)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2357 |
|
| 2358 |
// 🎨 背景画像が含まれている場合は設定
|
| 2359 |
if (poseData && poseData.background_image) {
|
|
|
|
| 2367 |
const existingPoseData = window.poseEditorGlobals.poseData;
|
| 2368 |
|
| 2369 |
if (isTemplateLoad) {
|
|
|
|
| 2370 |
// テンプレート読み込み時は完全置換
|
| 2371 |
window.poseEditorGlobals.poseData = poseData;
|
| 2372 |
// baseOriginalKeypointsもリセット(新しいテンプレート用)
|
| 2373 |
window.poseEditorGlobals.baseOriginalKeypoints = null;
|
| 2374 |
|
| 2375 |
+
// テンプレート読み込み時は現在のチェックボックス状態を強制取得
|
| 2376 |
updateDisplaySettingsFromCheckbox();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2377 |
|
| 2378 |
+
// チェックボックス監視も再設定
|
| 2379 |
setTimeout(() => setupGradioCheckboxListeners(), 100);
|
| 2380 |
} else if (existingPoseData && existingPoseData.people && existingPoseData.people[0] &&
|
| 2381 |
poseData && (!poseData.people || !poseData.people[0])) {
|
| 2382 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2383 |
|
| 2384 |
// Python側データを古い形式に変換してからマージ
|
| 2385 |
if (poseData.bodies || poseData.hands || poseData.faces) {
|
|
|
|
| 2398 |
}
|
| 2399 |
|
| 2400 |
// 手と顔データは既存を保持(Python側で消失している可能性があるため)
|
|
|
|
| 2401 |
|
| 2402 |
window.poseEditorGlobals.poseData = preservedPoseData;
|
| 2403 |
poseData = preservedPoseData; // 描画用も更新
|
|
|
|
| 2412 |
|
| 2413 |
// 💖 originalKeypointsも設定(但し、baseOriginalKeypointsは保護)
|
| 2414 |
if (poseData && poseData.people && poseData.people[0]) {
|
| 2415 |
+
// baseOriginalKeypointsは上書きしない(編集セッション保持のため)
|
| 2416 |
if (!window.poseEditorGlobals.baseOriginalKeypoints) {
|
| 2417 |
window.poseEditorGlobals.baseOriginalKeypoints = JSON.parse(JSON.stringify(poseData));
|
|
|
|
|
|
|
|
|
|
| 2418 |
}
|
| 2419 |
|
| 2420 |
// originalKeypointsは更新してOK(作業用)
|
| 2421 |
window.poseEditorGlobals.originalKeypoints = JSON.parse(JSON.stringify(poseData));
|
|
|
|
| 2422 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2423 |
}
|
| 2424 |
|
| 2425 |
if (!isCanvasReady()) {
|
|
|
|
| 2438 |
const ctx = window.poseEditorGlobals.ctx;
|
| 2439 |
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
| 2440 |
|
| 2441 |
+
// グローバル設定で描画(手・顔表示設定を反映)
|
| 2442 |
if (poseData && Object.keys(poseData).length > 0) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2443 |
drawPose(
|
| 2444 |
poseData,
|
| 2445 |
window.poseEditorGlobals.enableHands,
|