# 誤差拡散の偏りを減らす。 import numpy as np from PIL import Image def error_diffusion_optimized(input_path, output_path): # 1. 画像の読み込み(グレースケール変換) img = Image.open(input_path).convert('L') width, height = img.size # bmpFrom: 変換前の輝度 bmpFrom = np.array(img, dtype=np.int32) # bmpTo: 誤差蓄積用配列 bmpTo = np.zeros((height, width), dtype=np.int32) # 基本の誤差拡散パターン tdx = [1, -1, 0, 1] tdy = [0, 1, 1, 1] ratio = [7, 3, 5, 1] denominator = 16 # Y座標ループ(y+1が問題文のyに相当) for y_idx in range(height): y = y_idx + 1 # 問題文の1〜heightに合わせる # X方向のループ処理 for tx in range(1, width + 1): # [エ][オ][カ] 図6の処理を反映 x = tx is_even_row = (y % 2 == 0) if is_even_row: x = width - tx + 1 # Pythonのインデックス用に変換 curr_x, curr_y = x - 1, y - 1 # [ア] 手順3 f = bmpFrom[curr_y, curr_x] + bmpTo[curr_y, curr_x] # [イ] 手順4 if f >= 128: pixel_val = 255 d = f - 255 else: pixel_val = 0 d = f bmpTo[curr_y, curr_x] = pixel_val # 手順5: 誤差dの拡散 for c in range(4): # [エ][オ] 図7の処理を反映(偶数行ならX方向の拡散を左右反転) # x座標のオフセット計算: y%2が0(偶数)なら反転 dx = tdx[c] + (2 * tdx[c] * (y % 2 == 0)) # 図7のロジック # ※図7の式「tdx[c] + (2 * tdx[c] * (y mod 2))」は # 本文の「yが偶数なら左右逆」を数式化したものですが、 # 実装上は simple に「偶数行なら dx を反転させる」処理にします。 actual_dx = -tdx[c] if is_even_row else tdx[c] px = x + actual_dx py = y + tdy[c] # [キ][ク] 図5の③: クリッピング if 1 <= px <= width and 1 <= py <= height: # [ウ] 誤差の加算 err_share = (d * ratio[c]) // denominator bmpTo[py-1, px-1] += err_share # 画像として保存 result_img = Image.fromarray(bmpTo.astype(np.uint8)) result_img.save(output_path) print(f"蛇行スキャンによる変換が完了しました: {output_path}") # 実行 input_file = '/content/drive/MyDrive/Colab Notebooks/1_AP_programing/parakeet.png' output_file = '/content/drive/MyDrive/Colab Notebooks/1_AP_programing/parakeet_result2.png' error_diffusion_optimized(input_file, output_file)