{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "LfNcmEHg5hH-"
      },
      "outputs": [],
      "source": [
        "!pip install svgpathtools numpy moondream-station moondream"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "# Instance Segmentation COCO Format from Moondream Format"
      ],
      "metadata": {
        "id": "VV1eXtA76o2C"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "import moondream as md\n",
        "from PIL import Image\n",
        "import matplotlib.pyplot as plt\n",
        "import matplotlib.patches as patches\n",
        "import numpy as np\n",
        "import json\n",
        "from svgpathtools import parse_path\n",
        "import os\n",
        "\n",
        "\n",
        "api_key = \"abcd\"\n",
        "model = md.vl(api_key=api_key)\n",
        "\n",
        "image_path = \"/content/image_1.jpg\"\n",
        "\n",
        "if not os.path.exists(image_path):\n",
        "    print(f\"❌ Image not found at {image_path}\")\n",
        "else:\n",
        "    image = Image.open(image_path)\n",
        "    w, h = image.size\n",
        "\n",
        "    # Detect Points first\n",
        "    print(\"Detecting...\")\n",
        "    point_result = model.point(image, \"Roof\")\n",
        "    points = point_result[\"points\"]\n",
        "    print(f\"Found {len(points)} objects.\")\n",
        "\n",
        "    segments = []\n",
        "    print(\"Segmenting...\")\n",
        "    for point in points:\n",
        "        result = model.segment(\n",
        "            image,\n",
        "            \"Roof\", # Or \"Roof parts with damage\" as per your need\n",
        "            spatial_refs=[[point[\"x\"], point[\"y\"]]]\n",
        "        )\n",
        "        segments.append(result)\n",
        "\n",
        "    def svg_path_to_coco_polygon(path_str, bbox_norm, img_w, img_h, num_samples=30):\n",
        "        \"\"\"\n",
        "        Converts SVG path to Pixels using the Bounding Box as the reference frame.\n",
        "        \"\"\"\n",
        "        try:\n",
        "            box_x = bbox_norm['x_min'] * img_w\n",
        "            box_y = bbox_norm['y_min'] * img_h\n",
        "            box_w = (bbox_norm['x_max'] - bbox_norm['x_min']) * img_w\n",
        "            box_h = (bbox_norm['y_max'] - bbox_norm['y_min']) * img_h\n",
        "\n",
        "            path = parse_path(path_str)\n",
        "            poly_points = []\n",
        "\n",
        "            for segment in path:\n",
        "                for t in np.linspace(0, 1, num_samples):\n",
        "                    point = segment.point(t)\n",
        "\n",
        "                    abs_x = box_x + (point.real * box_w)\n",
        "                    abs_y = box_y + (point.imag * box_h)\n",
        "\n",
        "                    abs_x = min(max(abs_x, 0), img_w)\n",
        "                    abs_y = min(max(abs_y, 0), img_h)\n",
        "\n",
        "                    poly_points.extend([round(abs_x, 2), round(abs_y, 2)])\n",
        "\n",
        "            return [poly_points]\n",
        "        except Exception as e:\n",
        "            print(f\"Error parsing segment: {e}\")\n",
        "            return []\n",
        "\n",
        "    def calculate_area(segmentation):\n",
        "        try:\n",
        "            if not segmentation: return 0\n",
        "            poly = np.array(segmentation[0]).reshape(-1, 2)\n",
        "            x = poly[:, 0]\n",
        "            y = poly[:, 1]\n",
        "            return 0.5 * np.abs(np.dot(x, np.roll(y, 1)) - np.dot(y, np.roll(x, 1)))\n",
        "        except:\n",
        "            return 0\n",
        "\n",
        "\n",
        "    coco_output = {\n",
        "        \"info\": {\"description\": \"Roof Dataset\", \"year\": 2025},\n",
        "        \"categories\": [{\"id\": 1, \"name\": \"roof\", \"supercategory\": \"building\"}],\n",
        "        \"images\": [{\"id\": 1, \"width\": w, \"height\": h, \"file_name\": os.path.basename(image_path)}],\n",
        "        \"annotations\": []\n",
        "    }\n",
        "\n",
        "    ann_id = 1\n",
        "    for seg in segments:\n",
        "        segmentation = svg_path_to_coco_polygon(seg['path'], seg['bbox'], w, h)\n",
        "\n",
        "        if not segmentation or len(segmentation[0]) < 6: continue\n",
        "\n",
        "        b = seg['bbox']\n",
        "        abs_bbox = [\n",
        "            round(b['x_min'] * w, 2),\n",
        "            round(b['y_min'] * h, 2),\n",
        "            round((b['x_max'] - b['x_min']) * w, 2),\n",
        "            round((b['y_max'] - b['y_min']) * h, 2)\n",
        "        ]\n",
        "\n",
        "        coco_output[\"annotations\"].append({\n",
        "            \"id\": ann_id,\n",
        "            \"image_id\": 1,\n",
        "            \"category_id\": 1,\n",
        "            \"segmentation\": segmentation,\n",
        "            \"area\": calculate_area(segmentation),\n",
        "            \"bbox\": abs_bbox,\n",
        "            \"iscrowd\": 0\n",
        "        })\n",
        "        ann_id += 1\n",
        "\n",
        "    # Save\n",
        "    with open(\"coco_annotations.json\", \"w\") as f:\n",
        "        json.dump(coco_output, f)\n",
        "    print(f\"✅ Saved {len(coco_output['annotations'])} annotations.\")\n",
        "\n",
        "    print(\"\\nVisualizing Result...\")\n",
        "    fig, ax = plt.subplots(1, figsize=(12, 10))\n",
        "    ax.imshow(image)\n",
        "\n",
        "    colors = ['#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#00FFFF']\n",
        "\n",
        "    for i, ann in enumerate(coco_output[\"annotations\"]):\n",
        "        poly_data = ann['segmentation'][0]\n",
        "        poly_coords = np.array(poly_data).reshape(-1, 2)\n",
        "\n",
        "        c = colors[i % len(colors)]\n",
        "\n",
        "        poly_patch = patches.Polygon(\n",
        "            poly_coords,\n",
        "            linewidth=2,\n",
        "            edgecolor=c,\n",
        "            facecolor=c + \"40\"\n",
        "        )\n",
        "        ax.add_patch(poly_patch)\n",
        "\n",
        "    plt.axis('off')\n",
        "    plt.show()"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 911
        },
        "id": "2k0nam347vlN",
        "outputId": "92f0eac6-071a-4e3d-a152-7e54142b469a"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Detecting...\n",
            "Found 6 objects.\n",
            "Segmenting...\n",
            "✅ Saved 6 annotations.\n",
            "\n",
            "Visualizing Result...\n"
          ]
        },
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<Figure size 1200x1000 with 1 Axes>"
            ],
            "image/png": "[encoded data, 954392 characters]\n"
          },
          "metadata": {}
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "# Verifying the annotations (directly loading the json file, so that there is no possibility of contamination):"
      ],
      "metadata": {
        "id": "0tUb_v6hAHot"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "import json\n",
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "import matplotlib.patches as patches\n",
        "from PIL import Image\n",
        "import random\n",
        "\n",
        "IMAGE_PATH = \"/content/image_1.jpg\"\n",
        "\n",
        "JSON_PATH = \"/content/coco_annotations.json\"\n",
        "\n",
        "try:\n",
        "    image = Image.open(IMAGE_PATH)\n",
        "except FileNotFoundError:\n",
        "    print(f\"❌ Error: Could not find image at {IMAGE_PATH}\")\n",
        "    exit()\n",
        "\n",
        "try:\n",
        "    with open(JSON_PATH, 'r') as f:\n",
        "        coco_data = json.load(f)\n",
        "except FileNotFoundError:\n",
        "    print(f\"❌ Error: Could not find JSON file at {JSON_PATH}\")\n",
        "    exit()\n",
        "\n",
        "fig, ax = plt.subplots(1, figsize=(12, 12))\n",
        "ax.imshow(image)\n",
        "ax.set_title(f\"Visualizing {len(coco_data['annotations'])} Instance Masks\")\n",
        "\n",
        "colors = [\n",
        "    '#FF0000', # Red\n",
        "    '#00FF00', # Green\n",
        "    '#0000FF', # Blue\n",
        "    '#FFFF00', # Yellow\n",
        "    '#FF00FF', # Magenta\n",
        "    '#00FFFF', # Cyan\n",
        "    '#FFA500', # Orange\n",
        "    '#800080'  # Purple\n",
        "]\n",
        "\n",
        "print(f\"Found {len(coco_data['annotations'])} annotations.\")\n",
        "\n",
        "for i, ann in enumerate(coco_data['annotations']):\n",
        "    seg_points = ann['segmentation'][0]\n",
        "\n",
        "    poly_coords = np.array(seg_points).reshape(-1, 2)\n",
        "\n",
        "    color = colors[i % len(colors)]\n",
        "\n",
        "    poly_patch = patches.Polygon(\n",
        "        poly_coords,\n",
        "        linewidth=2,\n",
        "        edgecolor=color,\n",
        "        facecolor=color + \"50\"\n",
        "    )\n",
        "    ax.add_patch(poly_patch)\n",
        "\n",
        "    # Optional: Draw Bounding Box to verify alignment\n",
        "    # bbox = ann['bbox'] # [x, y, w, h]\n",
        "    # rect = patches.Rectangle((bbox[0], bbox[1]), bbox[2], bbox[3],\n",
        "    #                          linewidth=1, edgecolor='white', facecolor='none', linestyle='--')\n",
        "    # ax.add_patch(rect)\n",
        "\n",
        "plt.axis('off')\n",
        "plt.show()"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        },
        "id": "Sh1vv5ze_35s",
        "outputId": "8241fdda-05a5-4216-a047-96ca2a38318e"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Found 6 annotations.\n"
          ]
        },
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<Figure size 1200x1200 with 1 Axes>"
            ],
            "image/png": "[encoded data, 1290612 characters]\n"
          },
          "metadata": {}
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "lBzXNbUQAEkA"
      },
      "execution_count": null,
      "outputs": []
    }
  ]
}