#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) PROJECT_ROOT=$(cd "${SCRIPT_DIR}/../.." && pwd) RESULTS_ROOT=${RESULTS_ROOT:-/data1/dongying/Mono3d/G1Q3/feishu_project/inference_issue_data} PYTHON_BIN=${PYTHON_BIN:-/deeplearning_team/ydong/dongying/miniconda/envs/dev/bin/python} TRACKING_LAUNCHER=${TRACKING_LAUNCHER:-"${PROJECT_ROOT}/tools/temporal_analysis/track_objects_exported_onnx_infer_case.sh"} ISSUE_CONVERT_SCRIPT=${ISSUE_CONVERT_SCRIPT:-"${PROJECT_ROOT}/tools/feishu_project/run_issue_data_convert_tracking.sh"} ISSUE_VISUALIZE_SCRIPT=${ISSUE_VISUALIZE_SCRIPT:-"${PROJECT_ROOT}/tools/feishu_project/run_issue_data_visualize_tracking.sh"} ISSUE_TEMPORAL_SCRIPT=${ISSUE_TEMPORAL_SCRIPT:-"${PROJECT_ROOT}/tools/feishu_project/run_issue_data_temporal_observe.sh"} TRACK_CLASSES=${TRACK_CLASSES:-0 1 2 3 4 5 6 7 8 9 10 11 12 17 18 19} IOU_THRESH=${IOU_THRESH:-0.3} MAX_AGE=${MAX_AGE:-5} MIN_HITS=${MIN_HITS:-1} DIST_THRESH=${DIST_THRESH:-100} MAX_3D_DISTANCE=${MAX_3D_DISTANCE:-10.0} MAX_FRAMES=${MAX_FRAMES:-} MERGE_OUTPUT_NAME=${MERGE_OUTPUT_NAME:-combined_tracking.json} FILE_PATTERN=${FILE_PATTERN:-*.json} ENABLE_USE_3D=${ENABLE_USE_3D:-0} ENABLE_CONVERT=${ENABLE_CONVERT:-0} ENABLE_VISUALIZE=${ENABLE_VISUALIZE:-1} ENABLE_TEMPORAL_ANALYSIS=${ENABLE_TEMPORAL_ANALYSIS:-0} CONVERT_OUTPUT_DIR_NAME=${CONVERT_OUTPUT_DIR_NAME:-objectlist} CONVERT_TRACKING_JSON_NAME=${CONVERT_TRACKING_JSON_NAME:-merge.json} CONVERT_CAM_ID=${CONVERT_CAM_ID:-} VIS_DOWNLOAD_ROOT=${VIS_DOWNLOAD_ROOT:-/data1/dongying/Mono3d/G1Q3/feishu_project/downloaded_issue_data} VIS_OUTPUT_ROOT=${VIS_OUTPUT_ROOT:-} VIS_OUTPUT_DIR_NAME=${VIS_OUTPUT_DIR_NAME:-tracking_vis_raw} VIS_TRACKING_JSON_NAME=${VIS_TRACKING_JSON_NAME:-merge.json} VIS_MAX_FRAMES=${VIS_MAX_FRAMES:-} VIS_CLASS_ID=${VIS_CLASS_ID:-} VIS_TRACK_IDS=${VIS_TRACK_IDS:-} VIS_SHOW_TRAJECTORY=${VIS_SHOW_TRAJECTORY:-0} TEMPORAL_OUTPUT_ROOT=${TEMPORAL_OUTPUT_ROOT:-} TEMPORAL_OUTPUT_DIR_NAME=${TEMPORAL_OUTPUT_DIR_NAME:-temporal_observation} TEMPORAL_JSON_NAME=${TEMPORAL_JSON_NAME:-merge.json} TEMPORAL_MIN_LENGTH=${TEMPORAL_MIN_LENGTH:-3} TEMPORAL_TRACK_IDS=${TEMPORAL_TRACK_IDS:-} TEMPORAL_CLASS_ID=${TEMPORAL_CLASS_ID:-} TEMPORAL_FRAME_ID_START=${TEMPORAL_FRAME_ID_START:-} TEMPORAL_FRAME_ID_END=${TEMPORAL_FRAME_ID_END:-} TEMPORAL_PLOTS=${TEMPORAL_PLOTS:-0} TEMPORAL_EXPORT_SERIES=${TEMPORAL_EXPORT_SERIES:-1} TEMPORAL_FOCUS_TRACK_PLOTS=${TEMPORAL_FOCUS_TRACK_PLOTS:-1} TEMPORAL_PREFER_EGO=${TEMPORAL_PREFER_EGO:-1} TEMPORAL_X_AXIS=${TEMPORAL_X_AXIS:-frame_id} TEMPORAL_HEADING_SOURCE=${TEMPORAL_HEADING_SOURCE:-camera_reg} TRACKING_MODEL_VERSION=${TRACKING_MODEL_VERSION:-20260416} TARGET_PATH=${TARGET_PATH:-} ISSUE_IDS=() while (($# > 0)); do case "$1" in --issue-id) if (($# < 2)); then echo "Error: --issue-id requires a value" >&2 exit 1 fi ISSUE_IDS+=("$2") shift 2 ;; --issue-id=*) ISSUE_IDS+=("${1#*=}") shift ;; -*) echo "Error: unsupported option: $1" >&2 exit 1 ;; *) if [[ -n "${TARGET_PATH}" ]]; then echo "Error: multiple target paths provided: ${TARGET_PATH} and $1" >&2 exit 1 fi TARGET_PATH="$1" shift ;; esac done if [[ -z "${TARGET_PATH}" ]]; then TARGET_PATH="${RESULTS_ROOT}" fi if [[ ! -d "${TARGET_PATH}" ]]; then echo "Error: target directory does not exist: ${TARGET_PATH}" >&2 exit 1 fi run_tracking_wrapper() { local target_path="$1" echo "" echo "######################################################################" echo "# Feishu issue-data tracking" echo "######################################################################" echo "Target path: ${target_path}" if [[ -n "${TRACKING_MODEL_VERSION}" ]]; then echo "Model version: ${TRACKING_MODEL_VERSION}" fi if [[ -n "${TRACKING_MODEL_VERSION}" ]]; then MODEL_VERSION="${TRACKING_MODEL_VERSION}" \ PYTHON_BIN="${PYTHON_BIN}" \ RESULTS_ROOT="${target_path}" \ TRACK_CLASSES="${TRACK_CLASSES}" \ IOU_THRESH="${IOU_THRESH}" \ MAX_AGE="${MAX_AGE}" \ MIN_HITS="${MIN_HITS}" \ DIST_THRESH="${DIST_THRESH}" \ MAX_3D_DISTANCE="${MAX_3D_DISTANCE}" \ MAX_FRAMES="${MAX_FRAMES}" \ MERGE_OUTPUT_NAME="${MERGE_OUTPUT_NAME}" \ FILE_PATTERN="${FILE_PATTERN}" \ ENABLE_USE_3D="${ENABLE_USE_3D}" \ bash "${TRACKING_LAUNCHER}" "${target_path}" return fi PYTHON_BIN="${PYTHON_BIN}" \ RESULTS_ROOT="${target_path}" \ TRACK_CLASSES="${TRACK_CLASSES}" \ IOU_THRESH="${IOU_THRESH}" \ MAX_AGE="${MAX_AGE}" \ MIN_HITS="${MIN_HITS}" \ DIST_THRESH="${DIST_THRESH}" \ MAX_3D_DISTANCE="${MAX_3D_DISTANCE}" \ MAX_FRAMES="${MAX_FRAMES}" \ MERGE_OUTPUT_NAME="${MERGE_OUTPUT_NAME}" \ FILE_PATTERN="${FILE_PATTERN}" \ ENABLE_USE_3D="${ENABLE_USE_3D}" \ bash "${TRACKING_LAUNCHER}" "${target_path}" } run_conversion_wrapper() { local target_path="$1" local convert_args=("${target_path}") for issue_id in "${ISSUE_IDS[@]}"; do convert_args+=(--issue-id "${issue_id}") done echo "" echo "######################################################################" echo "# Feishu issue-data protocol conversion" echo "######################################################################" echo "Target path : ${target_path}" echo "Tracking JSON : ${CONVERT_TRACKING_JSON_NAME}" echo "Output dir name : ${CONVERT_OUTPUT_DIR_NAME}" if [[ -n "${CONVERT_CAM_ID}" ]]; then echo "Camera ID override: ${CONVERT_CAM_ID}" fi PYTHON_BIN="${PYTHON_BIN}" \ RESULTS_ROOT="${RESULTS_ROOT}" \ OUTPUT_DIR_NAME="${CONVERT_OUTPUT_DIR_NAME}" \ MERGE_JSON_NAME="${CONVERT_TRACKING_JSON_NAME}" \ CAM_ID="${CONVERT_CAM_ID}" \ bash "${ISSUE_CONVERT_SCRIPT}" "${convert_args[@]}" } run_visualization_wrapper() { local target_path="$1" local visualize_args=("${target_path}") for issue_id in "${ISSUE_IDS[@]}"; do visualize_args+=(--issue-id "${issue_id}") done echo "" echo "######################################################################" echo "# Feishu issue-data raw-image visualization" echo "######################################################################" echo "Target path : ${target_path}" echo "Download root : ${VIS_DOWNLOAD_ROOT}" if [[ -n "${VIS_OUTPUT_ROOT}" ]]; then echo "Output root : ${VIS_OUTPUT_ROOT}" else echo "Output dir name: ${VIS_OUTPUT_DIR_NAME}" fi PYTHON_BIN="${PYTHON_BIN}" \ RESULTS_ROOT="${RESULTS_ROOT}" \ DOWNLOAD_ROOT="${VIS_DOWNLOAD_ROOT}" \ OUTPUT_ROOT="${VIS_OUTPUT_ROOT}" \ OUTPUT_DIR_NAME="${VIS_OUTPUT_DIR_NAME}" \ TRACKING_JSON_NAME="${VIS_TRACKING_JSON_NAME}" \ VIS_MAX_FRAMES="${VIS_MAX_FRAMES}" \ VIS_CLASS_ID="${VIS_CLASS_ID}" \ VIS_TRACK_IDS="${VIS_TRACK_IDS}" \ VIS_SHOW_TRAJECTORY="${VIS_SHOW_TRAJECTORY}" \ bash "${ISSUE_VISUALIZE_SCRIPT}" "${visualize_args[@]}" } run_temporal_wrapper() { local target_path="$1" local temporal_args=("${target_path}") for issue_id in "${ISSUE_IDS[@]}"; do temporal_args+=(--issue-id "${issue_id}") done if [[ -n "${TEMPORAL_CLASS_ID}" ]]; then temporal_args+=(--class-id "${TEMPORAL_CLASS_ID}") fi if [[ -n "${TEMPORAL_FRAME_ID_START}" ]]; then temporal_args+=(--frame-id-start "${TEMPORAL_FRAME_ID_START}") fi if [[ -n "${TEMPORAL_FRAME_ID_END}" ]]; then temporal_args+=(--frame-id-end "${TEMPORAL_FRAME_ID_END}") fi if [[ -n "${TEMPORAL_TRACK_IDS}" ]]; then # shellcheck disable=SC2206 local temporal_track_id_arr=(${TEMPORAL_TRACK_IDS}) for track_id in "${temporal_track_id_arr[@]}"; do temporal_args+=(--track-id "${track_id}") done fi echo "" echo "######################################################################" echo "# Feishu issue-data temporal observation" echo "######################################################################" echo "Target path : ${target_path}" if [[ -n "${TEMPORAL_CLASS_ID}" ]]; then echo "Class ID : ${TEMPORAL_CLASS_ID}" fi if [[ -n "${TEMPORAL_TRACK_IDS}" ]]; then echo "Track IDs : ${TEMPORAL_TRACK_IDS}" fi if [[ -n "${TEMPORAL_FRAME_ID_START}" || -n "${TEMPORAL_FRAME_ID_END}" ]]; then echo "Frame ID Range : [${TEMPORAL_FRAME_ID_START:-"-inf"}, ${TEMPORAL_FRAME_ID_END:-"+inf"}]" fi echo "Heading Source : ${TEMPORAL_HEADING_SOURCE}" PYTHON_BIN="${PYTHON_BIN}" \ RESULTS_ROOT="${RESULTS_ROOT}" \ OUTPUT_ROOT="${TEMPORAL_OUTPUT_ROOT}" \ OUTPUT_DIR_NAME="${TEMPORAL_OUTPUT_DIR_NAME}" \ TRACKING_JSON_NAME="${TEMPORAL_JSON_NAME}" \ TEMPORAL_MIN_LENGTH="${TEMPORAL_MIN_LENGTH}" \ TEMPORAL_CLASS_ID="${TEMPORAL_CLASS_ID}" \ TEMPORAL_TRACK_IDS="${TEMPORAL_TRACK_IDS}" \ TEMPORAL_FRAME_ID_START="${TEMPORAL_FRAME_ID_START}" \ TEMPORAL_FRAME_ID_END="${TEMPORAL_FRAME_ID_END}" \ TEMPORAL_PLOTS="${TEMPORAL_PLOTS}" \ TEMPORAL_EXPORT_SERIES="${TEMPORAL_EXPORT_SERIES}" \ TEMPORAL_FOCUS_TRACK_PLOTS="${TEMPORAL_FOCUS_TRACK_PLOTS}" \ TEMPORAL_PREFER_EGO="${TEMPORAL_PREFER_EGO}" \ TEMPORAL_X_AXIS="${TEMPORAL_X_AXIS}" \ TEMPORAL_HEADING_SOURCE="${TEMPORAL_HEADING_SOURCE}" \ bash "${ISSUE_TEMPORAL_SCRIPT}" "${temporal_args[@]}" } if [[ "${#ISSUE_IDS[@]}" -eq 0 ]]; then run_tracking_wrapper "${TARGET_PATH}" workflow_failed=0 if [[ "${ENABLE_VISUALIZE}" == "1" ]]; then if ! run_visualization_wrapper "${TARGET_PATH}"; then workflow_failed=1 fi fi if [[ "${ENABLE_TEMPORAL_ANALYSIS}" == "1" ]]; then if ! run_temporal_wrapper "${TARGET_PATH}"; then workflow_failed=1 fi fi if [[ "${ENABLE_CONVERT}" == "1" ]]; then if ! run_conversion_wrapper "${TARGET_PATH}"; then workflow_failed=1 fi fi [[ "${workflow_failed}" -eq 0 ]] exit 0 fi total_issues=0 success_issues=0 failed_issues=0 for issue_index in "${!ISSUE_IDS[@]}"; do issue_id="${ISSUE_IDS[issue_index]}" issue_root="${TARGET_PATH}/issue_${issue_id}" ((total_issues += 1)) echo "" printf '[TRACKING][%d/%d] issue_%s\n' \ "$((issue_index + 1))" "${#ISSUE_IDS[@]}" "${issue_id}" if [[ ! -d "${issue_root}" ]]; then echo "[FAIL] issue_${issue_id}: not found under ${TARGET_PATH}" >&2 ((failed_issues += 1)) continue fi if run_tracking_wrapper "${issue_root}"; then ((success_issues += 1)) else ((failed_issues += 1)) echo "[FAIL] issue_${issue_id}: tracking failed" >&2 fi done echo "" printf '[DONE] issues=%d success=%d failed=%d\n' \ "${total_issues}" "${success_issues}" "${failed_issues}" workflow_failed=0 if [[ "${ENABLE_VISUALIZE}" == "1" ]]; then if [[ "${failed_issues}" -ne 0 ]]; then echo "Skipping visualization because some tracking jobs failed" >&2 else if ! run_visualization_wrapper "${TARGET_PATH}"; then workflow_failed=1 fi fi fi if [[ "${ENABLE_TEMPORAL_ANALYSIS}" == "1" ]]; then if [[ "${failed_issues}" -ne 0 ]]; then echo "Skipping temporal observation because some tracking jobs failed" >&2 else if ! run_temporal_wrapper "${TARGET_PATH}"; then workflow_failed=1 fi fi fi if [[ "${ENABLE_CONVERT}" == "1" ]]; then if [[ "${failed_issues}" -ne 0 ]]; then echo "Skipping protocol conversion because some tracking jobs failed" >&2 else if ! run_conversion_wrapper "${TARGET_PATH}"; then workflow_failed=1 fi fi fi [[ "${failed_issues}" -eq 0 && "${workflow_failed}" -eq 0 ]]