ディレクトリから画像をコピーして、黒枠をトリミングしてみた話【Deep Learning でも活用】

## はじめに

こんにちは！今回はPythonで「**ディレクトリごとに画像をコピーし、さらに黒枠を自動でトリミングする**」という話をお届けします。  
実はこれ、ただの画像処理だけでなく、**Deep Learning** の画像データ前処理でも役立つんです。  
Deep Learningでのトレーニングデータを準備する際、黒枠付きの画像をそのまま使うと、モデルの精度が下がる原因になることがあります。  
そこで、このスクリプトで黒枠を自動トリミングすることで、データの質を高め、学習結果を向上させました！

では、実際のコードとその流れを見ていきましょう。

## やりたいこと
1. `images_train_1` から `images_train_10` までのディレクトリから画像をコピーする。
2. コピーした画像の黒枠を自動でトリミングし、Deep Learning 用に準備。

## まずはコピーから

Deep Learning のトレーニングデータは数千枚に及ぶことが多く、それを手動で処理していたら一日が終わってしまいます。  
そんな時は、Pythonで一気にファイルをコピーしてしまいましょう。

```python
import os
import shutil
from tqdm import tqdm

source_dir_base = "path_to_source_directory"
dest_dir = "path_to_destination_directory"

for i in range(1, 11):
    source_dir = os.path.join(source_dir_base, f'images_train_{i}')

    # ソースディレクトリが存在しない場合はスキップ
    if not os.path.exists(source_dir):
        print(f"Source directory '{source_dir}' not found. Skipping...")
        continue

    # ファイルをコピー
    for filename in tqdm(os.listdir(source_dir)):
        source_file = os.path.join(source_dir, filename)
        dest_file = os.path.join(dest_dir, filename)
        shutil.copy(source_file, dest_file)
        print(f"Copied '{filename}' to '{dest_dir}'")
```

### ポイント
1. ディレクトリが存在しない場合は、`os.path.exists` でチェックしてスキップ。Deep Learning のトレーニングデータは膨大なので、ここでミスを避けます。
2. `tqdm` で進行状況を可視化して、コピーの進捗がひと目でわかるようにしています。

## 黒枠トリミングでクリーンなデータに！

次は画像処理。黒枠がついたままの画像をそのままモデルに入力すると、余計な情報を学習してしまうことがあります。そこで、画像から黒枠をトリミングしてクリーンなデータにしましょう。

```python
import cv2
import numpy as np

def trim_black_borders(image, tol=10):
    # Convert image to grayscale
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # Create a binary mask where non-black pixels are white
    mask = gray > tol

    # If the entire image is black, return the original image
    if not np.any(mask):
        return image

    # Get the bounding box of non-black pixels
    coords = np.argwhere(mask)
    x0, y0, x1, y1 = coords.min(axis=0)[0], coords.min(axis=0)[1], coords.max(axis=0)[0] + 1, coords.max(axis=0)[1] + 1

    # Crop the image
    trimmed_image = image[x0:x1, y0:y1]

    return trimmed_image
```

### トリミングのポイント
- 黒い部分を除去するために、`cv2.cvtColor` で画像をグレースケール化します。これにより、黒かそうでないかを単純に区別できるようになります。
- `np.argwhere` で黒くない領域の境界を特定し、その範囲だけをトリミングします。  
- もし画像全体が真っ黒の場合は、そのまま返すようにしています（念のため）。

## トリミング後にファイルを保存！

最後に、コピーした画像を黒枠トリミングして、元のファイルに上書き保存していきます。

```python
for filename in tqdm(os.listdir(dest_dir)):
    if filename.lower().endswith((".png", ".jpg", ".jpeg")):
        image_path = os.path.join(dest_dir, filename)
        image = cv2.imread(image_path)

        if image is not None:
            trimmed_image = trim_black_borders(image)
            cv2.imwrite(image_path, trimmed_image)  # 元のファイルに上書き
            print(f"Processed and saved: {image_path}")
        else:
            print(f"Failed to load image: {image_path}")
```

## Deep Learning モデルの精度向上に役立った話

このスクリプトを実際にDeep Learningのデータ準備で使ったところ、黒枠をトリミングした画像の方がモデルの学習結果が良好に！  
黒枠付きの画像をそのまま学習させると、モデルが余計な背景情報を覚えてしまい、重要な部分に焦点が当たらなくなってしまいます。  
しかし、トリミング後は、画像の中心部分（つまり本当に学習してほしい部分）にモデルが集中できるようになり、精度が向上しました！

## おわりに

このスクリプトを使えば、Deep Learning の画像前処理を大幅に効率化できます。大量のデータを扱う場合、こうした自動化によって時間を節約し、モデルの精度も向上させることができます。  
画像の黒枠をトリミングしてすっきりさせるだけで、データセット全体の質を上げ、より良い結果を得られることを実感しました。ぜひ試してみてください！