🔹 フェーズ1:画像処理の基礎(OpenCV中心)【Week 1〜8】
🔹 フェーズ2:ディープラーニングによる画像認識【Week 9〜16】
🔹 フェーズ3:農業現場応用プロジェクト制作【Week 17〜24】
週 | タイトル | 内容概要 | ノートブック例 |
Week 1 | 画像ファイルの読み込みと表示 | OpenCV入門、画像のRGB/BGR変換、チャンネル操作 | week01_opencv_intro.ipynb |
Week 2 | 基本的な画像処理 | グレースケール変換、ぼかし(平滑化)、閾値処理 | week02_opencv_processing.ipynb |
Week 3 | 輪郭検出と形状解析 | Canny、輪郭抽出、面積・外接矩形の計算 | week03_contour_analysis.ipynb |
Week 4 | ヒストグラム解析 | 明るさ/色の分布、ヒストグラム平坦化 | week04_histogram_analysis.ipynb |
Week 5 | 幾何変換 | リサイズ、回転、アフィン・射影変換 | week05_geometry_transforms.ipynb |
Week 6 | マスキングと領域抽出 | ROI抽出、条件付き抽出(色・閾値) | week06_masking_roi.ipynb |
Week 7 | 画像合成と透過処理 | 加重合成、透明背景合成(アルファチャンネル) | week07_compositing.ipynb |
Week 8 | 応用演習①:葉面積の測定 | 例:作物の葉を二値化→面積計算 | week08_leaf_area_calc.ipynb |
週 | タイトル | 内容概要 | ノートブック例 |
Week 9 | CNN基礎① | Convolutionの仕組み、MaxPoolingなど | week09_cnn_intro.ipynb |
Week 10 | CNN基礎② | kerasによるシンプルなCNN構築(分類) | week10_cnn_build.ipynb |
Week 11 | データ拡張と前処理 | 回転・反転・拡張による学習改善 | week11_data_aug.ipynb |
Week 12 | 転移学習(ResNet等) | 学習済みモデルの応用とfine-tuning | week12_transfer_learning.ipynb |
Week 13 | 精度評価と混同行列 | 精度/再現率/F1・Confusion Matrixの表示 | week13_model_eval.ipynb |
Week 14 | 物体検出①:YOLOv5入門 | 基本構造と使い方 | week14_yolo_intro.ipynb |
Week 15 | 物体検出②:農業応用 | 害虫・病斑・果実検出など | week15_yolo_agri.ipynb |
Week 16 | 応用演習②:病気画像分類 | 農研機構データを使った病気識別 | week16_disease_classify.ipynb |
以下が、画像処理の入門として構成されたノートブック week01_opencv_intro.ipynb の内容です。
この週では、OpenCV を用いた画像の基本操作(読み込み・表示・加工) を通して、農業画像処理への第一歩を学びます。
# week01_opencv_intro.ipynb:OpenCV 基本操作
import cv2
import matplotlib.pyplot as plt
import numpy as np
# Google Colab環境用: サンプル画像のアップロード
from google.colab import files
uploaded = files.upload()
# 画像読み込み
image_path = list(uploaded.keys())[0] # 最初にアップロードされたファイル
img = cv2.imread(image_path)
# OpenCV は BGR → RGB に変換して表示する必要あり
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 画像表示
plt.figure(figsize=(8, 6))
plt.imshow(img_rgb)
plt.title("📷 入力画像")
plt.axis("off")
plt.show()
# --- 基本操作 ---
# グレースケール変換
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# リサイズ
resized = cv2.resize(img_rgb, (200, 200))
# 回転(中心回転)
(h, w) = img.shape[:2]
center = (w // 2, h // 2)
matrix = cv2.getRotationMatrix2D(center, 45, 1.0) # 45度回転
rotated = cv2.warpAffine(img_rgb, matrix, (w, h))
# 画像の保存(例)
cv2.imwrite("rotated_image.jpg", rotated)
# --- 表示まとめ ---
fig, ax = plt.subplots(1, 3, figsize=(15, 4))
ax[0].imshow(gray, cmap='gray')
ax[0].set_title("Grayscale")
ax[1].imshow(resized)
ax[1].set_title("Resized")
ax[2].imshow(rotated)
ax[2].set_title("Rotated (45°)")
for a in ax:
a.axis("off")
plt.tight_layout()
plt.show()
機能 | 説明 |
cv2.imread() | 画像ファイルの読み込み |
cv2.cvtColor() | カラーモード変換(BGR→RGB, グレースケールなど) |
cv2.resize() | 任意サイズへの画像リサイズ |
cv2.getRotationMatrix2D() + warpAffine() | 画像の回転 |
cv2.imwrite() | 加工画像の保存 |
# week02_opencv_processing.ipynb:OpenCV 前処理編
import cv2
import numpy as np
import matplotlib.pyplot as plt
from google.colab import files
# ファイルアップロード
uploaded = files.upload()
image_path = list(uploaded.keys())[0]
img = cv2.imread(image_path)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# グレースケール変換
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 1. 平滑化(ぼかし処理)
blur = cv2.GaussianBlur(gray, (5, 5), 0)
# 2. しきい値処理(二値化)
_, binary = cv2.threshold(blur, 100, 255, cv2.THRESH_BINARY)
# 3. Canny エッジ検出
edges = cv2.Canny(blur, 50, 150)
# 4. 輪郭検出
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contour_img = img_rgb.copy()
cv2.drawContours(contour_img, contours, -1, (255, 0, 0), 2)
# 画像表示まとめ
titles = ["グレースケール", "ぼかし処理", "二値化", "エッジ検出", "輪郭抽出"]
images = [gray, blur, binary, edges, contour_img]
plt.figure(figsize=(15, 8))
for i in range(5):
plt.subplot(2, 3, i+1)
if i < 4:
plt.imshow(images[i], cmap='gray')
else:
plt.imshow(images[i])
plt.title(titles[i])
plt.axis("off")
plt.tight_layout()
plt.show()
処理手法 | 内容・活用例 |
グレースケール変換 | 処理の前段階として色情報を減らす |
ぼかし(平滑化) | ノイズ除去。GaussianBlur を使用 |
二値化処理 | 背景と対象を分離(例:葉 vs 背景) |
エッジ検出 | 境界線の検出。物体の形状を把握 |
輪郭抽出 | 葉・果実などの外形を捉える際に使用 |
こちらが、輪郭や領域の定量的な解析にフォーカスしたノートブック week03_contour_analysis.ipynb の内容です。
この週では、OpenCVで得た輪郭に対する面積・周囲長・アスペクト比・ヒストグラム などの特徴量抽出を行い、画像からの定量データ取得を体験します。
# week03_contour_analysis.ipynb:輪郭解析と特徴量抽出
import cv2
import numpy as np
import matplotlib.pyplot as plt
from google.colab import files
# ファイルアップロード
uploaded = files.upload()
image_path = list(uploaded.keys())[0]
img = cv2.imread(image_path)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 前処理:ぼかし + 二値化
blur = cv2.GaussianBlur(gray, (5, 5), 0)
_, binary = cv2.threshold(blur, 100, 255, cv2.THRESH_BINARY)
# 輪郭抽出
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 輪郭ごとの特徴量抽出
features = []
annotated_img = img_rgb.copy()
for i, cnt in enumerate(contours):
area = cv2.contourArea(cnt)
perimeter = cv2.arcLength(cnt, True)
# バウンディングボックス
x, y, w, h = cv2.boundingRect(cnt)
aspect_ratio = float(w) / h
# ラベル描画
cv2.rectangle(annotated_img, (x, y), (x+w, y+h), (0, 255, 0), 2)
cv2.putText(annotated_img, f"#{i+1}", (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
features.append({
"ID": i+1,
"Area": area,
"Perimeter": perimeter,
"AspectRatio": aspect_ratio,
"BoundingBox": (x, y, w, h)
})
# 結果表示
plt.figure(figsize=(8, 6))
plt.imshow(annotated_img)
plt.title("輪郭と特徴量の可視化")
plt.axis("off")
plt.show()
# 特徴量テーブル表示
import pandas as pd
df_features = pd.DataFrame(features)
df_features
機能・処理 | 説明 |
cv2.contourArea() | 面積の計算 |
cv2.arcLength() | 周囲長の計算 |
cv2.boundingRect() | バウンディングボックスとアスペクト比 |
cv2.putText() | 輪郭にIDを表示する |
以下は、色解析とヒストグラムを中心に学ぶノートブック week04_histogram_analysis.ipynb の内容です。
この週では、画像内の色情報の可視化・ヒストグラムの解析・しきい値処理や色抽出の応用 を学び、葉の健康状態や作物の熟度判定などへの応用の基礎を固めます。
# week04_histogram_analysis.ipynb:色ヒストグラムとマスク処理
import cv2
import numpy as np
import matplotlib.pyplot as plt
from google.colab import files
# 画像アップロード
uploaded = files.upload()
image_path = list(uploaded.keys())[0]
img = cv2.imread(image_path)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# --- 色ヒストグラムの表示(RGB別) ---
colors = ('r', 'g', 'b')
plt.figure(figsize=(10, 4))
for i, col in enumerate(colors):
hist = cv2.calcHist([img_rgb], [i], None, [256], [0, 256])
plt.plot(hist, color=col)
plt.xlim([0, 256])
plt.title("RGBヒストグラム")
plt.xlabel("画素値")
plt.ylabel("出現頻度")
plt.grid(True)
plt.show()
# --- HSV変換と色抽出(例:緑) ---
hsv = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2HSV)
# 緑の範囲を指定
lower_green = np.array([35, 40, 40])
upper_green = np.array([85, 255, 255])
# マスク作成と適用
mask = cv2.inRange(hsv, lower_green, upper_green)
result = cv2.bitwise_and(img_rgb, img_rgb, mask=mask)
# 結果表示
fig, ax = plt.subplots(1, 3, figsize=(16, 5))
ax[0].imshow(img_rgb)
ax[0].set_title("元画像")
ax[1].imshow(mask, cmap='gray')
ax[1].set_title("緑色マスク")
ax[2].imshow(result)
ax[2].set_title("抽出結果(緑)")
for a in ax:
a.axis("off")
plt.tight_layout()
plt.show()
処理名 | 説明 |
cv2.calcHist() | 色ヒストグラムの算出(R, G, B) |
cv2.cvtColor() | RGB → HSV 変換(色抽出しやすい) |
cv2.inRange() | 指定色の範囲をマスクとして抽出 |
cv2.bitwise_and() | マスクに基づく色領域の抽出 |
以下は、画像の幾何変換やリサイズ・回転・切り出しを扱うノートブック week05_geometry_transforms.ipynb の内容です。
この週では、画像前処理の一環としての座標操作やアフィン変換の基礎 を身につけ、データ拡張や部分領域の抽出(ROI)などの応用を可能にします。
# week05_geometry_transforms.ipynb:幾何変換・リサイズ・切り出し・回転
import cv2
import numpy as np
import matplotlib.pyplot as plt
from google.colab import files
# 画像アップロード
uploaded = files.upload()
image_path = list(uploaded.keys())[0]
img = cv2.imread(image_path)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# --- 1. リサイズ ---
resized = cv2.resize(img_rgb, (300, 300))
# --- 2. 切り出し(ROI)---
h, w = img_rgb.shape[:2]
roi = img_rgb[h//4:h//4*3, w//4:w//4*3]
# --- 3. 回転(中心回転) ---
center = (w // 2, h // 2)
matrix = cv2.getRotationMatrix2D(center, angle=45, scale=1.0)
rotated = cv2.warpAffine(img_rgb, matrix, (w, h))
# --- 4. アフィン変換 ---
pts1 = np.float32([[50, 50], [200, 50], [50, 200]])
pts2 = np.float32([[60, 70], [220, 50], [70, 250]])
M_affine = cv2.getAffineTransform(pts1, pts2)
affine = cv2.warpAffine(img_rgb, M_affine, (w, h))
# --- 表示 ---
titles = ['Original', 'Resized', 'ROI', 'Rotated', 'Affine Transform']
images = [img_rgb, resized, roi, rotated, affine]
plt.figure(figsize=(16, 8))
for i in range(5):
plt.subplot(2, 3, i+1)
plt.imshow(images[i])
plt.title(titles[i])
plt.axis('off')
plt.tight_layout()
plt.show()
処理内容 | 使用関数 | 応用例 |
リサイズ | cv2.resize | 学習用データの統一 |
ROI抽出 | 配列スライス | 葉や果実の一部だけを分析 |
回転 | getRotationMatrix2D, warpAffine | データ拡張、角度補正 |
アフィン変換 | getAffineTransform, warpAffine | 視点補正、形状変形 |
こちらが、画像内の特定領域(ROI)をマスク処理によって抽出・分析するためのノートブック week06_masking_roi.ipynb の内容です。
この週では、色抽出+輪郭+マスクの組み合わせにより、「分析対象を限定して処理する」実践力を養います。
# week06_masking_roi.ipynb:色と輪郭を用いたROIマスク抽出
import cv2
import numpy as np
import matplotlib.pyplot as plt
from google.colab import files
# 画像アップロード
uploaded = files.upload()
image_path = list(uploaded.keys())[0]
img = cv2.imread(image_path)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
hsv = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2HSV)
# --- 緑色の範囲をマスク ---
lower_green = np.array([35, 40, 40])
upper_green = np.array([85, 255, 255])
mask = cv2.inRange(hsv, lower_green, upper_green)
# --- 輪郭抽出 ---
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# --- 最大輪郭を抽出(最も大きな葉など) ---
max_contour = max(contours, key=cv2.contourArea)
roi_mask = np.zeros_like(mask)
cv2.drawContours(roi_mask, [max_contour], -1, 255, -1) # 塗りつぶし
# --- マスクを用いてROI画像を抽出 ---
roi_extracted = cv2.bitwise_and(img_rgb, img_rgb, mask=roi_mask)
# --- ヒストグラム(ROI部分のみ) ---
masked_pixels = cv2.bitwise_and(hsv, hsv, mask=roi_mask)
hist_hue = cv2.calcHist([masked_pixels], [0], roi_mask, [180], [0, 180])
plt.figure(figsize=(14, 6))
plt.subplot(1, 3, 1)
plt.imshow(img_rgb)
plt.title("元画像")
plt.axis("off")
plt.subplot(1, 3, 2)
plt.imshow(roi_extracted)
plt.title("ROI抽出(最大葉)")
plt.axis("off")
plt.subplot(1, 3, 3)
plt.plot(hist_hue, color='g')
plt.title("ROI部分の色相ヒストグラム")
plt.xlabel("Hue (色相)")
plt.ylabel("出現頻度")
plt.grid(True)
plt.tight_layout()
plt.show()
処理内容 | 説明 |
色範囲指定マスク | 緑色など特定範囲をマスクで抽出 |
最大輪郭の抽出 | 面積最大の葉や果実の選別 |
マスク付きbitwise_and処理 | ROIのみ可視化・処理対象とする |
ROI領域のヒストグラム解析 | ROI限定の色情報・形状情報取得 |
こちらが、画像から抽出した色・形状・面積などの特徴量を統合して分析するためのノートブック week07_compositing.ipynb の内容です。
この週では、ROI単位で得られた情報を 構造化データとして整形・比較 することで、分類や時系列分析への土台を作ります。
# week07_compositing.ipynb:色・形状の統合特徴量をCSVとして抽出
import cv2
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from google.colab import files
# 画像アップロード(複数対応)
uploaded = files.upload()
data = []
for filename in uploaded.keys():
img = cv2.imread(filename)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
hsv = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2HSV)
# 色マスク(緑)
lower_green = np.array([35, 40, 40])
upper_green = np.array([85, 255, 255])
mask = cv2.inRange(hsv, lower_green, upper_green)
# 輪郭検出
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
area = cv2.contourArea(cnt)
if area < 100: # 小さいノイズ除去
continue
# 輪郭マスク
roi_mask = np.zeros_like(mask)
cv2.drawContours(roi_mask, [cnt], -1, 255, -1)
# ROI領域のHSV取得
roi_pixels = cv2.bitwise_and(hsv, hsv, mask=roi_mask)
# 平均HSV値
mean_val = cv2.mean(roi_pixels, mask=roi_mask)
mean_h, mean_s, mean_v = mean_val[:3]
# 輪郭の外接矩形
x, y, w, h = cv2.boundingRect(cnt)
aspect_ratio = w / h
# データに追加
data.append({
'filename': filename,
'area': area,
'mean_h': mean_h,
'mean_s': mean_s,
'mean_v': mean_v,
'aspect_ratio': aspect_ratio
})
# --- DataFrame化してCSV保存 ---
df = pd.DataFrame(data)
df.to_csv("roi_features.csv", index=False)
files.download("roi_features.csv")
# --- 表示 ---
print("抽出された特徴量(上位5件):")
print(df.head())
# --- 可視化(面積 vs 色相) ---
plt.figure(figsize=(8, 6))
plt.scatter(df['area'], df['mean_h'], c=df['mean_h'], cmap='hsv', s=30)
plt.xlabel("面積")
plt.ylabel("平均色相 (Hue)")
plt.title("面積 vs 色相")
plt.grid(True)
plt.colorbar(label='Hue')
plt.show()
要素 | 内容 |
色特徴 | 平均 Hue / Saturation / Value |
形状特徴 | 面積・アスペクト比(縦横比) |
多画像対応 | 複数ファイルをまとめて処理 |
CSV化 | 構造化データとして出力・学習準備 |
散布図分析 | 異常検知やクラスタリングの布石に |
こちらが、画像から葉の面積をより高精度に算出するためのノートブック week08_leaf_area_calc.ipynb の内容です。
この週では、実寸換算・輪郭面積の厳密取得を通じて、農業現場で重要な「葉面積の定量評価」を可能にします。
# week08_leaf_area_calc.ipynb:葉面積をピクセル単位&cm²単位で測定
import cv2
import numpy as np
import matplotlib.pyplot as plt
from google.colab import files
# --- 画像アップロード ---
uploaded = files.upload()
image_path = list(uploaded.keys())[0]
img = cv2.imread(image_path)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
hsv = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2HSV)
# --- 緑色マスクの作成 ---
lower_green = np.array([35, 40, 40])
upper_green = np.array([85, 255, 255])
mask = cv2.inRange(hsv, lower_green, upper_green)
# --- 輪郭抽出 ---
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# --- 面積測定(最大輪郭) ---
leaf_contour = max(contours, key=cv2.contourArea)
area_px = cv2.contourArea(leaf_contour)
# --- 実寸換算:キャリブレーション(仮に1px = 0.05cmとする) ---
px_to_cm = 0.05 # 1ピクセル = 0.05cm
area_cm2 = (area_px * (px_to_cm ** 2))
# --- 結果表示 ---
img_contour = img_rgb.copy()
cv2.drawContours(img_contour, [leaf_contour], -1, (255, 0, 0), 2)
plt.figure(figsize=(8, 6))
plt.imshow(img_contour)
plt.title(f"面積: {area_px:.1f} px² / 約 {area_cm2:.2f} cm²")
plt.axis("off")
plt.show()
# --- 数値出力 ---
print(f"ピクセル面積: {area_px:.1f} px²")
print(f"実寸換算面積: {area_cm2:.2f} cm² (換算係数: {px_to_cm}cm/pixel)")
内容 | 説明 |
色マスク+輪郭抽出 | 葉部分を特定し、最大輪郭を抽出 |
輪郭面積(ピクセル) | cv2.contourArea() を使用 |
実寸換算 | キャリブレーション係数に基づく |
視覚化と定量評価 | 作物ごとの成長・健康評価へ応用可 |
こちらが、画像分類の基礎として CNN(畳み込みニューラルネットワーク) を使ったモデル構築の入門ノートブック
week09_cnn_intro.ipynb の内容です。
この週では、葉の画像を使って「病気 or 健康」などの 2クラス分類タスクに取り組み、画像→判定のパイプライン構築を体験します。
# week09_cnn_intro.ipynb:KerasでCNNモデルを構築し、葉画像を分類
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras import layers, models
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# --- Google Drive連携(データフォルダを置く) ---
from google.colab import drive
drive.mount('/content/drive')
# --- データの準備 ---
# フォルダ構成:
# /content/drive/MyDrive/datasets/leaf_images/
# ├── healthy/
# └── diseased/
data_dir = '/content/drive/MyDrive/datasets/leaf_images/'
# --- データ拡張と前処理 ---
datagen = ImageDataGenerator(
rescale=1./255,
validation_split=0.2,
rotation_range=20,
zoom_range=0.2,
horizontal_flip=True
)
train_data = datagen.flow_from_directory(
data_dir,
target_size=(128, 128),
batch_size=32,
class_mode='binary',
subset='training'
)
val_data = datagen.flow_from_directory(
data_dir,
target_size=(128, 128),
batch_size=32,
class_mode='binary',
subset='validation'
)
# --- CNNモデル構築 ---
model = models.Sequential([
layers.Conv2D(32, (3, 3), activation='relu', input_shape=(128, 128, 3)),
layers.MaxPooling2D(2, 2),
layers.Conv2D(64, (3, 3), activation='relu'),
layers.MaxPooling2D(2, 2),
layers.Conv2D(128, (3, 3), activation='relu'),
layers.MaxPooling2D(2, 2),
layers.Flatten(),
layers.Dense(128, activation='relu'),
layers.Dense(1, activation='sigmoid')
])
# --- コンパイルと学習 ---
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
history = model.fit(train_data, epochs=10, validation_data=val_data)
# --- 学習曲線の可視化 ---
plt.plot(history.history['accuracy'], label='Train Accuracy')
plt.plot(history.history['val_accuracy'], label='Val Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
plt.title('CNN Accuracy')
plt.show()
項目 | 内容 |
CNNの構造 | 畳み込み → プーリング → Flatten → 全結合 |
データ前処理 | 正規化・データ拡張(回転・ズーム) |
分類の実行 | 健康葉 vs 病葉など |
モデル評価 | 精度と損失の可視化 |
こちらが、画像分類モデルを本格構築・保存し、今後の応用(ダッシュボードやアプリ連携)に備えるノートブック
week10_cnn_build.ipynb の内容です。
この週では、モデルの再構成・保存・読み込みまでの流れを体験し、実運用につながる技術を身につけます。
# week10_cnn_build.ipynb:CNN構築・保存・テスト予測まで
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras import layers, models
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.models import load_model
from tensorflow.keras.preprocessing import image
import os
# --- Google Drive マウント(データとモデル保存用) ---
from google.colab import drive
drive.mount('/content/drive')
# --- ディレクトリ設定 ---
data_dir = '/content/drive/MyDrive/datasets/leaf_images/' # healthy / diseased のサブフォルダを持つ
model_save_path = '/content/drive/MyDrive/models/leaf_cnn_model.h5'
# --- データ前処理 ---
datagen = ImageDataGenerator(
rescale=1./255,
validation_split=0.2
)
train_data = datagen.flow_from_directory(
data_dir,
target_size=(128, 128),
batch_size=32,
class_mode='binary',
subset='training'
)
val_data = datagen.flow_from_directory(
data_dir,
target_size=(128, 128),
batch_size=32,
class_mode='binary',
subset='validation'
)
# --- CNN構築 ---
model = models.Sequential([
layers.Conv2D(32, (3, 3), activation='relu', input_shape=(128, 128, 3)),
layers.MaxPooling2D(2, 2),
layers.Conv2D(64, (3, 3), activation='relu'),
layers.MaxPooling2D(2, 2),
layers.Conv2D(128, (3, 3), activation='relu'),
layers.MaxPooling2D(2, 2),
layers.Flatten(),
layers.Dense(128, activation='relu'),
layers.Dropout(0.3),
layers.Dense(1, activation='sigmoid')
])
# --- コンパイル・学習 ---
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
history = model.fit(train_data, epochs=10, validation_data=val_data)
# --- モデル保存 ---
model.save(model_save_path)
print(f"✅ モデル保存完了:{model_save_path}")
# --- 学習曲線表示 ---
plt.plot(history.history['accuracy'], label='Train Acc')
plt.plot(history.history['val_accuracy'], label='Val Acc')
plt.legend()
plt.title('CNN Accuracy')
plt.show()
# --- 保存モデル読み込み ---
model = load_model(model_save_path)
# --- 単一画像による予測 ---
test_img_path = '/content/drive/MyDrive/test_leaf.jpg'
img = image.load_img(test_img_path, target_size=(128, 128))
img_array = image.img_to_array(img) / 255.0
img_array = np.expand_dims(img_array, axis=0)
prediction = model.predict(img_array)[0][0]
label = "Diseased" if prediction > 0.5 else "Healthy"
plt.imshow(img)
plt.title(f"予測: {label}(スコア: {prediction:.2f})")
plt.axis('off')
plt.show()
項目 | 内容 |
CNN構成の強化 | Dropout追加などで汎化能力アップ |
モデルの保存・再利用 | .h5形式で保存し、Streamlit等へ展開可能 |
単一画像の分類テスト | 実運用を想定したスクリプト形式 |
こちらが、データ拡張(Data Augmentation) にフォーカスしたノートブック
week11_data_aug.ipynb の内容です。
この週では、農業データにありがちな「データ不足・偏り」を解消するため、Keras の ImageDataGenerator を用いた拡張や、Albumentationsライブラリの利用にも触れていきます。
# week11_data_aug.ipynb:データ拡張による画像分類精度向上
import os
import matplotlib.pyplot as plt
import numpy as np
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.preprocessing import image
# --- 拡張前の画像を確認 ---
img_path = '/content/drive/MyDrive/datasets/leaf_images/healthy/001.jpg'
img = image.load_img(img_path, target_size=(128, 128))
img_array = image.img_to_array(img)
img_array = np.expand_dims(img_array, axis=0)
plt.imshow(img.astype("uint8"))
plt.title("Original Image")
plt.axis('off')
plt.show()
# --- ImageDataGenerator による拡張 ---
datagen = ImageDataGenerator(
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest'
)
# --- 拡張画像の表示 ---
aug_iter = datagen.flow(img_array, batch_size=1)
plt.figure(figsize=(12, 6))
for i in range(6):
plt.subplot(2, 3, i+1)
batch = next(aug_iter)
image_aug = batch[0].astype("uint8")
plt.imshow(image_aug)
plt.axis('off')
plt.title(f'Augmented {i+1}')
plt.suptitle('🌿 Image Augmentation Samples')
plt.show()
# インストール(初回のみ)
!pip install -q albumentations
import albumentations as A
from PIL import Image
# --- 拡張パイプライン ---
transform = A.Compose([
A.RandomCrop(width=120, height=120),
A.HorizontalFlip(p=0.5),
A.RandomBrightnessContrast(p=0.2),
A.Rotate(limit=40),
A.Resize(128, 128)
])
# --- 拡張適用 ---
img_pil = Image.open(img_path).convert("RGB")
img_np = np.array(img_pil)
augmented = transform(image=img_np)['image']
plt.imshow(augmented)
plt.title("Albumentations Example")
plt.axis('off')
plt.show()
技術 | 内容 |
ImageDataGenerator | Keras標準のリアルタイム拡張 |
Albumentations | 高速で多彩な拡張手法(Pytorchにも対応) |
実装パターン | 可視化/保存/訓練データへの導入方法 |
こちらが、転移学習(Transfer Learning) を使って、学習済みモデル(例:MobileNetV2)を農業の画像分類に応用するノートブック
week12_transfer_learning.ipynb の内容です。
# week12_transfer_learning.ipynb:学習済みモデルを活用した葉の分類
import tensorflow as tf
from tensorflow.keras.applications import MobileNetV2
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Dense, GlobalAveragePooling2D
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import matplotlib.pyplot as plt
# --- Google Drive をマウント(データ/保存先用) ---
from google.colab import drive
drive.mount('/content/drive')
# --- データセット準備 ---
data_dir = '/content/drive/MyDrive/datasets/leaf_images/' # healthy / diseased フォルダあり
img_size = (160, 160)
batch_size = 32
datagen = ImageDataGenerator(rescale=1./255, validation_split=0.2)
train_gen = datagen.flow_from_directory(
data_dir,
target_size=img_size,
batch_size=batch_size,
class_mode='binary',
subset='training'
)
val_gen = datagen.flow_from_directory(
data_dir,
target_size=img_size,
batch_size=batch_size,
class_mode='binary',
subset='validation'
)
# --- 転移学習モデル構築 ---
base_model = MobileNetV2(input_shape=img_size + (3,), include_top=False, weights='imagenet')
base_model.trainable = False # 転移学習の基本:特徴抽出部分は固定
x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(64, activation='relu')(x)
output = Dense(1, activation='sigmoid')(x)
model = Model(inputs=base_model.input, outputs=output)
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
# --- 学習 ---
history = model.fit(train_gen, validation_data=val_gen, epochs=5)
# --- 学習結果の可視化 ---
plt.plot(history.history['accuracy'], label='Train Acc')
plt.plot(history.history['val_accuracy'], label='Val Acc')
plt.legend()
plt.title('Transfer Learning Accuracy')
plt.show()
# --- base_modelの一部を再学習可能に ---
base_model.trainable = True
# 最後の数層のみ再学習する(例:100層以降)
fine_tune_at = 100
for layer in base_model.layers[:fine_tune_at]:
layer.trainable = False
model.compile(optimizer=tf.keras.optimizers.Adam(1e-5),
loss='binary_crossentropy',
metrics=['accuracy'])
fine_tune_epochs = 5
history_fine = model.fit(train_gen, validation_data=val_gen, epochs=fine_tune_epochs)
# --- 再学習後の精度表示 ---
plt.plot(history_fine.history['accuracy'], label='Train Acc (fine)')
plt.plot(history_fine.history['val_accuracy'], label='Val Acc (fine)')
plt.legend()
plt.title('Fine-Tuning Accuracy')
plt.show()
項目 | 内容 |
転移学習の基本 | 学習済みCNN(MobileNetV2)の利用方法 |
特徴抽出 vs 再学習 | base_modelのtrainableの切替 |
少ないデータでの高精度 | 実用性・少量データの応用に強い |
# week13_model_eval.ipynb:モデルの評価と評価指標の計算
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix, classification_report
from tensorflow.keras.models import load_model
from tensorflow.keras.preprocessing import image
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# --- モデル読み込み ---
model_path = '/content/drive/MyDrive/models/leaf_cnn_model.h5'
model = load_model(model_path)
# --- データ準備 ---
data_dir = '/content/drive/MyDrive/datasets/leaf_images/'
img_size = (160, 160)
batch_size = 32
datagen = ImageDataGenerator(rescale=1./255, validation_split=0.2)
val_gen = datagen.flow_from_directory(
data_dir,
target_size=img_size,
batch_size=batch_size,
class_mode='binary',
subset='validation'
)
# --- モデル評価 ---
loss, accuracy = model.evaluate(val_gen)
print(f"Loss: {loss:.4f}, Accuracy: {accuracy:.4f}")
# --- 混同行列の計算 ---
val_pred = model.predict(val_gen)
val_pred = (val_pred > 0.5).astype("int32") # 0.5で2クラス分類
true_labels = val_gen.classes
cm = confusion_matrix(true_labels, val_pred)
# --- 混同行列の表示 ---
plt.figure(figsize=(8, 6))
plt.imshow(cm, interpolation='nearest', cmap=plt.cm.Blues)
plt.title('Confusion Matrix')
plt.colorbar()
classes = ['Healthy', 'Diseased']
plt.xticks(np.arange(len(classes)), classes, rotation=45)
plt.yticks(np.arange(len(classes)), classes)
plt.ylabel('True label')
plt.xlabel('Predicted label')
plt.tight_layout()
plt.show()
# --- 分類レポート ---
report = classification_report(true_labels, val_pred, target_names=classes)
print(report)
評価項目 | 内容 |
評価指標 | Loss, Accuracy などの基本評価指標 |
混同行列 | モデルの誤分類を視覚化して理解 |
分類レポート | 精度、再現率、F1スコアを一目で確認 |
2クラス分類 | threshold を用いた分類の精度評価 |
こちらが、YOLO(You Only Look Once)による物体検出に関するノートブック、
week14_yolo_intro.ipynb の内容です。
# week14_yolo_intro.ipynb:YOLO(You Only Look Once)を用いた物体検出
import cv2
import numpy as np
import matplotlib.pyplot as plt
# --- YOLOの設定 ---
yolo_cfg = '/content/drive/MyDrive/yolov3/yolov3.cfg'
yolo_weights = '/content/drive/MyDrive/yolov3/yolov3.weights'
yolo_names = '/content/drive/MyDrive/yolov3/coco.names'
# --- YOLOネットワークの読み込み ---
net = cv2.dnn.readNetFromDarknet(yolo_cfg, yolo_weights)
layer_names = net.getLayerNames()
output_layers = [layer_names[i-1] for i in net.getUnconnectedOutLayers()]
# --- 画像読み込みと前処理 ---
image_path = '/content/drive/MyDrive/datasets/test_image.jpg'
img = cv2.imread(image_path)
height, width, channels = img.shape
# YOLO用に画像の前処理
blob = cv2.dnn.blobFromImage(img, 0.00392, (416, 416), (0, 0, 0), True, crop=False)
net.setInput(blob)
# --- 物体検出の実行 ---
outs = net.forward(output_layers)
# --- 検出結果の解析 ---
class_ids = []
confidences = []
boxes = []
conf_threshold = 0.5 # 信頼度の閾値
nms_threshold = 0.4 # 非最大抑制の閾値
for out in outs:
for detection in out:
scores = detection[5:]
class_id = np.argmax(scores)
confidence = scores[class_id]
if confidence > conf_threshold:
center_x = int(detection[0] * width)
center_y = int(detection[1] * height)
w = int(detection[2] * width)
h = int(detection[3] * height)
# バウンディングボックスの座標
x = int(center_x - w / 2)
y = int(center_y - h / 2)
boxes.append([x, y, w, h])
confidences.append(float(confidence))
class_ids.append(class_id)
# --- 非最大抑制(NMS)の適用 ---
indices = cv2.dnn.NMSBoxes(boxes, confidences, conf_threshold, nms_threshold)
# --- 結果の描画 ---
font = cv2.FONT_HERSHEY_SIMPLEX
colors = np.random.uniform(0, 255, size=(len(class_ids), 3))
for i in range(len(boxes)):
if i in indices:
x, y, w, h = boxes[i]
label = str(class_ids[i])
confidence = confidences[i]
color = colors[i]
# バウンディングボックスとラベルの描画
cv2.rectangle(img, (x, y), (x + w, y + h), color, 2)
cv2.putText(img, f'{label} {confidence:.2f}', (x, y - 10), font, 0.5, color, 2)
# 結果の表示
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.title('YOLO Object Detection')
plt.axis('off')
plt.show()
内容 | 詳細 |
YOLOの基本 | 物体検出モデル(YOLO)の読み込みと実行方法 |
物体検出の流れ | 画像の前処理、物体検出、バウンディングボックスの生成 |
NMS(非最大抑制) | 重複した検出結果を減らす手法 |
画像処理の実践 | OpenCVを用いた物体検出結果の可視化 |
このノートブックを基に、次週はYOLOを使った訓練や農業データへの適用について進めることができます!
こちらが、農業向けYOLO物体検出モデルに特化したノートブック、
week15_yolo_agri.ipynb の内容です。
# week15_yolo_agri.ipynb:農業向けYOLOを用いた作物検出
import cv2
import numpy as np
import matplotlib.pyplot as plt
# --- YOLOの設定(農業専用のデータセット) ---
yolo_cfg = '/content/drive/MyDrive/yolov3/yolov3_agri.cfg'
yolo_weights = '/content/drive/MyDrive/yolov3/yolov3_agri.weights'
yolo_names = '/content/drive/MyDrive/yolov3/agri_classes.names'
# --- YOLOネットワークの読み込み ---
net = cv2.dnn.readNetFromDarknet(yolo_cfg, yolo_weights)
layer_names = net.getLayerNames()
output_layers = [layer_names[i-1] for i in net.getUnconnectedOutLayers()]
# --- 農業画像の読み込み ---
image_path = '/content/drive/MyDrive/datasets/agri_test_image.jpg' # 農作物の画像
img = cv2.imread(image_path)
height, width, channels = img.shape
# YOLO用に画像の前処理
blob = cv2.dnn.blobFromImage(img, 0.00392, (416, 416), (0, 0, 0), True, crop=False)
net.setInput(blob)
# --- 物体検出の実行 ---
outs = net.forward(output_layers)
# --- 検出結果の解析 ---
class_ids = []
confidences = []
boxes = []
conf_threshold = 0.5 # 信頼度の閾値
nms_threshold = 0.4 # 非最大抑制の閾値
for out in outs:
for detection in out:
scores = detection[5:]
class_id = np.argmax(scores)
confidence = scores[class_id]
if confidence > conf_threshold:
center_x = int(detection[0] * width)
center_y = int(detection[1] * height)
w = int(detection[2] * width)
h = int(detection[3] * height)
# バウンディングボックスの座標
x = int(center_x - w / 2)
y = int(center_y - h / 2)
boxes.append([x, y, w, h])
confidences.append(float(confidence))
class_ids.append(class_id)
# --- 非最大抑制(NMS)の適用 ---
indices = cv2.dnn.NMSBoxes(boxes, confidences, conf_threshold, nms_threshold)
# --- 結果の描画 ---
font = cv2.FONT_HERSHEY_SIMPLEX
colors = np.random.uniform(0, 255, size=(len(class_ids), 3))
# 農業特有のクラス名
with open(yolo_names, 'r') as f:
classes = f.read().strip().split('\n')
for i in range(len(boxes)):
if i in indices:
x, y, w, h = boxes[i]
label = str(classes[class_ids[i]])
confidence = confidences[i]
color = colors[i]
# バウンディングボックスとラベルの描画
cv2.rectangle(img, (x, y), (x + w, y + h), color, 2)
cv2.putText(img, f'{label} {confidence:.2f}', (x, y - 10), font, 0.5, color, 2)
# 結果の表示
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.title('YOLO Object Detection - Agriculture')
plt.axis('off')
plt.show()
内容 | 詳細 |
農業特有のクラス | 農作物や病害虫、作物の状態などを識別するクラス |
カスタマイズされたYOLOモデル | 農業向けにトレーニングされたYOLOモデルの使い方 |
農業画像の物体検出 | 農作物、果物、病害の検出とバウンディングボックスの描画 |
こちらが、作物の病害分類に特化したノートブック、
week16_disease_classify.ipynb の内容です。
# week16_disease_classify.ipynb:病気画像分類(例:葉の病害)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout
from sklearn.metrics import classification_report, confusion_matrix
# --- データセットの準備 ---
# ディレクトリ構成(例):
# /content/drive/MyDrive/datasets/leaf_disease/
# ├── train/
# │ ├── healthy/
# │ └── diseased/
# └── val/
# ├── healthy/
# └── diseased/
train_dir = '/content/drive/MyDrive/datasets/leaf_disease/train'
val_dir = '/content/drive/MyDrive/datasets/leaf_disease/val'
img_size = (128, 128)
batch_size = 32
train_datagen = ImageDataGenerator(rescale=1./255)
val_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
train_dir,
target_size=img_size,
batch_size=batch_size,
class_mode='binary'
)
val_generator = val_datagen.flow_from_directory(
val_dir,
target_size=img_size,
batch_size=batch_size,
class_mode='binary'
)
# --- モデル構築(CNN) ---
model = Sequential([
Conv2D(32, (3, 3), activation='relu', input_shape=(128, 128, 3)),
MaxPooling2D(2, 2),
Conv2D(64, (3, 3), activation='relu'),
MaxPooling2D(2, 2),
Flatten(),
Dense(128, activation='relu'),
Dropout(0.3),
Dense(1, activation='sigmoid')
])
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
# --- モデル学習 ---
history = model.fit(
train_generator,
epochs=10,
validation_data=val_generator
)
# --- 学習の可視化 ---
plt.plot(history.history['accuracy'], label='Train Acc')
plt.plot(history.history['val_accuracy'], label='Val Acc')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.title('Disease Classification Accuracy')
plt.legend()
plt.show()
# --- モデル評価 ---
val_generator.reset()
preds = model.predict(val_generator, verbose=1)
y_pred = (preds > 0.5).astype('int32').flatten()
y_true = val_generator.classes
print(classification_report(y_true, y_pred))
print("Confusion Matrix:")
print(confusion_matrix(y_true, y_pred))
学習項目 | 説明 |
CNN構築の基礎 | 畳み込み、プーリング、全結合層などの使い方 |
データ前処理 | ImageDataGeneratorでの画像スケーリング |
学習・評価・可視化 | 精度のグラフ描画、分類レポート、混同行列 |
クラス分類 | 健康な葉 vs 病害を受けた葉の分類 |