{"metadata":{"kernelspec":{"display_name":".venv","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.12.0"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":112509,"databundleVersionId":14254895,"sourceType":"competition"}],"dockerImageVersionId":31193,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"Clovers/Weeds segmentation training notebook\nhttps://www.kaggle.com/code/welshonionman/clovers-weeds-segmentation","metadata":{}},{"cell_type":"code","source":"import os\nfrom pathlib import Path\n\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom PIL import Image\nimport cv2\n","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train = pd.read_csv(\"/kaggle/input/csiro-biomass/train.csv\")\ntrain = train.pivot(\n    index=[\"image_path\", \"Sampling_Date\", \"State\", \"Species\", \"Pre_GSHH_NDVI\", \"Height_Ave_cm\"],\n    columns=\"target_name\",\n    values=\"target\",\n).reset_index()\ntrain\n","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"IMAGE_DIR = f\"/kaggle/input/csiro-biomass/train\"\nMASK_DIR = f\"/kaggle/working/seg_green/masks\"\nPath(MASK_DIR).mkdir(parents=True, exist_ok=True)\n\nWEEDS = [\n    \"Lucerne\",\n    \"Ryegrass\",\n    \"Fescue_CrumbWeed\",\n    \"Phalaris\",\n    \"Fescue\",\n]\nCLOVERS = [\n    \"WhiteClover\",\n    \"Clover\",\n    \"SubcloverLosa\",\n    \"SubcloverDalkeith\",\n]","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 雑草とクローバーのデータをフィルタリング\nweeds_train = train[train[\"Species\"].isin(WEEDS)]\nclovers_train = train[train[\"Species\"].isin(CLOVERS)]\nfiltered_train = pd.concat([weeds_train, clovers_train])\n\nprint(f\"Total samples: {len(train)}\")\nprint(f\"Filtered samples (weeds + clovers): {len(filtered_train)}\")\nprint(f\"weeds: {train[train['Species'].isin(WEEDS)].shape}\")\nprint(f\"clovers: {train[train['Species'].isin(CLOVERS)].shape}\")\n","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def create_green_mask(img_array, lower_green=[35, 30, 30], upper_green=[85, 255, 255]):\n    \"\"\"\n    画像から緑色の部分をマスクする関数\n\n    Args:\n        img_array: RGB画像のnumpy配列\n\n    Returns:\n        masked_img: 緑色部分の二値画像\n        green_mask: 緑色部分のバイナリマスク\n    \"\"\"\n    # HSV色空間に変換\n    hsv = cv2.cvtColor(img_array, cv2.COLOR_RGB2HSV)\n\n    # 緑色の範囲を定義（HSVで）\n    lower_green = np.array([35, 30, 30])\n    upper_green = np.array([85, 255, 255])\n\n    # 緑色の部分をマスク\n    green_mask = cv2.inRange(hsv, lower_green, upper_green)\n\n    # 二値画像として返す（緑色部分を255、それ以外を0）\n    masked_img = green_mask\n\n    return masked_img, green_mask","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# HSV色空間での緑色の範囲を可視化\nfig, axes = plt.subplots(1, 3, figsize=(15, 5))\n\n# HSV色空間のサンプル画像を作成\nh_range = np.arange(0, 180, 1)\ns_range = np.arange(0, 256, 1)\nv_range = np.arange(0, 256, 1)\n\n# Hue (色相) の可視化\nh_img = np.zeros((100, 180, 3), dtype=np.uint8)\nfor i, h in enumerate(h_range):\n    h_img[:, i] = [h, 255, 255]  # 彩度と明度を最大に\nh_img_rgb = cv2.cvtColor(h_img, cv2.COLOR_HSV2RGB)\n\naxes[0].imshow(h_img_rgb)\naxes[0].axvline(x=35, color=\"red\", linestyle=\"--\", linewidth=2, label=\"Lower Green (35)\")\naxes[0].axvline(x=85, color=\"red\", linestyle=\"--\", linewidth=2, label=\"Upper Green (85)\")\naxes[0].set_title(\"Hue Range (0-179)\\nGreen range: 35-85\")\naxes[0].set_xlabel(\"Hue Value\")\naxes[0].legend()\n\n# Saturation (彩度) の可視化\ns_img = np.zeros((100, 256, 3), dtype=np.uint8)\nfor i, s in enumerate(s_range):\n    s_img[:, i] = [60, s, 255]  # 緑色の色相(60)と最大明度\ns_img_rgb = cv2.cvtColor(s_img, cv2.COLOR_HSV2RGB)\n\naxes[1].imshow(s_img_rgb)\naxes[1].axvline(x=40, color=\"red\", linestyle=\"--\", linewidth=2, label=\"Lower Saturation (40)\")\naxes[1].axvline(x=255, color=\"red\", linestyle=\"--\", linewidth=2, label=\"Upper Saturation (255)\")\naxes[1].set_title(\"Saturation Range (0-255)\\nGreen range: 40-255\")\naxes[1].set_xlabel(\"Saturation Value\")\naxes[1].legend()\n\n# Value (明度) の可視化\nv_img = np.zeros((100, 256, 3), dtype=np.uint8)\nfor i, v in enumerate(v_range):\n    v_img[:, i] = [60, 255, v]  # 緑色の色相(60)と最大彩度\nv_img_rgb = cv2.cvtColor(v_img, cv2.COLOR_HSV2RGB)\n\naxes[2].imshow(v_img_rgb)\naxes[2].axvline(x=40, color=\"red\", linestyle=\"--\", linewidth=2, label=\"Lower Value (40)\")\naxes[2].axvline(x=255, color=\"red\", linestyle=\"--\", linewidth=2, label=\"Upper Value (255)\")\naxes[2].set_title(\"Value Range (0-255)\\nGreen range: 40-255\")\naxes[2].set_xlabel(\"Value\")\naxes[2].legend()\n\nplt.tight_layout()\nplt.show()\n\n# 定義された緑色の範囲を表示\nprint(\"Defined Green Color Range in HSV:\")\nprint(f\"Lower bound: H={35}, S={40}, V={40}\")\nprint(f\"Upper bound: H={85}, S={255}, V={255}\")\nprint(\"\\nThis range captures:\")\nprint(\"- Hue: 35-85 (covers yellow-green to blue-green)\")\nprint(\"- Saturation: 40-255 (excludes very pale/washed out colors)\")\nprint(\"- Value: 40-255 (excludes very dark colors)\")\n","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for idx, row in filtered_train.iterrows():\n    image_path = f\"/kaggle/input/csiro-biomass/{row['image_path']}\"\n\n    # Load image\n    img = Image.open(image_path)\n    img_array = np.array(img)\n\n    # Create green mask\n    masked_img, green_mask = create_green_mask(img_array)\n\n    # Create labeled mask based on species category\n    labeled_mask = np.zeros_like(green_mask)\n\n    if row[\"Species\"] in CLOVERS:\n        # Green parts get label 1 for clovers\n        labeled_mask[green_mask > 0] = 1\n    elif row[\"Species\"] in WEEDS:\n        # Green parts get label 2 for weeds\n        labeled_mask[green_mask > 0] = 2\n\n    # Save the labeled mask (you can modify the save path as needed)\n    filename = Path(row[\"image_path\"]).stem\n    mask_path = f\"{MASK_DIR}/{filename}.png\"\n\n    # Save as PNG to preserve exact pixel values\n    cv2.imwrite(mask_path, labeled_mask)\n","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# データセットのパスを設定\n\n# 利用可能な画像ファイルを取得\nimage_files = sorted([f for f in os.listdir(IMAGE_DIR) if f.endswith(\".jpg\")])\nmask_files = sorted([f for f in os.listdir(MASK_DIR) if f.endswith(\".png\")])\nprint(f\"Found {len(image_files)} images in dataset\")\nprint(f\"Found {len(mask_files)} masks in dataset\")\n\n# 最初の20枚を可視化（マスクが存在するもののみ）\nnum_samples = min(20, len(mask_files))\nfig, axes = plt.subplots(num_samples, 2, figsize=(15, 3 * num_samples))\n\nvalid_count = 0\nfor i in range(len(mask_files)):\n    if valid_count >= num_samples:\n        break\n\n    image_id = mask_files[i].replace(\".png\", \"\")\n\n    image_path = os.path.join(IMAGE_DIR, f\"{image_id}.jpg\")\n\n    image = np.array(Image.open(image_path).convert(\"RGB\"))\n\n    mask_path = os.path.join(MASK_DIR, f\"{image_id}.png\")\n    mask = np.array(Image.open(mask_path))\n\n    axes[valid_count, 0].imshow(image)\n    axes[valid_count, 0].set_title(f\"Original Image\\n{image_id}\")\n    axes[valid_count, 0].axis(\"off\")\n\n    axes[valid_count, 1].imshow(mask, cmap=\"viridis\", vmin=0, vmax=2)\n    axes[valid_count, 1].set_title(\"Ground Truth Mask\\n(0=bg, 1=clover, 2=weed)\")\n    axes[valid_count, 1].axis(\"off\")\n\n    valid_count += 1\n\nfor i in range(valid_count, num_samples):\n    axes[i, 0].axis(\"off\")\n    axes[i, 1].axis(\"off\")\n\nplt.tight_layout()\nplt.show()\n\n# データセットの統計情報を表示\nprint(f\"\\nDataset Statistics:\")\nprint(f\"Total images: {len(image_files)}\")\n\n# マスクの統計を計算\nmask_stats = {\"background\": 0, \"clover\": 0, \"weed\": 0}\ntotal_pixels = 0\n\nfor image_file in image_files[:50]:  # 最初の50枚で統計を計算\n    image_id = image_file.replace(\".jpg\", \"\")\n    mask_path = os.path.join(MASK_DIR, f\"{image_id}.png\")\n\n    if os.path.exists(mask_path):\n        mask = np.array(Image.open(mask_path))\n        total_pixels += mask.size\n\n        mask_stats[\"background\"] += np.sum(mask == 0)\n        mask_stats[\"clover\"] += np.sum(mask == 1)\n        mask_stats[\"weed\"] += np.sum(mask == 2)\n","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null}]}