AccessPath / slurm /run_accesspath_demo.sbatch
anonymous-accesspath's picture
Audited anonymous-review AccessPath release
2f382c4 verified
Raw
History Blame Contribute Delete
22.5 kB
#!/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