第1章

デジタル画像の基礎

Digital Image Fundamentals

デジタル画像とは

デジタル画像は、2次元の格子状に配置されたピクセル(画素)の集合である。各ピクセルは位置 $(x, y)$ と輝度値(または色値)を持つ。

I(x,y) x y (0,0) 画像の表現 • 幅 W × 高さ H ピクセル • 各ピクセル: I(x, y) • 原点: 左上 (0, 0) • x: 右方向、y: 下方向 グレースケール: I(x,y) ∈ [0, 255] 0 = 黒、255 = 白
図1. ピクセル座標と画像の格子構造

y 軸が下向きである理由

数学の座標系では原点が左下にあり y 軸は上向きだが、画像処理では原点が左上にあり y 軸は下向きである。 これはCRTディスプレイの時代に、電子ビームが画面の左上から右へ、上から下へとラスタ走査(raster scan)していたことに由来する。 メモリ上でも画像データは左上のピクセルから順に格納されるため、行番号が増えるほど画面の下方に対応する。 この慣習は現在のすべての画像フォーマット、ディスプレイ、画像処理ライブラリ(OpenCV, PIL など)に引き継がれている。

解像度とビット深度

解像度(Resolution)

画像のピクセル数を表す。$W \times H$ で表記され、例えば 1920×1080 は約200万画素。 テレビやディスプレイの「4K」「8K」も水平方向の画素数に由来する呼称で、4K は 3840×2160(約830万画素)、8K は 7680×4320(約3300万画素)である。

※ 民生用テレビやディスプレイでは「4K UHD」(3840×2160) が標準で、映画業界の「DCI 4K」(4096×2160) とは異なる。

ビット深度(Bit Depth)

各ピクセルの輝度値を表現するビット数:

  • 1ビット: 2値画像(白黒)
  • 8ビット: 256階調(0〜255)。$n$ ビットでは $0$ から $2^n - 1$ の範囲
  • 16ビット: 65536階調
  • 24ビット: RGB各8ビット(フルカラー)
1ビット 2階調 4ビット 16階調 8ビット 256階調 24ビット 約1677万色 階調数 = 2^n (n: ビット数) 8ビットグレースケール: I(x, y) ∈ {0, 1, ..., 255} 24ビットカラー: R, G, B 各8ビット → 2^24 ≈ 1677万色
図2. ビット深度と階調数の比較

チャンネル数

チャンネル数(Number of Channels)

各ピクセルが持つ値の個数を表す。

チャンネル数 名称 各ピクセルの値 用途
1 グレースケール 輝度値 1 個 白黒写真、医療画像、エッジ検出の前処理
3 カラー(RGB) 赤・緑・青の 3 個 一般的なカラー画像
4 RGBA 赤・緑・青・透明度の 4 個 PNG、アイコン、UIデザイン

チャンネル数が増えるほど 1 ピクセルあたりのデータ量が増える。 画像処理では、カラー画像をグレースケールに変換して 1 チャンネルにすることで計算量を削減する手法がよく使われる。

画像のメモリサイズ

画像のデータサイズは以下で計算できる:

$$\text{サイズ (bytes)} = W \times H \times \frac{\text{ビット深度}}{8} \times \text{チャンネル数}$$

例: 1920×1080のフルHD画像

  • グレースケール(8bit): $1920 \times 1080 \times 1 = 2,073,600$ bytes ≈ 2MB
  • カラー(24bit RGB): $1920 \times 1080 \times 3 = 6,220,800$ bytes ≈ 6MB

画像の数学的表現

画像は数学的に以下のように表現される:

グレースケール画像

行列 $\mathbf{I} \in \mathbb{R}^{H \times W}$ として表現される。各成分 $I(x,y)$ がピクセルの輝度値である。

$$\mathbf{I} = \begin{pmatrix} I(0,0) & I(1,0) & \cdots & I(W-1,0) \\ I(0,1) & I(1,1) & \cdots & I(W-1,1) \\ \vdots & \vdots & \ddots & \vdots \\ I(0,H-1) & I(1,H-1) & \cdots & I(W-1,H-1) \end{pmatrix}$$

※ ここでは数学的な慣例に従い $I(x, y)$ の順序で書いているが、NumPy/OpenCV では img[y, x](行, 列)の順序でアクセスする。

カラー画像

3次元テンソル $\mathbf{I} \in \mathbb{R}^{H \times W \times C}$(C: チャンネル数、通常3)

$$I(x, y) = \begin{pmatrix} R(x,y) \\ G(x,y) \\ B(x,y) \end{pmatrix}$$
グレースケール H × W × 1ch グレースケール カラー(RGB) H × W × 3ch B G R ※ 透明度を含む場合は RGBA(4ch)
図3. グレースケールとカラー画像のデータ構造

OpenCV はなぜ BGR 順序なのか

一般的な画像形式(PNG, JPEG など)は RGB 順序だが、OpenCV は BGR 順序を採用している。 これは技術的な合理性ではなく、歴史的な経緯による。 OpenCV は1999年に Intel が開発を開始したが、当時 Windows で主流だったカメラ API(Video for Windows)やビットマップ形式(BMP/DIB)が BGR 順序でデータを返していたため、それに合わせた。 Windows の BMP が BGR なのは、Intel x86 のリトルエンディアンでメモリに 32bit RGBA を格納すると B, G, R, A の順になることに由来する。 OpenCV がクロスプラットフォーム化した後も、既存コードとの互換性のために BGR のまま維持されている。

OpenCV で読み込んだ画像を他のライブラリ(PIL, matplotlib など)で表示する際は cv2.cvtColor(img, cv2.COLOR_BGR2RGB) で変換が必要である。

コード例(Python)

import numpy as np
import cv2

# 画像の読み込み
img_color = cv2.imread('image.jpg')        # カラー (H, W, 3)
img_gray = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)  # グレースケール (H, W)

# 画像のプロパティ
print(f"Shape: {img_color.shape}")         # (高さ, 幅, チャンネル数)
print(f"Dtype: {img_color.dtype}")         # uint8 (0-255)
print(f"Size: {img_color.size} bytes")     # 総バイト数

# ピクセルへのアクセス
pixel = img_color[100, 200]                # (B, G, R) の値
gray_value = img_gray[100, 200]            # 輝度値

# 新しい画像の作成
blank = np.zeros((480, 640, 3), dtype=np.uint8)  # 黒画像
white = np.ones((480, 640), dtype=np.uint8) * 255  # 白画像

まとめ

  • デジタル画像はピクセルの2次元配列
  • 解像度は画像のピクセル数、ビット深度は階調数を決める
  • グレースケールは2次元行列、カラーは3次元テンソル
  • 画像処理では行列演算が基本となる