import cv2 import numpy as np # 画像を読み込む bmpOrg = cv2.imread('test.png') # イメージのサイズを取得してwidth,heightに代入する width = bmpOrg.shape[0] height = bmpOrg.shape[1] # bmpOrgからグレースケールの配列 bmpFrom = np.zeros((width+1)*(height+1)).astype(np.uint8).reshape(width+1,height+1) # bmpOrgはRGBで記録されているのでこれをグレースケールにした上でBmpFromに配置する # この時問題文は1スタート(NOT 0スタート)なので1つずつずらす for y in range(0,height): for x in range(0,width): bmpFrom[x+1][y+1] = int( np.average( bmpOrg[x][y] )) # 書き出し先用の配列(bmpTo)を作成する。bmpFromと違い、負の数があるのでint16型を使用する。 bmpTo = np.zeros((width+1)*(height+1)).astype(np.int16).reshape(width+1,height+1) # 誤差拡散の定義をする tdx = [ 1,-1, 0, 1] tdy = [ 0, 1, 1, 1] raito = [ 7, 3, 5, 1] raitoCount = 4 denominator = 16 # 動作モード # 0以外の数字に設定すると画質向上のための改修をしたバージョンで動作する mode = 1 # ドットごとに評価してbmoToに代入、更に誤差を計算して周辺のドットに反映させる # この時に周辺のドットも一緒に評価する for y in range(1,height+1): for tx in range(1,width+1): x = tx # 改修版の場合はここで動作を変える if( mode != 0): # 偶数行は逆から処理する if( y%2 == 0 ): x = width - tx +1 # From+To(現時点での誤差のSum) f = bmpFrom[x][y] + bmpTo[x][y] # 2値化と誤差Dを計算する if( f >= 128 ): d = f - 255 bmpTo[x][y] = 255 else: d = f bmpTo[x][y] = 0 # 誤差Dから周辺のドットに拡散させる(方式1) for c in list(range(raitoCount)): # change position if( mode == 0 ): px = x + tdx[c] else: px = x - tdx[c] + ( 2 * tdx[c] * (y%2) ) py = y + tdy[c] if( px>=1 and px<=width and py>=1 and py<=height ): bmpTo[px][py] = bmpTo[px][py] + ( d * raito[c] / denominator ) #print(bmpTo) # 処理はグレースケールで計算していたので、これをRGBに変換する # この際に問題文に合わせてx,yをそれぞれ+1した物を戻してやる # typeはuint8(8ビット符号なし) bmpToRGB = np.zeros(width*height*3).astype(np.uint8).reshape(width,height,3) for y in range(0,height): for x in range(0,width): tmp = bmpTo[x+1][y+1] bmpToRGB[x][y] = [ tmp, tmp, tmp ] # 画像を表示する WindowTitle = "Mode="+str(mode) cv2.imshow(WindowTitle,bmpToRGB) cv2.waitKey(0) cv2.destroyAllWindows()