#!/usr/bin/env bash set -Eeuo pipefail ROOT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" CONTAINER_NAME="${SCAN_CALIBRATOR_CONTAINER:-smart-cam}" SCAN_STATUS_URL="http://127.0.0.1:18080/api/v1/scan/status" HELPER_SOURCE="$ROOT_DIR/src/measure_overlap.cpp" HELPER_CONTAINER_SOURCE="/tmp/scan-calibrator-measure.cpp" HELPER_CONTAINER_BIN="/tmp/scan-calibrator-measure" info() { printf '[检查] %s\n' "$*" } ok() { printf '[通过] %s\n' "$*" } fail() { printf '[失败] %s\n' "$*" >&2 exit 1 } install_host_packages() { local -a packages=("$@") local -a elevate=() ((${#packages[@]} > 0)) || return 0 command -v apt-get >/dev/null 2>&1 || fail "缺少 ${packages[*]},且系统没有apt-get,需先按当前发行版手动安装" if ((EUID != 0)); then command -v sudo >/dev/null 2>&1 || fail "安装 ${packages[*]} 需要root权限;请用root运行本脚本" elevate=(sudo) fi info "安装宿主机依赖:${packages[*]}" "${elevate[@]}" apt-get update DEBIAN_FRONTEND=noninteractive "${elevate[@]}" apt-get install -y --no-install-recommends \ "${packages[@]}" } main() { printf 'scan-calibrator 安装与运行环境检查\n\n' local -a missing_packages=() command -v python3 >/dev/null 2>&1 || missing_packages+=(python3) if ! command -v identify >/dev/null 2>&1 || ! command -v montage >/dev/null 2>&1; then missing_packages+=(imagemagick) fi install_host_packages "${missing_packages[@]}" info "检查宿主机命令" command -v bash >/dev/null 2>&1 || fail "未找到bash" command -v python3 >/dev/null 2>&1 || fail "未找到python3" command -v identify >/dev/null 2>&1 || fail "未找到ImageMagick identify" command -v montage >/dev/null 2>&1 || fail "未找到ImageMagick montage" command -v docker >/dev/null 2>&1 || fail "未找到docker;请先部署smart-cam运行环境" docker info >/dev/null 2>&1 || fail "无法访问Docker daemon;请用有Docker权限的账号运行" ok "Python、Docker和ImageMagick命令可用" info "检查项目文件和Python语法" [[ -f "$HELPER_SOURCE" ]] || fail "缺少 $HELPER_SOURCE" [[ -f "$ROOT_DIR/interactive_calibrator.py" ]] || fail "缺少interactive_calibrator.py" [[ -f "$ROOT_DIR/scan_calibrator.py" ]] || fail "缺少scan_calibrator.py" [[ -f "$ROOT_DIR/scan-panorama/stitch_scan.py" ]] || fail "缺少scan-panorama/stitch_scan.py" python3 -B -c ' import ast import pathlib import sys for name in sys.argv[1:]: path = pathlib.Path(name) ast.parse(path.read_text(encoding="utf-8"), filename=str(path)) ' \ "$ROOT_DIR/interactive_calibrator.py" \ "$ROOT_DIR/scan_calibrator.py" \ "$ROOT_DIR/scan-panorama/stitch_scan.py" chmod +x \ "$ROOT_DIR/install.sh" \ "$ROOT_DIR/interactive.sh" \ "$ROOT_DIR/calibrate.sh" \ "$ROOT_DIR/scan-panorama/stitch.sh" mkdir -p "$ROOT_DIR/result" "$ROOT_DIR/scan-panorama/result" [[ -w "$ROOT_DIR/result" && -w "$ROOT_DIR/scan-panorama/result" ]] || fail "当前账号不能写入result目录" ok "程序文件完整且语法检查通过" info "检查smart-cam容器" [[ "$(docker inspect -f '{{.State.Running}}' "$CONTAINER_NAME" 2>/dev/null || true)" == "true" ]] || fail "容器 $CONTAINER_NAME 未运行" docker exec "$CONTAINER_NAME" sh -lc ' command -v curl >/dev/null && command -v python3 >/dev/null && command -v g++ >/dev/null && command -v pkg-config >/dev/null && pkg-config --exists opencv4 && test -f /smart-cam/config/config.json && test -d /smart-cam/data/scan && test -w /smart-cam/data/scan ' || fail "容器内缺少curl/python3/g++/OpenCV,或scan数据目录不可写" ok "容器内编译环境、配置文件和scan数据目录正常" info "编译并运行标定图像分析器自检" docker cp "$HELPER_SOURCE" "$CONTAINER_NAME:$HELPER_CONTAINER_SOURCE" >/dev/null docker exec "$CONTAINER_NAME" sh -lc \ "g++ -O2 -std=c++17 '$HELPER_CONTAINER_SOURCE' -o '$HELPER_CONTAINER_BIN' \ \$(pkg-config --cflags --libs opencv4)" docker exec "$CONTAINER_NAME" test -x "$HELPER_CONTAINER_BIN" || fail "标定图像分析器编译失败" ok "OpenCV标定图像分析器可以编译" info "检查scan HTTP服务" local status status="$(docker exec "$CONTAINER_NAME" curl -fsS --max-time 10 "$SCAN_STATUS_URL")" || fail "scan HTTP服务不可用:$SCAN_STATUS_URL" python3 -c ' import json import sys payload = json.load(sys.stdin) if not isinstance(payload.get("scan"), dict): raise SystemExit(1) ' <<<"$status" || fail "scan状态接口没有返回合法的scan JSON" ok "scan HTTP服务正常" info "检查ImageMagick拼图命令" identify -version >/dev/null montage -version >/dev/null ok "ImageMagick identify/montage正常" printf '\n全部检查通过。现在可以运行:\n cd %s\n ./interactive.sh\n' "$ROOT_DIR" } main "$@"