AI生成画像を本物のドット絵に!Pythonで実装する減色・ディザリング変換
出典: Rafael Minguet Delgado / Pexels
こんにちは、ぴこぴこです!画像生成AI(FLUX.1やStable Diffusionなど)で「ピクセルアート(ドット絵)」風の画像を生成したことがある人は多いと思います。プロンプトに「pixel art」と指定すれば、それらしい雰囲気の画像はすぐに出てきます。
しかし、出力された画像を拡大してみると、細部がボケていたり、使われている色が数千色にのぼっていたりして、そのままインディーズゲームの素材として使うには「本物っぽさ」が足りないことに気づくはずです。
本物のレトロなドット絵にするためには、解像度の縮小だけでなく、限られた「カラーパレット」への減色と、中間の階調を表現するための「ディザリング」が不可欠です。今回は、Pythonを使ってAI生成画像を美しくドット絵化するスクリプトの実装方法を紹介します!
なぜ単なる「縮小」だけではダメなのか?
高解像度で生成されたイラストをニアレストネイバー(Nearest Neighbor)法で単純に $64 \times 64$ や $128 \times 128$ ピクセルに縮小しただけでは、以下の問題が生じます。
- アンチエイリアスの残留: 輪郭線に微妙に中間色が混ざり、ドット絵特有の「くっきり感」が失われる。
- 無秩序なグラデーション: 生成AIは微細なノイズを多く含むため、減色しないままだと滑らかな階調になってしまい、8bit/16bitゲーム機のような懐かしいレトロ感が薄れる。
そこで、特定のゲーム機や規格を模した限定カラーパレット(例: レトロゲーム開発環境 PICO-8 の16色パレットなど)に画素のカラーをマッピングし直す処理が必要になります。
Pythonでパレット変換を行うコード
Pythonの画像処理ライブラリ Pillow (PIL) を使うと、独自のパレットとディザリングを用いた画像変換を数行で実装できます。
以下のコードは、入力画像を任意の解像度にリサイズしたのち、PICO-8の16色パレット(または任意のカスタムパレット)に変換して保存するスクリプトです。
from PIL import Image
def convert_to_pixel_art(image_path, output_path, size=(128, 128)):
# 1. 画像を読み込む
img = Image.open(image_path)
# 2. ニアレストネイバーで解像度を落とす
img_small = img.resize(size, Image.Resampling.NEAREST)
# 3. PICO-8の16色カラーパレットデータを定義する (RGB値のフラットリスト)
pico8_palette = [
0, 0, 0, # 0: Black
29, 43, 83, # 1: Dark Blue
126, 37, 83, # 2: Dark Purple
0, 135, 81, # 3: Dark Green
171, 82, 54, # 4: Brown
95, 87, 79, # 5: Dark Gray
194, 195, 199, # 6: Light Gray
255, 241, 232, # 7: White
255, 0, 77, # 8: Red
255, 163, 0, # 9: Orange
255, 236, 39, # 10: Yellow
0, 228, 54, # 11: Green
41, 173, 255, # 12: Blue
131, 118, 156, # 13: Lavender
255, 119, 168, # 14: Pink
255, 204, 170 # 15: Light Peach
]
# パレットを256色(768値)にパディングする
pico8_palette += [0] * (768 - len(pico8_palette))
# 4. パレット画像オブジェクトを作成する
palette_img = Image.new('P', (1, 1))
palette_img.putpalette(pico8_palette)
# 5. 元画像をRGBモードにしてから、パレットとディザリング(Floyd-Steinberg)を適用して変換
img_rgb = img_small.convert('RGB')
pixel_art = img_rgb.quantize(palette=palette_img, dither=Image.Dither.FLOYDSTEINBERG)
# 6. 保存する(拡大してドットを際立たせるために、ニアレストネイバーで再拡大)
# ※ゲーム素材として使うなら、小さいサイズのまま保存してOKです
pixel_art_scaled = pixel_art.resize((size[0] * 4, size[1] * 4), Image.Resampling.NEAREST)
pixel_art_scaled.save(output_path)
# 実行例
convert_to_pixel_art("my_ai_image.png", "pixelated_output.png")
ディザリングの種類とその使い分け
Pillowの quantize メソッドでは、ディザリングの有無をコントロールできます。
- Floyd-Steinbergディザ(
Image.Dither.FLOYDSTEINBERG): 誤差拡散法を用いて、中間のグラデーション部分にドットの細かい網目を生成します。空や肌のグラデーションが驚くほど滑らかになりますが、ノイジーに見える場合もあります。 - ディザリングなし(
dither=Image.Dither.NONE): ベタ塗りのフラットな仕上がりになります。キャラクターの立ち絵や、アニメ調・ポップな雰囲気を出したいときには、ディザを切るほうがすっきりしたラインになります。
まとめ:AI生成画像と伝統的処理のコンビネーション
AIが生成した「ドット絵風イラスト」に、このような古典的なパレット制約を与えることで、ただリサイズしただけでは得られない「制限の美学」が生まれます。
独自のゲームを作る際は、ゲーム全体のパレットをあらかじめ定義しておき、AIに背景やキャラクターを出力させ、このスクリプトを通して統一感を出すのがおすすめです。レトロゲーム開発の素材づくりの効率が飛躍的にアップするので、ぜひ試してみてくださいね!
お役立ち情報
- 📄 PICO-8 Wiki - Palette (英語)
- レトロファンタジーコンソール「PICO-8」のカラーパレットに関する仕様とRGBカラーコードの公式情報。
- 📄 Pillow Documentation - Image.quantize (英語)
- PythonのPillowライブラリにおける、カラーインデックス画像への変換とパレット適用のためのAPI仕様書。
- 📄 Qiita - PythonとPillowで画像のドット絵化(日本語)
- Pillowの基本的なリサイズや画素アクセスを用いて、画像をモザイク風・ドット絵風に加工する手順をわかりやすく解説した日本語の入門記事。