Claude: Findet .npz Fehler
This commit is contained in:
BIN
setup/generateSets/__pycache__/render_Loop.cpython-311.pyc
Normal file
BIN
setup/generateSets/__pycache__/render_Loop.cpython-311.pyc
Normal file
Binary file not shown.
BIN
setup/generateSets/__pycache__/render_robot.cpython-311.pyc
Normal file
BIN
setup/generateSets/__pycache__/render_robot.cpython-311.pyc
Normal file
Binary file not shown.
@@ -5,10 +5,17 @@ import shutil
|
||||
from pathlib import Path
|
||||
import argparse
|
||||
|
||||
STATE_KEYS = ("x", "y", "z", "a", "b", "c", "e")
|
||||
|
||||
|
||||
def update_robot_json(robot_json_file, camera_position, camera_target, default_position, width, height, fstop):
|
||||
"""Aktualisiert die cameraPosition und defaultPosition in der robot.json-Datei."""
|
||||
"""Aktualisiert cameraPosition/Target, Auflösung und defaultPosition in robot.json.
|
||||
|
||||
Hinweis: render_robot.py liest robot.json bei jedem Blender-Start frisch ein,
|
||||
deshalb wird hier pro Kamera in die Datei geschrieben.
|
||||
"""
|
||||
try:
|
||||
with open(robot_json_file, 'r') as f:
|
||||
with open(robot_json_file, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
data['renderingInfo']['cameraPosition'] = camera_position
|
||||
@@ -18,7 +25,7 @@ def update_robot_json(robot_json_file, camera_position, camera_target, default_p
|
||||
data['renderingInfo']['dofFStop'] = fstop
|
||||
data['defaultPosition'] = default_position
|
||||
|
||||
with open(robot_json_file, 'w') as f:
|
||||
with open(robot_json_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(data, f, indent=2)
|
||||
except FileNotFoundError:
|
||||
print(f"Fehler: Datei {robot_json_file} nicht gefunden.")
|
||||
@@ -28,6 +35,7 @@ def update_robot_json(robot_json_file, camera_position, camera_target, default_p
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def run_blender(blender_executable, script_path, log_level):
|
||||
"""Führt Blender mit dem angegebenen Skript aus."""
|
||||
try:
|
||||
@@ -45,8 +53,9 @@ def run_blender(blender_executable, script_path, log_level):
|
||||
print(f"Blender-Skript fehlgeschlagen:\n{e.stderr}")
|
||||
return False
|
||||
|
||||
|
||||
def copy_and_rename_file(source_file, destination_dir, new_filename):
|
||||
"""Kopiert die erstellte Bilddatei in den Zielordner und benennt sie um."""
|
||||
"""Kopiert die erstellte Datei in den Zielordner und benennt sie um."""
|
||||
destination_path = os.path.join(destination_dir, new_filename)
|
||||
try:
|
||||
shutil.copy2(source_file, destination_path) # copy2 behält Metadaten
|
||||
@@ -58,118 +67,133 @@ def copy_and_rename_file(source_file, destination_dir, new_filename):
|
||||
print(f"Fehler beim Kopieren/Umbenennen der Datei: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def load_render_config(robot_json_file):
|
||||
"""Liest Posen, Kamera-Setup und Render-Defaults aus robot.json."""
|
||||
with open(robot_json_file, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
poses = data.get("robot_test_poses", {}) or {}
|
||||
cam_positions = data.get("test_camera_positions", {}) or {}
|
||||
cam_targets = data.get("test_camera_targets", {}) or {}
|
||||
|
||||
rinfo = data.get("renderingInfo", {}) or {}
|
||||
default_rendering = {
|
||||
"width": int(rinfo.get("width", 1280)),
|
||||
"height": int(rinfo.get("height", 720)),
|
||||
"dofFStop": float(rinfo.get("dofFStop", 11)),
|
||||
}
|
||||
|
||||
return poses, cam_positions, cam_targets, default_rendering
|
||||
|
||||
|
||||
def split_pose(pose_entry):
|
||||
"""Trennt eine robot_test_poses-Definition in (joint_state, rendering_override)."""
|
||||
joint_state = {k: pose_entry[k] for k in STATE_KEYS if k in pose_entry}
|
||||
rendering_override = pose_entry.get("rendering", {}) or {}
|
||||
return joint_state, rendering_override
|
||||
|
||||
|
||||
def main():
|
||||
USER_HOME = Path.home()
|
||||
ROBOT_JSON_FILE = str(USER_HOME / "SynologyDrive" / "2026-AppServer-AppRobot" / "appRobotRendering" / "data" / "robot" / "robot.json")
|
||||
OUTPUT_DIR = str(USER_HOME / "SynologyDrive" / "2026-AppServer-AppRobot" / "appRobotRendering" / "data" / "simulation" / "debug" )
|
||||
BASE = USER_HOME / "SynologyDrive" / "2026-AppServer-AppRobot" / "appRobotRendering"
|
||||
|
||||
ROBOT_JSON_FILE = str(BASE / "data" / "robot" / "robot.json")
|
||||
OUTPUT_DIR = str(BASE / "data" / "simulation" / "debug")
|
||||
BLENDER_EXE = str("C:/Program Files/Blender Foundation/Blender 4.5/blender.exe")
|
||||
RENDER_PY= str(USER_HOME /"SynologyDrive" / "2026-AppServer-AppRobot" / "appRobotRendering"/ "setup"/"generateSets"/"render_robot.py")
|
||||
RENDER_PNG=str(USER_HOME /"SynologyDrive" / "2026-AppServer-AppRobot" / "appRobotRendering"/"data"/"simulation"/"debug"/"render.png")
|
||||
OUTPUT_SET = str(USER_HOME / "SynologyDrive" / "2026-AppServer-AppRobot" / "appRobotRendering" / "data" / "simulation" )
|
||||
|
||||
RENDER_PY = str(BASE / "setup" / "generateSets" / "render_robot.py")
|
||||
RENDER_PNG = str(BASE / "data" / "simulation" / "debug" / "render.png")
|
||||
OUTPUT_SET = str(BASE / "data" / "simulation")
|
||||
|
||||
parser = argparse.ArgumentParser(description="Automatisiert die Roboter-Rendering-Pipeline.")
|
||||
parser.add_argument("robot_json", nargs="?",
|
||||
default=ROBOT_JSON_FILE, help="Pfad zur robot.json-Datei.")
|
||||
parser.add_argument("blender_executable",nargs="?",
|
||||
default=BLENDER_EXE, help="Pfad zur Blender-Executable.")
|
||||
parser.add_argument("render_script",
|
||||
default=RENDER_PY,
|
||||
help="Pfad zum render_robot.py-Skript.",nargs="?")
|
||||
parser.add_argument("render_png",nargs="?",
|
||||
default=RENDER_PNG,help="script erzeugte png")
|
||||
parser.add_argument("output_dir", nargs="?",
|
||||
default=OUTPUT_DIR, help="Zielordner für die gerenderten Blender Bilder.")
|
||||
parser.add_argument("output_set", nargs="?",
|
||||
default=OUTPUT_SET, help="Zielordner in dem die Sets abgelegt werden")
|
||||
parser.add_argument("robot_json", nargs="?", default=ROBOT_JSON_FILE, help="Pfad zur robot.json-Datei.")
|
||||
parser.add_argument("blender_executable", nargs="?", default=BLENDER_EXE, help="Pfad zur Blender-Executable.")
|
||||
parser.add_argument("render_script", nargs="?", default=RENDER_PY, help="Pfad zum render_robot.py-Skript.")
|
||||
parser.add_argument("render_png", nargs="?", default=RENDER_PNG, help="vom Skript erzeugte png")
|
||||
parser.add_argument("output_dir", nargs="?", default=OUTPUT_DIR, help="Zielordner für die gerenderten Blender Bilder.")
|
||||
parser.add_argument("output_set", nargs="?", default=OUTPUT_SET, help="Zielordner in dem die Sets abgelegt werden")
|
||||
parser.add_argument("--poses", nargs="*", default=None,
|
||||
help="Nur diese Pose-Keys rendern (z.B. --poses 8 9). Default: alle aus robot_test_poses.")
|
||||
parser.add_argument("--scene_prefix", default="Scene", help="Präfix für die Scene-Ordnernamen (Default: Scene).")
|
||||
parser.add_argument("--log_level", type=int, default=2, help="Log-Level für Blender (Standard: 2).")
|
||||
args = parser.parse_args()
|
||||
|
||||
# Kamerapositions-Dictionary
|
||||
camera_positions = {
|
||||
"a": [-300, -800, 800],
|
||||
"b": [300, -900, 1200],
|
||||
"c": [300, -900, 400],
|
||||
"d": [700, -800, 400],
|
||||
"e": [1200, -900, 400],
|
||||
"f": [500, -300, 1400],
|
||||
"g": [-200, 200, 1400],
|
||||
}
|
||||
camera_targets = {
|
||||
"a": [210, -100, 180],
|
||||
"b": [310, -80, 180],
|
||||
"c": [210, -100, 150],
|
||||
"d": [210, -100, 150],
|
||||
"e": [210, -100, 50],
|
||||
"f": [200, -200, 180],
|
||||
"g": [200, -200, 180],
|
||||
}
|
||||
|
||||
# Konfiguration aus robot.json
|
||||
robot_poses, camera_positions, camera_targets, default_rendering = load_render_config(args.robot_json)
|
||||
|
||||
# Robot-Pose-Dictionary
|
||||
robot_poses = {
|
||||
#"4": {"x": 70, "y": 50,"z": -70,"a": 120,"b": 50,"c": 30,"e": 20},
|
||||
#"5": {"x": 180,"y": 86,"z": -120,"a": -60,"b": 22,"c": 91,"e": 10},
|
||||
#"6": {"x": 80, "y": 20, "z": 80, "a": -120, "b": 23, "c": 9, "e": 3},
|
||||
#"7": {"x": 30, "y": -2, "z": 95, "a": 20, "b": 23, "c": 9, "e": 9},
|
||||
#"8": {"x": 50, "y": -2, "z": 95, "a": 20, "b": 60, "c": 9, "e": 3},
|
||||
#"9": {"x": 60, "y": -2, "z": 95, "a": 200, "b": 60, "c": 9, "e": 8},
|
||||
#"9a": {"x": 60, "y": -2, "z": 95, "a": 200, "b": 60, "c": 9, "e": 8},
|
||||
"9b": {"x": 60, "y": -2, "z": 95, "a": 200, "b": 60, "c": 9, "e": 8},
|
||||
#"10": {"x": 120, "y": 60, "z": -110, "a": 20, "b": 30, "c": 180, "e": 4},
|
||||
#"11": {"x": 50, "y": 4, "z": 176, "a": 20, "b": 60, "c": 9, "e": 5},
|
||||
#"12": {"x": 50, "y": 0, "z": 178, "a": 210, "b": 80, "c": 90, "e": 6},
|
||||
}
|
||||
if not robot_poses:
|
||||
print("Keine 'robot_test_poses' in robot.json gefunden.")
|
||||
return
|
||||
if not camera_positions:
|
||||
print("Keine 'test_camera_positions' in robot.json gefunden.")
|
||||
return
|
||||
|
||||
renderingInfos = {
|
||||
"4": {"width":1280, "height":720, "dofFStop":11},
|
||||
"5": {"width":1280, "height":720, "dofFStop":11},
|
||||
"6": {"width":1280, "height":720, "dofFStop":11},
|
||||
"7": {"width":1280, "height":720, "dofFStop":11},
|
||||
"8": {"width":1280, "height":720, "dofFStop":11},
|
||||
"9": {"width":1280, "height":720, "dofFStop":11},
|
||||
"9a": {"width":1440, "height":1080, "dofFStop":11},
|
||||
"9b": {"width":4896, "height":3264, "dofFStop":5.6},
|
||||
"10": {"width":1280, "height":720, "dofFStop":11},
|
||||
"11": {"width":1280, "height":720, "dofFStop":11},
|
||||
"12": {"width":1280, "height":720, "dofFStop":11},
|
||||
}
|
||||
# Optionaler Pose-Filter
|
||||
if args.poses:
|
||||
missing = [p for p in args.poses if p not in robot_poses]
|
||||
for p in missing:
|
||||
print(f"[WARN] Pose '{p}' nicht in robot_test_poses – wird übersprungen.")
|
||||
selected = {p: robot_poses[p] for p in args.poses if p in robot_poses}
|
||||
else:
|
||||
selected = robot_poses
|
||||
|
||||
for pose_name, default_position in robot_poses.items():
|
||||
new_folder = Path(args.output_set) / f"Scene{pose_name}"
|
||||
print(f"Zu rendernde Posen: {list(selected.keys())}")
|
||||
print(f"Kameras pro Pose: {list(camera_positions.keys())}")
|
||||
|
||||
for pose_name, pose_entry in selected.items():
|
||||
joint_state, rendering_override = split_pose(pose_entry)
|
||||
|
||||
# Render-Settings: globaler Default, pro Pose überschreibbar
|
||||
rendering = dict(default_rendering)
|
||||
rendering.update({k: rendering_override[k] for k in ("width", "height", "dofFStop") if k in rendering_override})
|
||||
|
||||
new_folder = Path(args.output_set) / f"{args.scene_prefix}{pose_name}"
|
||||
os.makedirs(new_folder, exist_ok=True)
|
||||
|
||||
renderingInfo = renderingInfos[pose_name]
|
||||
print(renderingInfo)
|
||||
|
||||
|
||||
print(f"\n=== Scene {pose_name} | {rendering['width']}x{rendering['height']} f/{rendering['dofFStop']} ===")
|
||||
|
||||
# Ground-Truth-Record: Joint-Pose + Kamera-Setup (für spätere Messung/GT-Posen)
|
||||
pose_file = new_folder / "pose.json"
|
||||
pose_data = {"name": pose_name,"position": default_position, "camera_positions": camera_positions}
|
||||
with open(pose_file, "w") as f:
|
||||
pose_data = {
|
||||
"name": pose_name,
|
||||
"position": joint_state,
|
||||
"rendering": rendering,
|
||||
"camera_positions": camera_positions,
|
||||
"camera_targets": camera_targets,
|
||||
}
|
||||
with open(pose_file, "w", encoding="utf-8") as f:
|
||||
json.dump(pose_data, f, indent=2)
|
||||
|
||||
for frame_name, camera_position in camera_positions.items():
|
||||
camera_target = camera_targets.get(frame_name)
|
||||
if camera_target is None:
|
||||
print(f"[WARN] Kein Target für Kamera '{frame_name}' – übersprungen.")
|
||||
continue
|
||||
|
||||
camera_target = camera_targets[frame_name]
|
||||
# 1. robot.json für diesen Render aktualisieren
|
||||
if not update_robot_json(args.robot_json, camera_position, camera_target, joint_state,
|
||||
rendering["width"], rendering["height"], rendering["dofFStop"]):
|
||||
continue
|
||||
|
||||
# 1. JSON aktualisieren
|
||||
if not update_robot_json(args.robot_json, camera_position, camera_target, default_position, renderingInfo["width"], renderingInfo["height"], renderingInfo["dofFStop"]):
|
||||
continue # Gehe zum nächsten Schleifendurchlauf
|
||||
|
||||
# 2. Blender-Skript ausführen
|
||||
# 2. Blender ausführen
|
||||
if not run_blender(args.blender_executable, args.render_script, args.log_level):
|
||||
continue # Gehe zum nächsten Schleifendurchlauf
|
||||
continue
|
||||
|
||||
# 3. Datei kopieren und umbenennen
|
||||
# 3. Ergebnisse kopieren und umbenennen (png, npz, markers.json)
|
||||
new_filename = f"render_{frame_name}.png"
|
||||
if not copy_and_rename_file(args.render_png, new_folder, new_filename):
|
||||
continue # Gehe zum nächsten Schleifendurchlauf
|
||||
|
||||
if not copy_and_rename_file(args.render_png.replace(".png",".npz"), new_folder, new_filename.replace(".png",".npz")):
|
||||
continue # Gehe zum nächsten Schleifendurchlauf
|
||||
|
||||
if not copy_and_rename_file(args.render_png.replace("render.png","markers.json"), new_folder, new_filename.replace(".png",".json")):
|
||||
continue # Gehe zum nächsten Schleifendurchlauf
|
||||
continue
|
||||
if not copy_and_rename_file(args.render_png.replace(".png", ".npz"),
|
||||
new_folder, new_filename.replace(".png", ".npz")):
|
||||
continue
|
||||
if not copy_and_rename_file(args.render_png.replace("render.png", "markers.json"),
|
||||
new_folder, new_filename.replace(".png", ".json")):
|
||||
continue
|
||||
|
||||
print(f" Frame {frame_name}: OK")
|
||||
|
||||
print(f"Scene {pose_name} fertig -> {new_folder}")
|
||||
|
||||
print(f"Rendering für Frame {frame_name}, Scene {pose_name} erfolgreich abgeschlossen.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
||||
@@ -465,22 +465,35 @@ CALIBRATION_OUTPUT = str(
|
||||
render = scene.render
|
||||
cam = cam_obj.data
|
||||
|
||||
width_px = render.resolution_x
|
||||
height_px = render.resolution_y
|
||||
|
||||
scale = render.resolution_percentage / 100.0
|
||||
width_px = render.resolution_x * scale
|
||||
height_px = render.resolution_y * scale
|
||||
|
||||
width_px *= scale
|
||||
height_px *= scale
|
||||
|
||||
focal_mm = cam.lens
|
||||
sensor_width_mm = cam.sensor_width
|
||||
sensor_height_mm = cam.sensor_height
|
||||
|
||||
focal_mm = cam.lens
|
||||
# Pixel aspect ratio (1.0 for synthetic cameras with square pixels)
|
||||
pixel_aspect_ratio = render.pixel_aspect_y / render.pixel_aspect_x
|
||||
|
||||
# focal length in pixels
|
||||
fx = (width_px * focal_mm) / sensor_width_mm
|
||||
fy = (height_px * focal_mm) / sensor_height_mm
|
||||
# Blender's 'sensor_fit' decides which sensor axis defines the focal length.
|
||||
# With AUTO it is the longer (pixel-aspect-weighted) image axis, and pixels are
|
||||
# square (fy == fx). The previous code used sensor_height for fy, which only
|
||||
# matched at a 3:2 aspect ratio and was ~15% off at 16:9 (e.g. 1280x720).
|
||||
sensor_fit = cam.sensor_fit
|
||||
if sensor_fit == 'AUTO':
|
||||
sensor_fit = 'HORIZONTAL' if width_px >= height_px * pixel_aspect_ratio else 'VERTICAL'
|
||||
|
||||
if sensor_fit == 'HORIZONTAL':
|
||||
sensor_size_mm = sensor_width_mm
|
||||
view_fac_px = width_px
|
||||
else: # VERTICAL
|
||||
sensor_size_mm = sensor_height_mm
|
||||
view_fac_px = pixel_aspect_ratio * height_px
|
||||
|
||||
f_px = focal_mm * view_fac_px / sensor_size_mm
|
||||
fx = f_px
|
||||
fy = f_px / pixel_aspect_ratio # square pixels => fy == fx
|
||||
|
||||
cx = width_px / 2.0
|
||||
cy = height_px / 2.0
|
||||
|
||||
Reference in New Issue
Block a user