#!/usr/bin/env bash #SBATCH -J acc-single-demo #SBATCH -p 5090 #SBATCH -G 1 #SBATCH -c 8 #SBATCH --mem=64G #SBATCH -t 04:00:00 #SBATCH -o Logs/slurm-%j.out #SBATCH -e Logs/slurm-%j.err set -euo pipefail mkdir -p Logs PROJECT_DIR="${PROJECT_DIR:-${SLURM_SUBMIT_DIR:-$PWD}}" IMAGE="${IMAGE:?Set IMAGE=/absolute/or/project-relative/image.jpg}" CATEGORY="${CATEGORY:-walkway}" SAMPLE_ID="${SAMPLE_ID:-}" OUTPUT_DIR="${OUTPUT_DIR:-$PROJECT_DIR/output/inference/$SLURM_JOB_ID}" ACCESSIBILITY3D_DIR="$OUTPUT_DIR/accessibility3d" RUN_GPU_2D="${RUN_GPU_2D:-${RUN_SD_2D:-1}}" RUN_FAST_2D="${RUN_FAST_2D:-0}" ALLOW_LARGE_2D="${ALLOW_LARGE_2D:-0}" RUN_DEPTH="${RUN_DEPTH:-1}" RUN_AMODAL3D_3D="${RUN_ACCESSIBILITYAMODAL_VISUAL_3D:-${RUN_AMODAL3D_3D:-1}}" RUN_AMODAL3D_GLB="${EXPORT_ACCESSIBILITYAMODAL_VISUAL_GLB:-${RUN_AMODAL3D_GLB:-0}}" NO_TARGET_OCCLUDER="${NO_TARGET_OCCLUDER:-0}" REVIEWED_VISIBLE_WORKSPACE="${REVIEWED_VISIBLE_WORKSPACE:-}" SAM3_PYTHON="${SAM3_PYTHON:-$PROJECT_DIR/.envs/sam3/bin/python}" AMODAL3D_PYTHON="${AMODAL3D_PYTHON:-$PROJECT_DIR/.envs/amodal3d/bin/python}" SAM3_REPO="${SAM3_REPO:-$PROJECT_DIR/repos/sam3}" SAM3_CHECKPOINT="${SAM3_CHECKPOINT:-$PROJECT_DIR/weights/sam3/sam3.pt}" AMODAL_CHECKPOINT="${AMODAL_CHECKPOINT:-$PROJECT_DIR/weights/accessibility_amodal_adapter/best.pt}" DEPTH_REPO="${DEPTH_REPO:-$PROJECT_DIR/repos/Depth-Anything-V2}" DEPTH_CHECKPOINT="${DEPTH_CHECKPOINT:-$PROJECT_DIR/weights/depth_anything_v2_metric_hypersim_vitl.pth}" PROMPT_CONFIG="${PROMPT_CONFIG:-}" if [[ -z "$PROMPT_CONFIG" ]]; then if [[ "$NO_TARGET_OCCLUDER" == "1" && "$CATEGORY" == "stairs" ]]; then PROMPT_CONFIG="$PROJECT_DIR/configs/accessibility_stairs_outdoor_no_occlusion_prompts.json" else # Unified prompt bank: SAM3 decides which target/occluder concepts are # present in the image; callers do not need to classify the scene first. PROMPT_CONFIG="$PROJECT_DIR/configs/accessibility_mask_prompts_e5_v2.json" fi fi SD_MODEL="${SD_MODEL:-$PROJECT_DIR/weights/stable-diffusion-inpainting}" AMODAL3D_MODEL="${AMODAL3D_MODEL:-$PROJECT_DIR/weights/Amodal3R}" AMODAL3D_TORCH_HOME="${AMODAL3D_TORCH_HOME:-$PROJECT_DIR/weights/torch}" LOG_SANITIZER="$PROJECT_DIR/tools/sanitize_log_stream.py" METADATA_SANITIZER="$PROJECT_DIR/tools/sanitize_output_metadata.py" VERIFICATION_TOOL="$PROJECT_DIR/tools/audit_accessibility_3d_candidate.py" REVIEWED_VISIBLE_VALIDATOR="$PROJECT_DIR/tools/validate_accessibility_reviewed_visible_workspace.py" GPU_TURNTABLE_TOOL="$PROJECT_DIR/tools/render_accessibility_turntable.py" REVIEW_BUNDLE_TOOL="$PROJECT_DIR/tools/build_accessibility_review_bundle.py" # Keep workstation usernames, home prefixes, and external paths out of the # persistent Slurm logs. Python warnings and tracebacks pass through this too. privacy_filter_args=( --project-root "$PROJECT_DIR" --output-root "$OUTPUT_DIR" --sensitive-path "$IMAGE" --sensitive-path "$PROMPT_CONFIG" --sensitive-path "$SAM3_PYTHON" --sensitive-path "$AMODAL3D_PYTHON" --sensitive-path "$SAM3_REPO" --sensitive-path "$SAM3_CHECKPOINT" --sensitive-path "$AMODAL_CHECKPOINT" --sensitive-path "$DEPTH_REPO" --sensitive-path "$DEPTH_CHECKPOINT" --sensitive-path "$SD_MODEL" --sensitive-path "$AMODAL3D_MODEL" --sensitive-path "$AMODAL3D_TORCH_HOME" ) if [[ -n "$REVIEWED_VISIBLE_WORKSPACE" ]]; then privacy_filter_args+=(--sensitive-path "$REVIEWED_VISIBLE_WORKSPACE") fi LOG_FILTER_PYTHON="$AMODAL3D_PYTHON" if [[ ! -x "$LOG_FILTER_PYTHON" ]]; then LOG_FILTER_PYTHON="$(command -v python3 || true)" fi if [[ -n "$LOG_FILTER_PYTHON" ]] && [[ -f "$LOG_SANITIZER" ]]; then exec > >("$LOG_FILTER_PYTHON" "$LOG_SANITIZER" "${privacy_filter_args[@]}") exec 2> >("$LOG_FILTER_PYTHON" "$LOG_SANITIZER" "${privacy_filter_args[@]}" >&2) fi module load cuda/13.0 || true case "$CATEGORY" in curb_cut|ramp|stairs|tactile_paving|walkway) ;; *) echo "Unsupported CATEGORY=$CATEGORY" >&2; exit 2 ;; esac if ! cd "$PROJECT_DIR" 2>/dev/null; then echo "Could not enter the configured project directory." >&2 exit 2 fi [[ -f "$IMAGE" ]] || { echo "The configured input image was not found." >&2; exit 2; } IMAGE="$(realpath "$IMAGE")" if [[ -z "$SAMPLE_ID" ]]; then SAMPLE_ID="$(basename "$IMAGE")" SAMPLE_ID="${SAMPLE_ID%.*}" SAMPLE_ID="${SAMPLE_ID//[^A-Za-z0-9_-]/_}" fi [[ -x "$AMODAL3D_PYTHON" ]] || { echo "The Accessibility3D Python environment is missing." >&2; exit 2; } for tool_path in "$VERIFICATION_TOOL" "$GPU_TURNTABLE_TOOL" "$REVIEW_BUNDLE_TOOL"; do [[ -f "$tool_path" ]] || { echo "A required AccessibilityAmodal tool is missing." >&2; exit 2; } done [[ -e "$AMODAL_CHECKPOINT" ]] || { echo "The amodal-mask runtime asset is missing." >&2; exit 2; } if [[ -n "$REVIEWED_VISIBLE_WORKSPACE" ]]; then [[ -d "$REVIEWED_VISIBLE_WORKSPACE" ]] || { echo "The reviewed-visible workspace is missing." >&2; exit 2; } [[ -f "$REVIEWED_VISIBLE_VALIDATOR" ]] || { echo "The reviewed-visible validator is missing." >&2; exit 2; } else [[ -x "$SAM3_PYTHON" ]] || { echo "The SAM3 Python environment is missing." >&2; exit 2; } for path in "$SAM3_REPO" "$SAM3_CHECKPOINT"; do [[ -e "$path" ]] || { echo "A required SAM3 runtime asset is missing." >&2; exit 2; } done fi if [[ "$RUN_DEPTH" == "1" ]]; then for path in "$DEPTH_REPO" "$DEPTH_CHECKPOINT"; do [[ -e "$path" ]] || { echo "A required depth runtime asset is missing." >&2; exit 2; } done fi if [[ "$RUN_GPU_2D" == "1" ]] && [[ ! -e "$SD_MODEL" ]]; then echo "The Stable Diffusion inpainting model is missing." >&2 exit 2 fi if [[ "$RUN_AMODAL3D_3D" == "1" ]]; then for path in \ "$AMODAL3D_MODEL/pipeline.json" \ "$AMODAL3D_TORCH_HOME/hub/facebookresearch_dinov2_main"; do [[ -e "$path" ]] || { echo "A required Accessibility3D runtime asset is missing." >&2; exit 2; } done fi export JOB_TMPDIR="$TMPDIR/job-$SLURM_JOB_ID" export XDG_CACHE_HOME="$JOB_TMPDIR/xdg_cache" export HF_HOME="$JOB_TMPDIR/huggingface" export TORCH_HOME="$JOB_TMPDIR/torch" export TRITON_CACHE_DIR="$JOB_TMPDIR/triton" export MPLCONFIGDIR="$JOB_TMPDIR/matplotlib" export PYTHONNOUSERSITE=1 mkdir -p "$JOB_TMPDIR" "$XDG_CACHE_HOME" "$HF_HOME" "$TORCH_HOME" \ "$TRITON_CACHE_DIR" "$MPLCONFIGDIR" "$OUTPUT_DIR" # These weights are seconds measured from a representative full stairs run on # the target GPU partition. They drive an approximate progress bar and ETA; actual # image complexity, cold model caches, and cluster load can change the timing. SAM3_WEIGHT=150 if [[ -n "$REVIEWED_VISIBLE_WORKSPACE" ]]; then SAM3_WEIGHT=5 fi MASK_WEIGHT=13 FAST_2D_WEIGHT=12 GPU_2D_WEIGHT=40 GEOMETRY_WEIGHT=24 if [[ "$RUN_DEPTH" != "1" ]]; then GEOMETRY_WEIGHT=6 fi TURNTABLE_WEIGHT=3 VARIANTS_WEIGHT=420 AMODAL3D_WEIGHT=75 if [[ "$RUN_AMODAL3D_GLB" == "1" ]]; then # On the 1368x1824 9528 reference run, GPU UV/PBR baking added about nine # minutes after the ordinary Gaussian and mesh renders had completed. AMODAL3D_WEIGHT=615 fi TOTAL_WEIGHT=$((SAM3_WEIGHT + MASK_WEIGHT + GEOMETRY_WEIGHT + TURNTABLE_WEIGHT + VARIANTS_WEIGHT)) if [[ "$RUN_FAST_2D" == "1" ]]; then TOTAL_WEIGHT=$((TOTAL_WEIGHT + FAST_2D_WEIGHT)) fi if [[ "$RUN_GPU_2D" == "1" ]]; then TOTAL_WEIGHT=$((TOTAL_WEIGHT + GPU_2D_WEIGHT)) fi if [[ "$RUN_AMODAL3D_3D" == "1" ]]; then TOTAL_WEIGHT=$((TOTAL_WEIGHT + AMODAL3D_WEIGHT)) fi PROGRESS_FILE="$OUTPUT_DIR/progress.json" PROGRESS_WRITER="$PROJECT_DIR/tools/update_accessibility_inference_progress.py" COMPLETED_WEIGHT=0 CURRENT_STAGE_KEY="initializing" CURRENT_STAGE_LABEL="Initializing GPU job" start_stage() { local stage_key="$1" local stage_label="$2" local stage_weight="$3" local start_percent end_percent start_percent=$((COMPLETED_WEIGHT * 100 / TOTAL_WEIGHT)) end_percent=$(((COMPLETED_WEIGHT + stage_weight) * 100 / TOTAL_WEIGHT)) CURRENT_STAGE_KEY="$stage_key" CURRENT_STAGE_LABEL="$stage_label" "$AMODAL3D_PYTHON" "$PROGRESS_WRITER" \ --path "$PROGRESS_FILE" \ --status running \ --stage-key "$stage_key" \ --stage-label "$stage_label" \ --percent "$start_percent" \ --stage-end-percent "$end_percent" \ --stage-expected-seconds "$stage_weight" \ --total-estimated-seconds "$TOTAL_WEIGHT" } finish_stage() { COMPLETED_WEIGHT=$((COMPLETED_WEIGHT + $1)) } sanitize_output_metadata() { if [[ -x "$AMODAL3D_PYTHON" ]] && [[ -f "$METADATA_SANITIZER" ]]; then "$AMODAL3D_PYTHON" "$METADATA_SANITIZER" \ --root "$OUTPUT_DIR" \ --project-root "$PROJECT_DIR" \ --sensitive-path "$IMAGE" \ --sensitive-path "$PROMPT_CONFIG" \ --sensitive-path "$SAM3_PYTHON" \ --sensitive-path "$AMODAL3D_PYTHON" \ --sensitive-path "$SAM3_REPO" \ --sensitive-path "$SAM3_CHECKPOINT" \ --sensitive-path "$AMODAL_CHECKPOINT" \ --sensitive-path "$DEPTH_REPO" \ --sensitive-path "$DEPTH_CHECKPOINT" \ --sensitive-path "$SD_MODEL" \ --sensitive-path "$AMODAL3D_MODEL" \ --sensitive-path "$AMODAL3D_TORCH_HOME" fi } record_exit() { local exit_code=$? if [[ "$exit_code" -ne 0 ]]; then set +e "$AMODAL3D_PYTHON" "$PROGRESS_WRITER" \ --path "$PROGRESS_FILE" \ --status failed \ --message "Stage failed: $CURRENT_STAGE_LABEL" \ --exit-code "$exit_code" fi sanitize_output_metadata } trap record_exit EXIT echo "Image: $IMAGE" echo "Category: $CATEGORY" echo "No target occluder mode: $NO_TARGET_OCCLUDER" echo "Reviewed visible workspace: ${REVIEWED_VISIBLE_WORKSPACE:-none}" echo "Sample ID: $SAMPLE_ID" echo "Output: $OUTPUT_DIR" echo "Estimated GPU runtime: about $(( (TOTAL_WEIGHT + 59) / 60 )) minutes (queue time excluded)" TARGET_VISIBLE_MASK="" OBSTACLE_CANDIDATE_MASK="" if [[ -n "$REVIEWED_VISIBLE_WORKSPACE" ]]; then REVIEWED_VISIBLE_OUTPUT="$OUTPUT_DIR/01_reviewed_visible" start_stage "reviewed_visible" "Validated human-reviewed visible target mask" "$SAM3_WEIGHT" "$AMODAL3D_PYTHON" "$REVIEWED_VISIBLE_VALIDATOR" \ --workspace "$REVIEWED_VISIBLE_WORKSPACE" \ --image "$IMAGE" \ --sample-id "$SAMPLE_ID" \ --category "$CATEGORY" \ --output-dir "$REVIEWED_VISIBLE_OUTPUT" finish_stage "$SAM3_WEIGHT" TARGET_VISIBLE_MASK="$REVIEWED_VISIBLE_OUTPUT/target_visible.png" OBSTACLE_CANDIDATE_MASK="$REVIEWED_VISIBLE_OUTPUT/obstacle.png" else SAM3_OUTPUT="$OUTPUT_DIR/01_sam3" start_stage "sam3" "SAM3 target and obstacle masks" "$SAM3_WEIGHT" "$SAM3_PYTHON" tools/accessibility_mask_proposals.py \ --image "$IMAGE" \ --single-sample-id "$SAMPLE_ID" \ --single-category "$CATEGORY" \ --prompt-config "$PROMPT_CONFIG" \ --output-dir "$SAM3_OUTPUT" \ --backend sam3 \ --device cuda \ --artifact-level standard \ --sam3-repo "$SAM3_REPO" \ --sam3-checkpoint "$SAM3_CHECKPOINT" finish_stage "$SAM3_WEIGHT" SAM3_SAMPLE="$SAM3_OUTPUT/samples/$SAMPLE_ID" TARGET_VISIBLE_MASK="$SAM3_SAMPLE/target_visible_candidate.png" OBSTACLE_CANDIDATE_MASK="$SAM3_SAMPLE/obstacle.png" fi MASK_OUTPUT="$OUTPUT_DIR/02_masks" start_stage "amodal_masks" "Visible, hidden, amodal, and obstacle masks" "$MASK_WEIGHT" "$AMODAL3D_PYTHON" tools/accessibility_amodal_mask.py \ --image "$IMAGE" \ --target-visible-mask "$TARGET_VISIBLE_MASK" \ --obstacle-candidate-mask "$OBSTACLE_CANDIDATE_MASK" \ --category "$CATEGORY" \ --checkpoint "$AMODAL_CHECKPOINT" \ --output-dir "$MASK_OUTPUT" \ --device cuda finish_stage "$MASK_WEIGHT" # Do not turn a rejected SAM3 proposal into a polished but physically unrelated # 3D object. The verifier records the evidence in a persistent JSON report; # a clean exit is intentional so the user can correct/re-prompt the masks. PREFLIGHT_DIR="$OUTPUT_DIR/05_quality_checks" PREFLIGHT_DECISION="$("$AMODAL3D_PYTHON" "$VERIFICATION_TOOL" \ --run-dir "$OUTPUT_DIR" \ --sample-id "$SAMPLE_ID" \ --category "$CATEGORY" \ --output "$PREFLIGHT_DIR/preflight.json" \ --preflight-only \ --print-decision)" echo "3D preflight decision: $PREFLIGHT_DECISION" if [[ "$PREFLIGHT_DECISION" != "accept" ]]; then "$AMODAL3D_PYTHON" "$PROGRESS_WRITER" \ --path "$PROGRESS_FILE" \ --status completed \ --stage-key mask_gate \ --stage-label "3D withheld: re-prompt or review masks" \ --percent 100 \ --stage-end-percent 100 \ --stage-expected-seconds 0 \ --total-estimated-seconds "$TOTAL_WEIGHT" \ --message "3D preflight=$PREFLIGHT_DECISION; see 05_quality_checks/preflight.json" echo "3D generation withheld. Review: $PREFLIGHT_DIR/preflight.json" exit 0 fi if [[ "$RUN_FAST_2D" == "1" ]]; then start_stage "fast_2d" "Optional OpenCV 2D baseline" "$FAST_2D_WEIGHT" completion_cmd=( "$AMODAL3D_PYTHON" tools/accessibility_fast_2d_baseline.py --image "$IMAGE" --single-sample-id "$SAMPLE_ID" --target-visible-mask "$MASK_OUTPUT/target_visible.png" --target-amodal-mask "$MASK_OUTPUT/target_amodal.png" --hidden-mask "$MASK_OUTPUT/hidden.png" --obstacle-mask "$MASK_OUTPUT/obstacle.png" --output-dir "$OUTPUT_DIR/03_fast_2d_baseline" --mask-mode hidden --opencv-mode pyramid --overwrite ) if [[ "$ALLOW_LARGE_2D" == "1" ]]; then completion_cmd+=(--allow-large-mask) fi "${completion_cmd[@]}" finish_stage "$FAST_2D_WEIGHT" fi if [[ "$RUN_GPU_2D" == "1" ]]; then start_stage "gpu_2d" "GPU generative 2D completion and candidate selection" "$GPU_2D_WEIGHT" "$AMODAL3D_PYTHON" tools/accessibility_2d_completion.py \ --image "$IMAGE" \ --mask "$MASK_OUTPUT/hidden.png" \ --obstacle-mask "$MASK_OUTPUT/obstacle_all_detected.png" \ --target-visible-mask "$MASK_OUTPUT/target_visible.png" \ --target-amodal-mask "$MASK_OUTPUT/target_amodal.png" \ --category "$CATEGORY" \ --output-dir "$OUTPUT_DIR/03_2d_completion" \ --model "$SD_MODEL" \ --device cuda finish_stage "$GPU_2D_WEIGHT" COMPLETION_STATUS="$("$AMODAL3D_PYTHON" -c 'import json,sys; print(json.load(open(sys.argv[1], encoding="utf-8")).get("status", "completed"))' "$OUTPUT_DIR/03_2d_completion/manifest.json")" echo "2D completion quality status: $COMPLETION_STATUS" case "$COMPLETION_STATUS" in candidate_selected_for_review|skipped_empty_removal_mask) ;; *) echo "The 2D candidate needs review and will not condition either 3D backend." echo "Accessibility3D will still use the original RGB plus the strict three-value mask." ;; esac fi start_stage "geometry" "Depth and 3D geometry reconstruction" "$GEOMETRY_WEIGHT" REFERENCE_IMAGE="" if [[ "$RUN_GPU_2D" == "1" ]] \ && [[ "${COMPLETION_STATUS:-}" =~ ^(candidate_selected_for_review|skipped_empty_removal_mask)$ ]]; then REFERENCE_IMAGE="$OUTPUT_DIR/03_2d_completion/completed_rgb_selected.png" fi pipeline_cmd=( "$AMODAL3D_PYTHON" -m accessibilityamodal.pipeline --image "$IMAGE" --sample-id "$SAMPLE_ID" --preset "$CATEGORY" --target-visible-mask "$MASK_OUTPUT/target_visible.png" --target-amodal-mask "$MASK_OUTPUT/target_amodal.png" --obstacle-mask "$MASK_OUTPUT/obstacle.png" --output-dir "$OUTPUT_DIR/04_3d_completion" ) if [[ -n "$REFERENCE_IMAGE" ]]; then pipeline_cmd+=( --reference-image "$REFERENCE_IMAGE" --completed-rgb "$REFERENCE_IMAGE" ) fi if [[ "$RUN_DEPTH" == "1" ]]; then pipeline_cmd+=( --estimate-depth --depth-engine depth_anything_v2 --depth-device cuda --depth-anything-repo "$DEPTH_REPO" --depth-checkpoint "$DEPTH_CHECKPOINT" --depth-encoder vitl --metric-depth --max-depth 20 --depth-fallback error ) fi "${pipeline_cmd[@]}" finish_stage "$GEOMETRY_WEIGHT" start_stage "surface_variants" "Auxiliary surface and canonical 3D views" "$VARIANTS_WEIGHT" variants_cmd=( "$AMODAL3D_PYTHON" tools/accessibility_3d_variants.py --geometry-dir "$OUTPUT_DIR/04_3d_completion/geometry" --output-dir "$OUTPUT_DIR/04_3d_completion/geometry/presentation_models" --sample-id "$SAMPLE_ID" --category "$CATEGORY" --frames 72 --duration-ms 140 --hidden-tint 0 --model-only ) if [[ -n "$REFERENCE_IMAGE" ]]; then variants_cmd+=(--texture-image "$REFERENCE_IMAGE") fi "${variants_cmd[@]}" finish_stage "$VARIANTS_WEIGHT" PRESENTATION_MESH="$OUTPUT_DIR/04_3d_completion/geometry/completed_mesh.ply" if [[ -f "$OUTPUT_DIR/04_3d_completion/geometry/presentation_models/02_canonical_stairs/02_canonical_stairs.ply" ]]; then PRESENTATION_MESH="$OUTPUT_DIR/04_3d_completion/geometry/presentation_models/02_canonical_stairs/02_canonical_stairs.ply" elif [[ -f "$OUTPUT_DIR/04_3d_completion/geometry/presentation_models/02_continuous_support_surface/02_continuous_support_surface.ply" ]]; then PRESENTATION_MESH="$OUTPUT_DIR/04_3d_completion/geometry/presentation_models/02_continuous_support_surface/02_continuous_support_surface.ply" fi start_stage "turntable" "Diagnostic category-geometry turntable" "$TURNTABLE_WEIGHT" "$AMODAL3D_PYTHON" "$GPU_TURNTABLE_TOOL" \ --ply "$PRESENTATION_MESH" \ --output-dir "$OUTPUT_DIR/04_3d_completion/turntable" \ --sample-id "$SAMPLE_ID" \ --category "$CATEGORY" \ --frames 96 \ --fps 24 \ --shader defaultUnlit \ --background 0.82,0.82,0.80,1 \ --orbit-mode front_arc \ --orbit-span 140 \ --multiview-yaws=-60,-30,0,30,60 \ --require-vertex-colors finish_stage "$TURNTABLE_WEIGHT" if [[ "$RUN_AMODAL3D_3D" == "1" ]]; then start_stage "amodal3d" "Accessibility3D CUDA Gaussian rotation and dense mesh" "$AMODAL3D_WEIGHT" amodal3d_cmd=( "$AMODAL3D_PYTHON" tools/accessibility_3d_completion.py --image "$IMAGE" --conditioning-rgb original --mask "$OUTPUT_DIR/04_3d_completion/amodal3d_three_value_mask.png" --output-dir "$ACCESSIBILITY3D_DIR" --model "$AMODAL3D_MODEL" ) # Match the known-good 9527 run: the learned backend receives the original # display-oriented RGB and the strict reviewed three-value condition mask. # The separate 2D inpaint must never become foggy texture conditioning here. if [[ "$RUN_AMODAL3D_GLB" == "1" ]]; then amodal3d_cmd+=(--export-glb) fi AMODAL3D_TORCH_HOME="$AMODAL3D_TORCH_HOME" "${amodal3d_cmd[@]}" finish_stage "$AMODAL3D_WEIGHT" POST_3D_DECISION="$("$AMODAL3D_PYTHON" "$VERIFICATION_TOOL" \ --run-dir "$OUTPUT_DIR" \ --sample-id "$SAMPLE_ID" \ --category "$CATEGORY" \ --output "$PREFLIGHT_DIR/verification.json" \ --print-decision)" echo "Generated 3D verification decision: $POST_3D_DECISION" if [[ "$POST_3D_DECISION" == "accept" ]]; then echo "Local 3D candidate passed the reconstruction-quality gate." echo "Paper/GitHub packaging is intentionally withheld pending explicit human release approval for license/privacy and calibrated-geometry review." else echo "Learned 3D debug artifacts are withheld because generated 3D verification=$POST_3D_DECISION" fi fi # Normalize persistent upstream manifests before the review bundle records # their byte hashes. The EXIT trap runs the same sanitizer again as a final # privacy guard, but it is idempotent and must not invalidate review provenance. sanitize_output_metadata if [[ "$RUN_GPU_2D" == "1" ]]; then PRIMARY_3D_ROLE="open_world_accessibility_surface" PRIMARY_3D_GIF="$OUTPUT_DIR/04_3d_completion/turntable/turntable.gif" PRIMARY_3D_MULTIVIEW="$OUTPUT_DIR/04_3d_completion/turntable/multiview.jpg" PRIMARY_3D_MESH="$PRESENTATION_MESH" if [[ "$RUN_AMODAL3D_3D" == "1" && "${POST_3D_DECISION:-}" == "accept" && -f "$ACCESSIBILITY3D_DIR/sample_gaussian.gif" && -f "$ACCESSIBILITY3D_DIR/multiview_contact_sheet.jpg" && -f "$ACCESSIBILITY3D_DIR/mesh.ply" ]]; then PRIMARY_3D_ROLE="learned_amodal3d_gaussian" PRIMARY_3D_GIF="$ACCESSIBILITY3D_DIR/sample_gaussian.gif" PRIMARY_3D_MULTIVIEW="$ACCESSIBILITY3D_DIR/multiview_contact_sheet.jpg" PRIMARY_3D_MESH="$ACCESSIBILITY3D_DIR/mesh.ply" fi review_cmd=( "$AMODAL3D_PYTHON" "$REVIEW_BUNDLE_TOOL" --source "$IMAGE" --completion-2d "$OUTPUT_DIR/03_2d_completion/completed_rgb_selected.png" --turntable-gif "$PRIMARY_3D_GIF" --multiview "$PRIMARY_3D_MULTIVIEW" --mesh "$PRIMARY_3D_MESH" --primary-3d-role "$PRIMARY_3D_ROLE" --completion-manifest "$OUTPUT_DIR/03_2d_completion/manifest.json" --geometry-manifest "$OUTPUT_DIR/04_3d_completion/geometry/geometry_manifest.json" --category "$CATEGORY" --sample-id "$SAMPLE_ID" --output-dir "$OUTPUT_DIR" ) if [[ -f "$PREFLIGHT_DIR/verification.json" ]]; then review_cmd+=( --verification-manifest "$PREFLIGHT_DIR/verification.json" ) fi "${review_cmd[@]}" fi FINAL_STAGE_LABEL="All requested local outputs completed" if [[ "$RUN_AMODAL3D_3D" == "1" ]]; then FINAL_STAGE_LABEL="Local 3D outputs completed; public release withheld pending human approval" if [[ "$POST_3D_DECISION" != "accept" ]]; then FINAL_STAGE_LABEL="3D debug artifacts generated but withheld after verification" fi fi "$AMODAL3D_PYTHON" "$PROGRESS_WRITER" \ --path "$PROGRESS_FILE" \ --status completed \ --stage-key completed \ --stage-label "$FINAL_STAGE_LABEL" \ --percent 100 \ --stage-end-percent 100 \ --stage-expected-seconds 0 \ --total-estimated-seconds "$TOTAL_WEIGHT" echo "Completed. Review these first:" if [[ "$RUN_GPU_2D" == "1" ]]; then echo " $OUTPUT_DIR/00_quick_review/overview.jpg" echo " $OUTPUT_DIR/00_quick_review/03_3d_turntable.gif" fi echo " $MASK_OUTPUT/mask_overlay.png" if [[ "$RUN_GPU_2D" == "1" ]]; then echo " $OUTPUT_DIR/03_2d_completion/completed_rgb_selected.png" echo " $OUTPUT_DIR/03_2d_completion/candidate_comparison.jpg" fi if [[ "$RUN_FAST_2D" == "1" ]]; then echo " $OUTPUT_DIR/03_fast_2d_baseline/$SAMPLE_ID/contact_sheet.jpg" fi echo " $OUTPUT_DIR/04_3d_completion/geometry/completed_region_overlay.png" echo " $OUTPUT_DIR/04_3d_completion/geometry/completed_mesh.ply" echo " $OUTPUT_DIR/04_3d_completion/geometry/presentation_models/manifest.json" echo " diagnostic geometry mesh: $PRESENTATION_MESH" if [[ "$RUN_AMODAL3D_3D" == "1" ]]; then echo " $OUTPUT_DIR/05_quality_checks/verification.json" echo " source-colored CUDA rotation: $ACCESSIBILITY3D_DIR/sample_gaussian.gif" echo " CUDA mesh-normal diagnostic: $ACCESSIBILITY3D_DIR/sample_mesh.gif" echo " primary multiview: $ACCESSIBILITY3D_DIR/multiview_contact_sheet.jpg" echo " dense triangle mesh: $ACCESSIBILITY3D_DIR/mesh.ply" if [[ "$RUN_AMODAL3D_GLB" == "1" ]]; then echo " dense GLB mesh: $ACCESSIBILITY3D_DIR/mesh.glb" fi fi