JPEGの色数の上限は?

【要約】JPEGの最大色数は1677万ではなく400万くらいのようだ。未確認だが、MPEG-4なども同様だろう。

「JPEGは最大65536色表せる」という間違った説明があって、2563 ≒ 1677万色の間違いだろうととっさに思ったが、JPEGは一般にRGB→YCbCr→RGBと色空間を変換するため、1677万色全部をカバーするとは言えない。それなら何色くらい表せるのか。

JPEGは8×8ブロック単位でDCT変換を行うので、8×8ブロックを256×256含む2048×2048の画像を256枚作れば、ブロック単位ですべての色のパターンが尽くせる。これをいったん保存してから読み出し、何通りの色が使われていたかを調べる。GPT-4に手伝ってもらって、次のようなプログラムを作った。

import numpy as np
from PIL import Image

ary = np.zeros((2048, 2048, 3), dtype=np.uint8)
flg = np.zeros((256, 256, 256), dtype=np.uint8)

for k in range(256):
    for i in range(256):
        for j in range(256):
            ary[8*i:8*i+8, 8*j:8*j+8] = [i, j, k]
    img = Image.fromarray(ary)
    img.save("image.jpg", "JPEG", quality=100)
    img2 = Image.open("image.jpg")
    img2 = img2.convert('RGB')
    width, height = img2.size
    for x in range(width):
        for y in range(height):
            r, g, b = img2.getpixel((x, y))
            flg[r, g, b] = 1

print(np.sum(flg)) # 4006938

この実験では400万通りほどの色が再現された。1677万色の24%ほどである。22ビットくらいの情報量だ。

パターンを変えると色数は変わるが、上限は400万よりそんなに大きくならないようだ。

だいたいの分布を見てみる:

for k in range(16):
    print()
    print(k)
    for i in range(16):
        for j in range(16):
            s = np.sum(flg[16*k:16*k+16, 16*i:16*i+16, 16*j:16*j+16])
            print(f"{s:5d}", end="")
        print()

特にどの色域が手薄ということはなく、ほぼまんべんなく1/4くらいの色が再現されるという感じのようだ。

未確認だが、同様なDCTを使っているMPEG-4などの動画もおそらく同じであろう。

[追記] WebP形式で同じことをやってみたら、約267万色(2671414色)であった。HEICはPILが対応していないようだ。