デジタル画像の基礎

Digital Image Fundamentals

デジタル画像とは

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

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

y 軸が下向きである理由

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

解像度とビット深度

解像度(Resolution)

ここでは画像のピクセル数(画素寸法)を表す(印刷やディスプレイでは、1インチあたりの画素数 dpi/ppi を解像度と呼ぶこともある)。$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 つのチャンネル(1 つの値)を表現するビット数。1 画素あたりのビット数は、これにチャンネル数を掛けたものになる:

  • 1ビット: 2値画像(白黒)
  • 8ビット: 256階調(0〜255)。$n$ ビットでは $0$ から $2^n - 1$ の範囲
  • 16ビット: 65536階調
  • 24ビット(1画素あたり): RGB 各8ビット × 3 チャンネル(フルカラー)
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 チャンネルにすることで計算量を削減する手法がよく使われる。 具体的な変換式(ガンマ補正済みの RGB に対する ITU-R BT.601 の係数による $Y = 0.299R + 0.587G + 0.114B$ など)は 「色空間」で扱う。

画像のメモリサイズ

非圧縮の画素配列としてメモリ上に置いたときのデータサイズは、以下で計算できる(JPEG や PNG のファイルは圧縮されるので、ファイルの大きさとは異なる):

$$\text{サイズ (bytes)} = W \times H \times \frac{\text{1チャンネルあたりのビット深度}}{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}$ として表現される。行 $y$・列 $x$ の成分が、ピクセル $(x, y)$ の輝度値 $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 R G B ※ 透明度を含む場合は RGBA(4ch)
図3. グレースケールとカラー画像のデータ構造

OpenCV はなぜ BGR 順序なのか

多くの画像ライブラリ(PIL, matplotlib など)はカラー画像を RGB 順の配列で扱うが、OpenCV の imread は BGR 順の配列を返す。 これは技術的な合理性ではなく、歴史的な経緯による。 OpenCV は1999年に Intel が開発を開始したが、当時 Windows で主流だったカメラ API(Video for Windows)やビットマップ形式(BMP/DIB)が BGR 順序でデータを返していたため、それに合わせたとされる。 Windows の BMP が BGR なのは、画素を 0xAARRGGBB(上位から A, R, G, B)の 32 ビット整数として扱い、リトルエンディアンの Intel x86 でメモリに置くと 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.nbytes} bytes")   # 総バイト数(.size は要素数。uint8 なら同じ値)

# ピクセルへのアクセス
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次元配列
  • 解像度は画像のピクセル数、1チャンネルあたりのビット深度は各チャンネルの階調数を決める
  • グレースケールは2次元行列、カラーは3次元テンソル
  • 画像処理では行列演算が基本となる

よくある質問

デジタル画像の y 軸はなぜ下向きなのか

CRT ディスプレイの時代に、電子ビームが画面の左上から右へ、上から下へとラスタ走査していたことに由来する。メモリ上でも画像データは左上のピクセルから順に格納されることが多いため、行番号が増えるほど画面の下方に対応する。この慣習は OpenCV や PIL など多くの画像処理ライブラリに引き継がれているが、BMP は既定で下の行から画素を格納し、OpenGL のテクスチャ座標は原点が左下であるなど、例外もある。

OpenCV はなぜ BGR 順序なのか

OpenCV は1999年に Intel で開発が始まり、当時の Windows のカメラ API や BMP 形式が BGR 順序でデータを扱っていたため、それに合わせたとされる。BMP の BGR は、画素を 0xAARRGGBB の 32 ビット整数として扱い、リトルエンディアンの x86 でメモリに置くと B, G, R, A の順になることに由来するとされる。互換性のため、現在も BGR のまま維持されている。