STEP 2:画像の基礎知識

📷 STEP 2: 画像の基礎知識

デジタル画像の表現、RGB・グレースケール、画像の読み込みと基本操作を学びます

📋 このステップで学ぶこと

  • デジタル画像の表現(ピクセル、解像度、チャンネル)
  • RGB、RGBA、グレースケールの理解
  • PIL/Pillow、OpenCV、matplotlibでの画像読み込み
  • 画像の基本操作(リサイズ、クロップ、回転、反転)
  • 色空間変換(RGB↔HSV)
  • NumPy配列としての画像処理

練習問題: 5問

🎯 1. デジタル画像とは何か

STEP 1で「コンピュータにとって画像は数字の羅列」と学びました。このセクションでは、その「数字」がどのように構成されているかを詳しく見ていきます。

1-1. ピクセル(画素)とは?

デジタル画像は、ピクセル(画素)の集合です。「ピクセル」とは「Picture Element(画像要素)」の略で、画像を構成する最小単位です。

📷 例え話:モザイクアート

デジタル画像は、小さなタイルを並べたモザイクアートのようなものです。

1つのタイル = 1ピクセル
・近くで見ると、タイルの集まりに見える
・遠くから見ると、1枚の絵に見える

タイルの数 = 解像度
・タイルが多い(高解像度)→ 細かい絵が描ける
・タイルが少ない(低解像度)→ 粗い絵になる

【ピクセルの基本】 ピクセル(Pixel)= Picture Element(画像要素)の略 ・画像を構成する「最小単位」 ・1ピクセル = 1つの点 ・各ピクセルは「色」の情報を持つ 例: ・白いピクセル:RGB(255, 255, 255) ・黒いピクセル:RGB(0, 0, 0) ・赤いピクセル:RGB(255, 0, 0)

1-2. 解像度(Resolution)とは?

解像度は、画像の「幅」×「高さ」のピクセル数を表します。解像度が高いほど、細かい表現が可能になります。

【解像度の例】 ・640×480 = 307,200ピクセル(VGA) → 約30万ピクセル ・1920×1080 = 2,073,600ピクセル(フルHD) → 約207万ピクセル(1080pとも呼ばれる) ・3840×2160 = 8,294,400ピクセル(4K) → 約829万ピクセル(フルHDの4倍) 高解像度のメリット:細かい表現が可能、拡大しても綺麗 高解像度のデメリット:データサイズが大きい、処理に時間がかかる
🎯 画像サイズとファイルサイズの違い

この2つは別物なので注意が必要です。

解像度(画像サイズ):ピクセル数(例:1920×1080)
ファイルサイズ:圧縮後のバイト数(例:500KB)

JPEG、PNGなどの形式は圧縮されているため、ファイルサイズは小さくなります。
プログラムで読み込むと、メモリ上では「解像度×チャンネル数」分のサイズになります。

🎨 2. 色の表現 – RGB、RGBA、グレースケール

コンピュータはどのように「色」を表現しているのでしょうか?主な3つの形式を学びましょう。

2-1. RGB(Red, Green, Blue)

最も一般的な色の表現方法です。光の三原色(赤・緑・青)を混ぜ合わせて、様々な色を表現します。

🔴🟢🔵 RGBの仕組み

各ピクセルが、赤(R)、緑(G)、青(B)の3つの値を持ちます。
それぞれの値は 0〜255 の256段階(8ビット)です。

【RGBの色の例】 各色の値は 0(暗い)〜 255(明るい)の範囲 ■ 基本の色 ・赤: RGB(255, 0, 0) ← 赤だけMAX ・緑: RGB(0, 255, 0) ← 緑だけMAX ・青: RGB(0, 0, 255) ← 青だけMAX ■ 混ぜ合わせた色 ・黄色: RGB(255, 255, 0) ← 赤+緑 ・紫: RGB(255, 0, 255) ← 赤+青 ・水色: RGB(0, 255, 255) ← 緑+青 ■ 白と黒 ・白: RGB(255, 255, 255) ← 全部MAX(光を全部混ぜると白) ・黒: RGB(0, 0, 0) ← 全部0(光がないと黒) ■ 灰色 ・灰色: RGB(128, 128, 128) ← 全部同じ値で灰色になる

なぜRGB(255, 255, 255)が白になるのか、疑問に思うかもしれません。絵の具を混ぜると黒っぽくなりますよね。

💡 光の混色と絵の具の混色の違い

RGBは「光」の混色(加法混色)
・光を混ぜると、どんどん明るくなる
・全部混ぜると → 白
・ディスプレイ、プロジェクターなどで使用

絵の具は「色素」の混色(減法混色)
・色素を混ぜると、どんどん暗くなる
・全部混ぜると → 黒っぽくなる
・印刷物(CMYK)で使用

2-2. RGBA(RGB + Alpha)

RGBに透明度(Alpha)を加えたものです。Webデザインや画像合成でよく使われます。

【RGBAとは】 RGB + アルファチャンネル(透明度) ・R(赤): 0〜255 ・G(緑): 0〜255 ・B(青): 0〜255 ・A(透明度):0〜255 ├─ 0 = 完全に透明(見えない) ├─ 128 = 半透明 └─ 255 = 不透明(普通の状態) 【用途】 ・PNG画像(透過PNG) ・UI/グラフィックデザイン(ボタンの半透明効果など) ・画像合成(背景と人物を重ねるなど)

2-3. グレースケール(Grayscale)

白〜黒の濃淡だけで表現した画像です。「白黒写真」のようなものです。

⚪⚫ グレースケールとは

1ピクセル = 1つの値(0〜255)で表現

・0 = 黒
・128 = 灰色(中間)
・255 = 白

【RGB → グレースケール変換式】 単純な平均ではなく、人間の目の感度を考慮した重み付け平均を使う Gray = 0.299×R + 0.587×G + 0.114×B なぜこの重みなのか? ・人間の目は「緑」に最も敏感 ・次いで「赤」、「青」の順 ・この重みで変換すると、人間の目に自然に見える
💡 なぜグレースケールを使うのか?

メリット:
データサイズが1/3:RGBは3チャンネル、グレースケールは1チャンネル
処理が速い:計算量が減る
色が不要なタスク:エッジ検出、文字認識など

使用例:
・文字認識(OCR)
・エッジ検出
・古典的CV手法(SIFT、HOGなど)

ただし、現代の深層学習ではRGBを直接使うことが多いです。色の情報も有用な特徴になるからです。

2-4. チャンネル(Channel)について

「チャンネル」は画像の「次元」のようなものです。RGBなら3チャンネル、グレースケールなら1チャンネルです。

【チャンネルとは】 画像データの「層」のこと ・グレースケール:1チャンネル(H × W × 1)または(H × W) ・RGB: 3チャンネル(H × W × 3) ・RGBA: 4チャンネル(H × W × 4) 例:640×480のRGB画像 → 640 × 480 × 3 = 921,600個の値 → NumPy配列では shape=(480, 640, 3) ※注意:(高さ, 幅, チャンネル)の順番!(幅, 高さではない)
形式 チャンネル数 値の範囲 主な用途
グレースケール 1 0〜255 文字認識、エッジ検出
RGB 3 各0〜255 一般的な画像処理、深層学習
RGBA 4 各0〜255 透過画像、画像合成

💻 3. Pythonでの画像読み込み

Pythonには、画像を扱うための複数のライブラリがあります。それぞれの特徴を理解して、適切に使い分けましょう。

3-1. 主要ライブラリの比較

ライブラリ 特徴 チャンネル順序 主な用途
PIL/Pillow シンプル、初心者向け RGB 基本的な画像操作
OpenCV 高速、機能豊富 BGR(注意!) コンピュータビジョン
matplotlib 可視化に強い RGB 画像表示、グラフ作成
⚠️ 超重要:OpenCVはBGR順序!

OpenCVは歴史的な理由で、BGR(青、緑、赤)の順序で画像を読み込みます。
一般的なRGB順序とはなので、色がおかしくなる原因になります。

対処法:OpenCVで読み込んだら、すぐにRGBに変換する習慣をつけましょう。

3-2. PIL/Pillow – シンプルで使いやすい

最初に学ぶならPillowがおすすめです。直感的で分かりやすい書き方ができます。

ステップ1:ライブラリのインポート

# PIL(Pillow)からImageクラスをインポート # Image:画像を読み込み・保存・加工するためのクラス from PIL import Image # NumPyもインポート(配列操作に使用) import numpy as np

ステップ2:画像の読み込み

# Image.open()で画像ファイルを開く # 引数:画像ファイルのパス(文字列) img = Image.open(‘sample.jpg’) # この時点ではまだ「PIL Imageオブジェクト」であり、 # NumPy配列ではないことに注意

ステップ3:画像情報の確認

# size属性で画像のサイズを取得 # 注意:Pillowは (幅, 高さ) の順番で返す print(img.size) # 出力例: (640, 480) # mode属性で色モードを確認 # ‘RGB’ = カラー画像 # ‘L’ = グレースケール # ‘RGBA’ = 透過あり print(img.mode) # 出力例: ‘RGB’

ステップ4:NumPy配列への変換

# np.array()でNumPy配列に変換 # これにより、ピクセル値を直接操作できるようになる img_array = np.array(img) # 配列の形状を確認 # NumPyは (高さ, 幅, チャンネル) の順番 print(img_array.shape) # 出力例: (480, 640, 3)

完成コード(実際に入力して試す場合)

以下のコードをGoogle Colabで実行できます。

# PIL/Pillowで画像を読み込む完全なコード from PIL import Image import numpy as np # サンプル画像をダウンロード import urllib.request url = “https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg” urllib.request.urlretrieve(url, “sample.jpg”) # 画像を読み込み img = Image.open(‘sample.jpg’) # 画像情報を表示 print(f”サイズ(幅×高さ): {img.size}”) print(f”色モード: {img.mode}”) # NumPy配列に変換 img_array = np.array(img) print(f”配列の形状(高さ, 幅, チャンネル): {img_array.shape}”) print(f”データ型: {img_array.dtype}”) # 画像を表示(Jupyter/Colabの場合) img.show() # または display(img)

実行結果:

サイズ(幅×高さ): (1200, 800) 色モード: RGB 配列の形状(高さ, 幅, チャンネル): (800, 1200, 3) データ型: uint8

3-3. OpenCV – 高速で機能豊富

コンピュータビジョンの実務では、OpenCVが最もよく使われます。C++で実装されているため高速です。

ステップ1:ライブラリのインポート

# cv2はOpenCVのPythonバインディング # opencv-pythonをインストールすると使える import cv2 # NumPyも必要 import numpy as np

ステップ2:画像の読み込み

# cv2.imread()で画像を読み込む # 重要:OpenCVはBGR順序で読み込む! img_bgr = cv2.imread(‘sample.jpg’) # 読み込みに失敗するとNoneが返る if img_bgr is None: print(“画像の読み込みに失敗しました”) else: print(“読み込み成功”)

ステップ3:BGR → RGB変換(重要!)

# OpenCVはBGR順序で読み込むため、 # 他のライブラリ(matplotlib等)と組み合わせる場合は # RGB順序に変換する必要がある # cv2.cvtColor()で色空間を変換 # cv2.COLOR_BGR2RGB:BGRからRGBへ変換 img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) # これでmatplotlibで正しい色で表示できる

ステップ4:グレースケールで読み込む方法

# 第2引数で読み込みモードを指定できる # cv2.IMREAD_GRAYSCALE:グレースケールで読み込み img_gray = cv2.imread(‘sample.jpg’, cv2.IMREAD_GRAYSCALE) # グレースケールは2次元配列になる print(img_gray.shape) # 出力例: (480, 640)

完成コード(実際に入力して試す場合)

# OpenCVで画像を読み込む完全なコード import cv2 import numpy as np import matplotlib.pyplot as plt # サンプル画像をダウンロード import urllib.request url = “https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg” urllib.request.urlretrieve(url, “sample.jpg”) # 画像を読み込み(BGR順序) img_bgr = cv2.imread(‘sample.jpg’) # RGB順序に変換 img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) # グレースケールでも読み込み img_gray = cv2.imread(‘sample.jpg’, cv2.IMREAD_GRAYSCALE) # 画像情報を表示 print(f”カラー画像の形状: {img_rgb.shape}”) print(f”グレースケール画像の形状: {img_gray.shape}”) # matplotlibで表示 fig, axes = plt.subplots(1, 2, figsize=(12, 5)) axes[0].imshow(img_rgb) axes[0].set_title(‘RGB Image’) axes[0].axis(‘off’) axes[1].imshow(img_gray, cmap=’gray’) axes[1].set_title(‘Grayscale Image’) axes[1].axis(‘off’) plt.tight_layout() plt.show()
✅ OpenCVの特徴まとめ

高速:C++で実装、最適化されている
機能豊富:フィルタ、エッジ検出、物体検出など多数
NumPy配列:直接NumPy配列として扱える
BGR順序:注意が必要!読み込んだらすぐRGBに変換する習慣を

3-4. どのライブラリを使うべき?

💡 ライブラリの使い分けガイド

🎨 PIL/Pillow を使う場面:
・シンプルな画像操作(リサイズ、クロップなど)
・プロトタイピング、学習目的
・PyTorchのデータ拡張(torchvision.transforms)

🚀 OpenCV を使う場面:
・本格的なコンピュータビジョン開発
・リアルタイム処理(動画、カメラ入力)
・高度な画像処理(フィルタ、エッジ検出、特徴抽出)

📊 matplotlib を使う場面:
・画像の可視化、表示
・Jupyter Notebook での開発
・グラフと画像を組み合わせた表示

このコースでは、OpenCVを中心に学びます(CV業界の標準)

🔧 4. 画像の基本操作

画像のリサイズ、クロップ、回転、反転など、基本操作を学びましょう。これらは深層学習のデータ拡張でも頻繁に使われます。

4-1. リサイズ(Resize)

画像の大きさを変更する操作です。深層学習では、モデルの入力サイズに合わせるために必須です。

OpenCVでのリサイズ

# cv2.resize()で画像をリサイズ # 第1引数:元の画像 # 第2引数:(新しい幅, 新しい高さ) のタプル import cv2 # 画像読み込み img = cv2.imread(‘sample.jpg’) # 320×240にリサイズ img_resized = cv2.resize(img, (320, 240)) print(f”元のサイズ: {img.shape}”) print(f”リサイズ後: {img_resized.shape}”)

アスペクト比を保持してリサイズ

単純にリサイズすると、画像が歪む可能性があります。アスペクト比(縦横比)を保持する方法も覚えておきましょう。

# アスペクト比を保持してリサイズする関数 def resize_keeping_aspect_ratio(img, new_width): “”” 幅を指定して、アスペクト比を保持してリサイズする 引数: img: 元の画像 new_width: 新しい幅 戻り値: リサイズされた画像 “”” # 元の画像のサイズを取得 height, width = img.shape[:2] # アスペクト比を計算 aspect_ratio = height / width # 新しい高さを計算(アスペクト比を維持) new_height = int(new_width * aspect_ratio) # リサイズ return cv2.resize(img, (new_width, new_height))

完成コード(リサイズ)

# 画像のリサイズを試すコード import cv2 import matplotlib.pyplot as plt # 画像読み込み img = cv2.imread(‘sample.jpg’) img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 固定サイズにリサイズ(歪む可能性あり) img_fixed = cv2.resize(img_rgb, (224, 224)) # アスペクト比を保持してリサイズ height, width = img_rgb.shape[:2] new_width = 400 new_height = int(height * (new_width / width)) img_aspect = cv2.resize(img_rgb, (new_width, new_height)) # 表示 fig, axes = plt.subplots(1, 3, figsize=(15, 5)) axes[0].imshow(img_rgb) axes[0].set_title(f’Original ({img_rgb.shape[1]}x{img_rgb.shape[0]})’) axes[0].axis(‘off’) axes[1].imshow(img_fixed) axes[1].set_title(f’Fixed Size (224×224)’) axes[1].axis(‘off’) axes[2].imshow(img_aspect) axes[2].set_title(f’Keep Aspect ({new_width}x{new_height})’) axes[2].axis(‘off’) plt.tight_layout() plt.show()

4-2. クロップ(Crop)- 切り抜き

画像の一部を切り抜く操作です。NumPyのスライスを使うのが最もシンプルです。

# NumPy配列のスライスでクロップ # 書式:img[y1:y2, x1:x2] # 注意:(y, x)の順番!(数学の(x, y)とは逆) import cv2 img = cv2.imread(‘sample.jpg’) # 左上の座標(100, 50)から、右下(400, 300)までを切り抜き # y方向:50〜300、x方向:100〜400 img_cropped = img[50:300, 100:400] print(f”切り抜き後のサイズ: {img_cropped.shape}”)

中央クロップ(Center Crop)

画像の中央部分を指定サイズで切り抜く方法です。深層学習のテストデータ前処理でよく使います。

# 中央から224×224を切り抜く def center_crop(img, crop_size): “”” 画像の中央から指定サイズを切り抜く 引数: img: 元の画像 crop_size: 切り抜きサイズ(正方形) 戻り値: 切り抜かれた画像 “”” height, width = img.shape[:2] # 中央の座標を計算 top = (height – crop_size) // 2 left = (width – crop_size) // 2 # 切り抜き return img[top:top+crop_size, left:left+crop_size] # 使用例 img_center = center_crop(img, 224)

4-3. 回転(Rotation)

画像を回転させる操作です。90度単位の回転と、任意角度の回転があります。

90度単位の回転(高速)

# cv2.rotate()で90度単位の回転 import cv2 img = cv2.imread(‘sample.jpg’) # 時計回りに90度回転 img_90 = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE) # 180度回転 img_180 = cv2.rotate(img, cv2.ROTATE_180) # 反時計回りに90度回転(= 時計回りに270度) img_270 = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)

任意角度の回転

# cv2.warpAffine()で任意角度の回転 import cv2 img = cv2.imread(‘sample.jpg’) height, width = img.shape[:2] # 回転の中心点 center = (width // 2, height // 2) # 回転行列を取得 # 引数:(中心点, 角度(反時計回りが正), スケール) rotation_matrix = cv2.getRotationMatrix2D(center, 45, 1.0) # アフィン変換で回転 img_rotated = cv2.warpAffine(img, rotation_matrix, (width, height)) # 注意:回転すると、角の部分が切れてしまう # 黒い部分(背景)が見える

4-4. 反転(Flip)

画像を左右または上下に反転させる操作です。データ拡張で最も基本的なテクニックです。

# cv2.flip()で反転 import cv2 img = cv2.imread(‘sample.jpg’) # 水平反転(左右反転) # 第2引数:1 = 水平反転 img_h_flip = cv2.flip(img, 1) # 垂直反転(上下反転) # 第2引数:0 = 垂直反転 img_v_flip = cv2.flip(img, 0) # 両方向反転(180度回転と同じ) # 第2引数:-1 = 両方向反転 img_both_flip = cv2.flip(img, -1)
🎯 回転・反転の用途

データ拡張:
・水平反転だけでデータを2倍に増やせる
・回転を組み合わせれば4倍、8倍に
・モデルが様々な向きに対応できるようになる

画像補正:
・傾いて撮影された画像を修正
・スキャンした文書の向き補正

完成コード(基本操作まとめ)

# 画像の基本操作をまとめて試すコード import cv2 import numpy as np import matplotlib.pyplot as plt # 画像読み込み img = cv2.imread(‘sample.jpg’) img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 1. リサイズ img_resized = cv2.resize(img_rgb, (224, 224)) # 2. 中央クロップ height, width = img_rgb.shape[:2] crop_size = min(height, width) top = (height – crop_size) // 2 left = (width – crop_size) // 2 img_cropped = img_rgb[top:top+crop_size, left:left+crop_size] img_cropped = cv2.resize(img_cropped, (224, 224)) # 3. 回転 center = (width // 2, height // 2) rotation_matrix = cv2.getRotationMatrix2D(center, 30, 1.0) img_rotated = cv2.warpAffine(img_rgb, rotation_matrix, (width, height)) # 4. 水平反転 img_flipped = cv2.flip(img_rgb, 1) # 表示 fig, axes = plt.subplots(2, 3, figsize=(15, 10)) axes[0, 0].imshow(img_rgb) axes[0, 0].set_title(‘Original’) axes[0, 0].axis(‘off’) axes[0, 1].imshow(img_resized) axes[0, 1].set_title(‘Resized (224×224)’) axes[0, 1].axis(‘off’) axes[0, 2].imshow(img_cropped) axes[0, 2].set_title(‘Center Cropped’) axes[0, 2].axis(‘off’) axes[1, 0].imshow(img_rotated) axes[1, 0].set_title(‘Rotated (30°)’) axes[1, 0].axis(‘off’) axes[1, 1].imshow(img_flipped) axes[1, 1].set_title(‘Flipped (Horizontal)’) axes[1, 1].axis(‘off’) axes[1, 2].axis(‘off’) plt.tight_layout() plt.show()

🌈 5. 色空間変換

RGB以外にも、様々な色空間があります。タスクに応じて適切な色空間を選ぶことで、処理が効率的になります。

5-1. 主要な色空間

【色空間の種類】 ■ RGB(Red, Green, Blue) ・最も一般的 ・光の三原色 ・ディスプレイの表示に使用 ■ HSV(Hue, Saturation, Value) ・色相(H)、彩度(S)、明度(V)で表現 ・特定の色を検出するのに便利 ・照明の影響を受けにくい ■ グレースケール ・白〜黒の1チャンネル ・処理が軽い ■ Lab(Lightness, a, b) ・人間の知覚に近い ・色の差を測定するのに適している ■ YCrCb ・輝度(Y)と色差(Cr, Cb) ・動画圧縮(JPEG、MPEG)で使用

5-2. HSV色空間の詳細

HSVは色検出でよく使われる色空間です。RGB より直感的に「色」を扱えます。

🌈 HSVの3要素

H(Hue:色相) – 「何色か」
・0〜180(OpenCVの場合)または 0〜360度
・0度付近 = 赤
・60度付近 = 黄色
・120度付近 = 緑
・180度付近 = 青紫

S(Saturation:彩度) – 「色の鮮やかさ」
・0〜255(OpenCVの場合)
・0 = 無彩色(灰色)
・255 = 最も鮮やか

V(Value:明度) – 「明るさ」
・0〜255(OpenCVの場合)
・0 = 黒
・255 = 最も明るい

RGB → HSV変換

# cv2.cvtColor()で色空間を変換 import cv2 # 画像読み込み(BGR) img_bgr = cv2.imread(‘sample.jpg’) # BGR → HSV変換 img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV) # HSVの各チャンネルを分離 h, s, v = cv2.split(img_hsv) print(f”Hue(色相)の範囲: {h.min()} 〜 {h.max()}”) print(f”Saturation(彩度)の範囲: {s.min()} 〜 {s.max()}”) print(f”Value(明度)の範囲: {v.min()} 〜 {v.max()}”)
💡 HSVの用途

色検出が簡単:
・「赤い物体を検出」→ Hueが0〜10または170〜180の範囲
・RGBだと、赤はR成分だけでなくG,Bの組み合わせも考慮が必要

照明補正:
・明度(V)だけを調整すれば、色味を変えずに明るさを調整できる

次のSTEP 3で、HSVを使った色検出とトラッキングを実装します。

5-3. 色空間変換の一覧

# OpenCVでの色空間変換 import cv2 img_bgr = cv2.imread(‘sample.jpg’) # よく使う変換 img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) # BGR → RGB img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY) # BGR → グレースケール img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV) # BGR → HSV img_lab = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2LAB) # BGR → Lab # 逆変換 img_bgr_back = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2BGR) # RGB → BGR img_bgr_from_hsv = cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR) # HSV → BGR # OpenCVには100種類以上の変換フラグがある # cv2.COLOR_* で確認可能

📊 6. NumPy配列としての画像処理

Pythonでは、画像はNumPy配列として扱われます。NumPyの操作を理解すると、画像処理が自在にできます。

6-1. 画像の配列構造

# 画像の配列構造を確認 import cv2 import numpy as np img = cv2.imread(‘sample.jpg’) # 配列の形状 print(f”shape: {img.shape}”) # (高さ, 幅, チャンネル) # 出力例: (480, 640, 3) # データ型 print(f”dtype: {img.dtype}”) # uint8 = 0〜255の整数 # 出力例: uint8 # 総要素数 print(f”size: {img.size}”) # 高さ × 幅 × チャンネル # 出力例: 921600

6-2. ピクセル値へのアクセス

# ピクセル値へのアクセス方法 import cv2 img = cv2.imread(‘sample.jpg’) # 特定のピクセルの値を取得 # img[y, x] の順番(行, 列) pixel = img[100, 200] print(f”ピクセル(y=100, x=200)の値: {pixel}”) # 出力例: [123 145 89] (BGR値) # 特定のチャンネルの値を取得 blue = img[100, 200, 0] # 青チャンネル green = img[100, 200, 1] # 緑チャンネル red = img[100, 200, 2] # 赤チャンネル print(f”B={blue}, G={green}, R={red}”)

6-3. 画像の一部を変更

# 画像の一部を変更する import cv2 import numpy as np img = cv2.imread(‘sample.jpg’) # 重要:元の画像を保護するためにコピーを作成 img_copy = img.copy() # 左上100×100ピクセルを赤色に変更 # OpenCVはBGR順序なので、赤は(0, 0, 255) img_copy[0:100, 0:100] = [0, 0, 255] # 特定のチャンネルだけを変更 # 青チャンネルをゼロに(黄色っぽくなる) img_copy[:, :, 0] = 0

6-4. 画像の正規化

深層学習では、画像データを正規化することが重要です。学習の安定化と高速化に役立ちます。

# 正規化の方法 import numpy as np # 元の画像(uint8, 0〜255) img = cv2.imread(‘sample.jpg’) # 方法1:0〜1に正規化 # float32に変換してから255で割る img_normalized = img.astype(np.float32) / 255.0 print(f”範囲: {img_normalized.min()} 〜 {img_normalized.max()}”) # 出力: 範囲: 0.0 〜 1.0 # 方法2:平均0、標準偏差1に標準化 # ImageNetで学習したモデルを使う場合はこれを使う mean = np.array([0.485, 0.456, 0.406]) # ImageNetの平均(RGB) std = np.array([0.229, 0.224, 0.225]) # ImageNetの標準偏差(RGB) img_standardized = (img_normalized – mean) / std
💡 なぜ正規化するのか?

学習の安定化:勾配爆発・消失を防ぐ
収束の高速化:学習が速くなる
転移学習:事前学習モデルと同じ正規化が必要

ImageNetで事前学習されたモデル(ResNet、EfficientNetなど)を使う場合は、
必ず同じ正規化パラメータ(mean, std)を使用してください。

📝 練習問題

問題1:画像の配列構造(基礎)

以下のコードを実行したとき、出力される形状(shape)を答えてください。

import cv2 # 640×480のRGB画像を読み込み img = cv2.imread(‘sample.jpg’) # 640×480の画像 print(img.shape) # グレースケールで読み込み img_gray = cv2.imread(‘sample.jpg’, cv2.IMREAD_GRAYSCALE) print(img_gray.shape)
解答:

1つ目の出力(カラー画像):
(480, 640, 3)
・高さ480、幅640、チャンネル3(BGR)
・NumPyは(高さ, 幅, チャンネル)の順序

2つ目の出力(グレースケール):
(480, 640)
・高さ480、幅640
・グレースケールはチャンネルが1つなので、2次元配列

補足:
・画像ファイルが「640×480」と言う場合は「幅×高さ」の順番
・NumPy配列は「高さ×幅」の順番なので、(480, 640)になる

問題2:BGR vs RGB(基礎)

OpenCVで読み込んだ画像をmatplotlibで表示すると、色がおかしくなります。なぜでしょうか?また、どう修正すれば良いですか?

解答:

原因:
・OpenCVはBGR順序で画像を読み込む
・matplotlibはRGB順序を期待している
→ 赤と青が入れ替わって表示される

修正方法:
import cv2 import matplotlib.pyplot as plt # OpenCVで読み込み(BGR順序) img_bgr = cv2.imread(‘sample.jpg’) # RGB順序に変換 img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) # matplotlibで表示 plt.imshow(img_rgb) plt.axis(‘off’) plt.show()

ポイント:
・OpenCVで読み込んだら、すぐにRGBに変換するのがベストプラクティス
・保存する際は、再度BGRに戻す必要がある

問題3:画像の明るさ調整(中級)

画像全体を「50」だけ明るくするコードを書いてください。ただし、ピクセル値が255を超えないように注意してください。

解答:

import cv2 import numpy as np # 画像読み込み img = cv2.imread(‘sample.jpg’) # 方法1:np.clipを使う(推奨) # int型に変換してから加算し、0〜255にクリップ img_bright = np.clip(img.astype(int) + 50, 0, 255).astype(np.uint8) # 方法2:cv2.addを使う(自動でクリップされる) img_bright2 = cv2.add(img, np.full(img.shape, 50, dtype=np.uint8)) # 保存 cv2.imwrite(‘bright.jpg’, img_bright)

説明:
単純な加算はNG:img + 50だとオーバーフローする
np.clip:値を0〜255の範囲にクリップ
int型に変換:uint8のままだと、255+50=49になる(オーバーフロー)
cv2.add:OpenCVが自動でクリップしてくれる

よくある間違い:
# ❌ これはダメ(オーバーフローする) img_bright = img + 50 # uint8(0〜255)の範囲を超えると… # 200 + 50 = 250 ✅ # 250 + 50 = 44 ❌(256で割った余り)

問題4:データ拡張の実装(応用)

以下の変換を組み合わせた、データ拡張関数を実装してください。

  1. 画像を224×224にリサイズ
  2. 50%の確率で水平反転
  3. 0〜30度の範囲でランダムに回転
解答:

import cv2 import numpy as np import random def augment_image(img): “”” データ拡張パイプライン 引数: img: 入力画像(BGR) 戻り値: 拡張された画像 “”” # 1. リサイズ(224×224) img_aug = cv2.resize(img, (224, 224)) # 2. 50%の確率で水平反転 if random.random() < 0.5: img_aug = cv2.flip(img_aug, 1) # 3. 0〜30度のランダム回転 angle = random.uniform(0, 30) height, width = img_aug.shape[:2] center = (width // 2, height // 2) rotation_matrix = cv2.getRotationMatrix2D(center, angle, 1.0) img_aug = cv2.warpAffine(img_aug, rotation_matrix, (width, height)) return img_aug # 使用例 img = cv2.imread('sample.jpg') # 複数の拡張画像を生成 for i in range(5): img_aug = augment_image(img) cv2.imwrite(f'augmented_{i}.jpg', img_aug) print(f'拡張画像{i}を保存しました')

ポイント:
・データ拡張は学習時のみ適用
・テスト時は中央クロップのみ(ランダム要素なし)
・次のSTEP 4で、より詳しく学習します

問題5:HSVによる色検出(応用)

画像から「赤い物体」だけを抽出するコードを書いてください。HSV色空間を使い、赤の範囲を指定してマスクを作成してください。

解答:

import cv2 import numpy as np import matplotlib.pyplot as plt # 画像読み込み img = cv2.imread(‘sample.jpg’) img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # BGR → HSV変換 img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 赤の範囲を定義(HSVで) # 赤は0度付近と180度付近に2箇所ある(色相環で赤は端にある) lower_red1 = np.array([0, 100, 100]) # 0〜10度 upper_red1 = np.array([10, 255, 255]) lower_red2 = np.array([160, 100, 100]) # 160〜180度 upper_red2 = np.array([180, 255, 255]) # マスクを作成 # cv2.inRange():範囲内のピクセルを白(255)、範囲外を黒(0)に mask1 = cv2.inRange(img_hsv, lower_red1, upper_red1) mask2 = cv2.inRange(img_hsv, lower_red2, upper_red2) # 2つのマスクを結合 mask = cv2.bitwise_or(mask1, mask2) # マスクを適用して赤い部分だけ抽出 result = cv2.bitwise_and(img_rgb, img_rgb, mask=mask) # 結果を表示 fig, axes = plt.subplots(1, 3, figsize=(15, 5)) axes[0].imshow(img_rgb) axes[0].set_title(‘Original’) axes[0].axis(‘off’) axes[1].imshow(mask, cmap=’gray’) axes[1].set_title(‘Mask’) axes[1].axis(‘off’) axes[2].imshow(result) axes[2].set_title(‘Red Objects Only’) axes[2].axis(‘off’) plt.tight_layout() plt.show()

説明:
HSVで色検出が簡単な理由:Hue(色相)が色を直接表すため
赤が2箇所:Hueは0〜180度の範囲で、赤は0度と180度付近にある
inRange:範囲内のピクセルを白(255)、範囲外を黒(0)にする

他の色の範囲(参考):
# 緑 lower_green = np.array([40, 40, 40]) upper_green = np.array([80, 255, 255]) # 青 lower_blue = np.array([100, 40, 40]) upper_blue = np.array([140, 255, 255]) # 黄色 lower_yellow = np.array([20, 100, 100]) upper_yellow = np.array([30, 255, 255])

📝 STEP 2 のまとめ

✅ このステップで学んだこと

デジタル画像は、ピクセルの集合である
RGB:光の三原色(赤、緑、青)で色を表現
グレースケール:白〜黒の1チャンネルで表現
HSV:色相、彩度、明度で表現(色検出に便利)

PIL/Pillow:シンプル、初心者向け、RGB順序
OpenCV:高速、機能豊富、BGR順序(注意!)
matplotlib:可視化に便利、RGB順序

基本操作:リサイズ、クロップ、回転、反転
NumPy配列:画像はNumPy配列として扱われる
正規化:深層学習では必須の前処理

💡 重要ポイント

⚠️ OpenCVのBGR順序:
これは頻繁に混乱の原因になります。
読み込んだらすぐにcv2.cvtColor(img, cv2.COLOR_BGR2RGB)でRGBに変換する習慣をつけましょう。

📐 配列の順序:
NumPyは(高さ, 幅, チャンネル)の順番です。
画像ファイルの「640×480」は「幅×高さ」なので、混同しないように注意。

🎯 次のステップの準備

次のSTEP 3では、「OpenCVによる画像処理」を学びます。

学習内容:
・フィルタリング(ブラー、シャープニング)
・エッジ検出(Sobel、Canny)
・モルフォロジー変換(膨張、収縮)
・色検出とトラッキング

これらの古典的CV技術は、深層学習でも前処理として頻繁に使われます

📝

学習メモ

コンピュータビジョン(CV) - Step 2

📋 過去のメモ一覧
#artnasekai #学習メモ
LINE