{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %% [Code cell 0]: Imports & paths\n",
    "import os\n",
    "import sys\n",
    "import shutil\n",
    "import subprocess\n",
    "import numpy as np\n",
    "import cv2\n",
    "from PIL import Image\n",
    "import matplotlib.pyplot as plt\n",
    "import torch\n",
    "\n",
    "# Distill-Any-Depth 관련 경로\n",
    "DISTILL_BASE_DIR = \"/ltb/media/ltb/90887173887158A4/Users/ltb/모델들/Distill-Any-Depth\"\n",
    "DISTILL_INFER_SCRIPT = os.path.join(DISTILL_BASE_DIR, \"scripts/00_infer.sh\")\n",
    "DISTILL_INPUT_DIR = os.path.join(DISTILL_BASE_DIR, \"data\", \"input\")\n",
    "DISTILL_OUTPUT_DIR = os.path.join(DISTILL_BASE_DIR, \"output\", \"large\")\n",
    "\n",
    "# Depth-Anything-V2 관련 경로\n",
    "DEPTH_ANYTHING_DIR = \"/ltb/media/ltb/90887173887158A4/Users/ltb/회사용/4090_옮길거/workspace/Depth-Anything-V2\"\n",
    "DEPTH_ANYTHING_CHECKPOINT_VITL = os.path.join(DEPTH_ANYTHING_DIR, \"checkpoints/depth_anything_v2_vitl.pth\")\n",
    "DEPTH_ENCODER_TYPE = \"vitl\"\n",
    "\n",
    "# 입력 이미지 폴더 (Distill-Any-Depth와 동일 폴더로 가정)\n",
    "INPUT_FOLDER = DISTILL_INPUT_DIR  # \"/.../Distill-Any-Depth/data/input\"\n",
    "# 최종 비교 결과 저장 폴더\n",
    "COMPARE_DEPTH_SAVE_DIR = \"/ltb/media/ltb/90887173887158A4/Users/ltb/compare_depth\"\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %% [1] Distill-Any-Depth 추론\n",
    "def run_distill_any_depth():\n",
    "    print(\"[Distill-Any-Depth] 전체 이미지 추론을 시작합니다.\")\n",
    "    if os.path.exists(DISTILL_OUTPUT_DIR):\n",
    "        for old_file in os.listdir(DISTILL_OUTPUT_DIR):\n",
    "            path_to_remove = os.path.join(DISTILL_OUTPUT_DIR, old_file)\n",
    "            if os.path.isfile(path_to_remove):\n",
    "                os.remove(path_to_remove)\n",
    "            else:\n",
    "                shutil.rmtree(path_to_remove, ignore_errors=True)\n",
    "    else:\n",
    "        os.makedirs(DISTILL_OUTPUT_DIR, exist_ok=True)\n",
    "\n",
    "    # 실행\n",
    "    prev_cwd = os.getcwd()\n",
    "    os.chdir(DISTILL_BASE_DIR)\n",
    "    try:\n",
    "        cmd = f\"bash {DISTILL_INFER_SCRIPT}\"\n",
    "        subprocess.run(cmd, shell=True, check=True)\n",
    "    except subprocess.CalledProcessError as e:\n",
    "        print(\"[Distill-Any-Depth] 추론 에러 발생:\", e)\n",
    "    finally:\n",
    "        os.chdir(prev_cwd)\n",
    "\n",
    "    print(\"[Distill-Any-Depth] 추론 완료!\")\n",
    "\n",
    "    # image_logs -> compare_depth 복사\n",
    "    distill_image_logs = os.path.join(DISTILL_OUTPUT_DIR, \"image_logs\")\n",
    "    if not os.path.exists(distill_image_logs):\n",
    "        print(f\"[Distill-Any-Depth] image_logs 폴더가 없습니다: {distill_image_logs}\")\n",
    "    else:\n",
    "        os.makedirs(COMPARE_DEPTH_SAVE_DIR, exist_ok=True)\n",
    "        distill_logs = os.listdir(distill_image_logs)\n",
    "        for f in distill_logs:\n",
    "            src_path = os.path.join(distill_image_logs, f)\n",
    "            if os.path.isfile(src_path):\n",
    "                dst_name = f\"distill_{f}\"\n",
    "                dst_path = os.path.join(COMPARE_DEPTH_SAVE_DIR, dst_name)\n",
    "                shutil.copy2(src_path, dst_path)\n",
    "                print(f\"[Distill-Any-Depth] Copied => {os.path.abspath(dst_path)}\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %% [2] Load Depth-Anything-V2\n",
    "def load_depth_anything_v2(checkpoint_path, device=\"cuda\"):\n",
    "    if DEPTH_ANYTHING_DIR not in sys.path:\n",
    "        sys.path.append(DEPTH_ANYTHING_DIR)\n",
    "\n",
    "    from depth_anything_v2.dpt import DepthAnythingV2\n",
    "    model = DepthAnythingV2(\n",
    "        encoder=DEPTH_ENCODER_TYPE,\n",
    "        features=256,\n",
    "        out_channels=[256, 512, 1024, 1024]\n",
    "    )\n",
    "    model.load_state_dict(torch.load(checkpoint_path, map_location=device))\n",
    "    model = model.to(device)\n",
    "    model.eval()\n",
    "    return model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %% [3] V2 inference on input images\n",
    "def run_depth_anything_on_images(model, input_images, device=\"cuda\", resize_size=700):\n",
    "    depth_results = {}\n",
    "    with torch.no_grad():\n",
    "        for img_path in input_images:\n",
    "            img_name = os.path.basename(img_path)\n",
    "            pil_img = Image.open(img_path).convert('RGB')\n",
    "            img_np = np.array(pil_img)\n",
    "            depth_map = model.infer_image(img_np, resize_size)\n",
    "            depth_map = depth_map.squeeze()\n",
    "            depth_results[img_name] = depth_map\n",
    "    return depth_results\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %% [4] Util\n",
    "def normalize_minmax(depth_map):\n",
    "    d_min, d_max = depth_map.min(), depth_map.max()\n",
    "    if d_max - d_min < 1e-6:\n",
    "        return np.zeros_like(depth_map, dtype=np.float32)\n",
    "    return (depth_map - d_min) / (d_max - d_min)\n",
    "\n",
    "def depth_to_colormap(depth_map, cmap_name=\"plasma\"):\n",
    "    depth_map_norm = normalize_minmax(depth_map)\n",
    "    cmap = plt.get_cmap(cmap_name)\n",
    "    depth_color = cmap(depth_map_norm)[:, :, :3]\n",
    "    depth_color = (depth_color * 255).astype(np.uint8)\n",
    "    return depth_color\n",
    "\n",
    "def create_comparison_image(original_img, depth_img_1, depth_img_2, label1=\"ModelA\", label2=\"ModelB\"):\n",
    "    h, w, _ = original_img.shape\n",
    "    concat_img = np.concatenate([original_img, depth_img_1, depth_img_2], axis=1)\n",
    "\n",
    "    import cv2\n",
    "    font = cv2.FONT_HERSHEY_SIMPLEX\n",
    "    font_scale = 1.0\n",
    "    color_text = (255, 255, 255)\n",
    "    thickness = 2\n",
    "\n",
    "    cv2.putText(concat_img, \"Original\", (10, 30), font, font_scale, color_text, thickness, cv2.LINE_AA)\n",
    "    label_x = w + 10\n",
    "    cv2.putText(concat_img, label1, (label_x, 30), font, font_scale, color_text, thickness, cv2.LINE_AA)\n",
    "    label_x2 = w*2 + 10\n",
    "    cv2.putText(concat_img, label2, (label_x2, 30), font, font_scale, color_text, thickness, cv2.LINE_AA)\n",
    "    return concat_img\n",
    "\n",
    "def create_difference_map(depth_v2_color, distill_color):\n",
    "    diff_img = cv2.absdiff(depth_v2_color, distill_color)\n",
    "    return diff_img"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %% [5] 수치 기반 + RGB 기반 비교\n",
    "def run_depth_comparison_on_input_folder():\n",
    "    device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
    "\n",
    "    # 1) Distill-Any-Depth 추론\n",
    "    run_distill_any_depth()\n",
    "\n",
    "    # 2) Load Depth-Anything-V2\n",
    "    model_v2 = load_depth_anything_v2(checkpoint_path=DEPTH_ANYTHING_CHECKPOINT_VITL, device=device)\n",
    "\n",
    "    os.makedirs(COMPARE_DEPTH_SAVE_DIR, exist_ok=True)\n",
    "\n",
    "    input_files = [f for f in os.listdir(INPUT_FOLDER)\n",
    "                   if f.lower().endswith(('.jpg','.jpeg','.png','.bmp','.webp'))]\n",
    "    input_files.sort()\n",
    "    full_paths = [os.path.join(INPUT_FOLDER, x) for x in input_files]\n",
    "\n",
    "    # 3) V2 inference\n",
    "    depth_results_v2 = run_depth_anything_on_images(model_v2, full_paths, device=device, resize_size=700)\n",
    "\n",
    "    # distill logs\n",
    "    distill_image_logs = os.path.join(DISTILL_OUTPUT_DIR, \"image_logs\")\n",
    "    if not os.path.exists(distill_image_logs):\n",
    "        print(f\"[경고] {distill_image_logs} 폴더가 없어 Distill 결과 없음.\")\n",
    "        return\n",
    "\n",
    "    distill_outputs_jpg = sorted([f for f in os.listdir(distill_image_logs) if f.startswith(\"da_sota_\") and f.endswith(\".jpg\")])\n",
    "    distill_outputs_npy = sorted([f for f in os.listdir(distill_image_logs) if f.startswith(\"da_sota_\") and f.endswith(\"_depth.npy\")])\n",
    "\n",
    "    for idx, in_file in enumerate(input_files):\n",
    "        in_path = os.path.join(INPUT_FOLDER, in_file)\n",
    "        origin_pil = Image.open(in_path).convert(\"RGB\")\n",
    "        origin_np = np.array(origin_pil)\n",
    "        h, w, c = origin_np.shape\n",
    "\n",
    "        # V2 depth\n",
    "        depth_map_v2 = depth_results_v2.get(in_file, None)\n",
    "        if depth_map_v2 is None:\n",
    "            print(f\"[오류] V2 depth 결과 없음: {in_file}\")\n",
    "            continue\n",
    "        # v2 컬러맵\n",
    "        depth_color_v2 = depth_to_colormap(depth_map_v2, \"plasma\")\n",
    "        depth_color_v2 = cv2.resize(depth_color_v2, (w, h), interpolation=cv2.INTER_LINEAR)\n",
    "\n",
    "        # Distill JPG\n",
    "        if idx >= len(distill_outputs_jpg):\n",
    "            print(f\"[오류] Distill JPG 인덱스 초과: idx={idx}\")\n",
    "            continue\n",
    "        distill_file_jpg = distill_outputs_jpg[idx]\n",
    "        distill_img_path = os.path.join(distill_image_logs, distill_file_jpg)\n",
    "        if not os.path.isfile(distill_img_path):\n",
    "            print(f\"[오류] Distill JPG 없음: {distill_img_path}\")\n",
    "            continue\n",
    "\n",
    "        distill_pil = Image.open(distill_img_path).convert(\"RGB\")\n",
    "        distill_np = np.array(distill_pil)\n",
    "        distill_np = cv2.resize(distill_np, (w, h), interpolation=cv2.INTER_LINEAR)\n",
    "\n",
    "        # Distill NPY\n",
    "        if idx >= len(distill_outputs_npy):\n",
    "            print(f\"[오류] Distill NPY 인덱스 초과 idx={idx}\")\n",
    "            continue\n",
    "        distill_file_npy = distill_outputs_npy[idx]\n",
    "        distill_npy_path = os.path.join(distill_image_logs, distill_file_npy)\n",
    "        if not os.path.isfile(distill_npy_path):\n",
    "            print(f\"[오류] Distill NPY 없음: {distill_npy_path}\")\n",
    "            continue\n",
    "\n",
    "        distill_depth = np.load(distill_npy_path)\n",
    "        # shape 검사\n",
    "        if distill_depth.ndim == 3 and distill_depth.shape[0] == 1:\n",
    "            distill_depth = distill_depth[0]\n",
    "        dh, dw = distill_depth.shape\n",
    "        if dh < 1 or dw < 1:\n",
    "            print(f\"[오류] Distill depth 크기 이상: shape={distill_depth.shape}\")\n",
    "            continue\n",
    "\n",
    "        if (dh, dw) != (h, w):\n",
    "            distill_depth = cv2.resize(distill_depth, (w, h), interpolation=cv2.INTER_LINEAR)\n",
    "\n",
    "        # V2도 0~1로 가정 => 필요시 수동 정규화\n",
    "        v2_min, v2_max = depth_map_v2.min(), depth_map_v2.max()\n",
    "        if v2_max - v2_min < 1e-9:\n",
    "            v2_norm = np.zeros_like(depth_map_v2, dtype=np.float32)\n",
    "        else:\n",
    "            v2_norm = (depth_map_v2 - v2_min)/(v2_max - v2_min)\n",
    "\n",
    "        # MAE\n",
    "        diff_map_num = np.abs(v2_norm - distill_depth)\n",
    "        mae = diff_map_num.mean()\n",
    "        print(f\"[{in_file}] => MAE(Distill vs V2)={mae:.4f}\")\n",
    "\n",
    "        diff_map_255 = (diff_map_num*255).astype(np.uint8)\n",
    "        diff_color = cv2.applyColorMap(diff_map_255, cv2.COLORMAP_JET)\n",
    "\n",
    "        # RGB 차이\n",
    "        rgb_diff_img = create_difference_map(depth_color_v2, distill_np)\n",
    "        compare_3way = create_comparison_image(origin_np, depth_color_v2, distill_np, \"DepthV2\", \"Distill\")\n",
    "\n",
    "        out_name_base = os.path.splitext(in_file)[0]\n",
    "        out_v2_path       = os.path.join(COMPARE_DEPTH_SAVE_DIR, f\"{out_name_base}_v2.png\")\n",
    "        out_distill_path  = os.path.join(COMPARE_DEPTH_SAVE_DIR, f\"{out_name_base}_distill.png\")\n",
    "        out_compare_path  = os.path.join(COMPARE_DEPTH_SAVE_DIR, f\"{out_name_base}_compare.png\")\n",
    "        out_rgbdiff_path  = os.path.join(COMPARE_DEPTH_SAVE_DIR, f\"{out_name_base}_diff_rgb.png\")\n",
    "        out_numdiff_path  = os.path.join(COMPARE_DEPTH_SAVE_DIR, f\"{out_name_base}_diff_numerical.png\")\n",
    "\n",
    "        cv2.imwrite(out_v2_path,        cv2.cvtColor(depth_color_v2, cv2.COLOR_RGB2BGR))\n",
    "        cv2.imwrite(out_distill_path,   cv2.cvtColor(distill_np,      cv2.COLOR_RGB2BGR))\n",
    "        cv2.imwrite(out_compare_path,   cv2.cvtColor(compare_3way,    cv2.COLOR_RGB2BGR))\n",
    "        cv2.imwrite(out_rgbdiff_path,   cv2.cvtColor(rgb_diff_img,    cv2.COLOR_RGB2BGR))\n",
    "        cv2.imwrite(out_numdiff_path,   diff_color)\n",
    "\n",
    "        print(f\"[{in_file}] => 저장 완료(MAE={mae:.4f}) => {out_numdiff_path}\")\n",
    "\n",
    "    print(\"=== 모든 이미지 비교 완료 ===\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %% [6] 실행\n",
    "if __name__ == \"__main__\":\n",
    "    run_depth_comparison_on_input_folder()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "sam2",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.20"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
