NumPyのarrayとPILの変換
Python Imaging LibraryのImageクラスのデータをNumpyのarrayとして扱うための方法について。
Numpyの関数を使って直接pixel値を書き換えることが目標です。
まずは両方のライブラリをインポートしておきます。
import numpy import Image
PILからNumpyのarrayへの変換
numpyで用意されているasarray関数を使うと、PILのImageオブジェクトを配列に変換することができます。
imgArray = numpy.asarray(pilImg)
さらに配列の値を書き変えられるようにするためには、writeableフラグをTrueにする必要があるようです。
imgArray.flags.writeable = True
NumpyのarrayからPILへの変換
PILのfromarrayメソッドによって、配列の各値を1byte整数型(0〜255)として画像のpixel値に変換することができます。
pilImg = Image.fromarray(numpy.uint8(imgArray))
RGBモードの画像処理
3×4pixのRGB画像を読み込んだ配列を表示させると下のように値が格納されています。
import numpy import Image pilIN = Image.open("small.bmp") imgArray = numpy.asarray(pilIN) print imgArray
1pixの情報が[R,G,B]というリストで与えられていて、それが列方向に3,行方向に4だけ格納されていることがわかります。
[ [ [100 161 217] ←[0][0]
[104 163 218] ←[0][1]
[114 169 221] ←[0][2]
[105 164 218] ] ←[0][3][ [169 203 234] ←[1][0]
[160 197 231] ←[1][1]
[117 171 220] ←[1][2]
[167 201 233] ] ←[1][3][ [124 175 221] ←[2][0]
[158 195 230] ←[2][1]
[ 80 147 209] ←[2][2]
[158 195 230] ] ] ←[2][3]
この情報を扱うには、サイズを取得してfor文の中で[列][行][色]のようにアクセスすると良いです。
下の例は入力画像をネガ変換(RGB全てのモードで反転)して、PIL画像に戻して表示した例です。
import numpy import Image pilIN = Image.open("small.bmp") imgArray = numpy.asarray(pilIN) #PILToNumpy maxcol , maxrow = pilIN.size #get size imgArray.flags.writeable = True for i in range(maxrow): for j in range(maxcol): imgArray[i,j][0] = 255-imgArray[i,j][0] #R imgArray[i,j][1] = 255-imgArray[i,j][1] #G imgArray[i,j][2] = 255-imgArray[i,j][2] #B pilOUT = Image.fromarray(numpy.uint8(imgArray)) #NumpyToPIL pilOUT.show()
RGBAモードの画像処理
RGBAモードでは透過情報が含まれているため、1pixelに4つの情報が保存されていることになります。
3×4pixのRGBA画像を読み込み、その配列を表示させると下のように[R,G,B,A]という4つの値が格納されていることが分かります。
import numpy import Image pilIN = Image.open("small.bmp").convert("RGBA")#RGBAに変換 imgArray = numpy.asarray(pilIN) print imgArray
RGBAの値にアクセスするには次のようにそれぞれのリストの値を取得するとよいでしょう。添え字を指定するには[i][j][k],[i,j][k],[i,j,k]などいくつかの書き方があります。
[ [ [100 161 217 255]
[104 163 218 255]
[114 169 221 255]
[105 164 218 255] ][ [169 203 234 255]
[160 197 231 255]
[117 171 220 255]
[167 201 233 255] ][ [124 175 221 255]
[158 195 230 255]
[ 80 147 209 255]
[158 195 230 255] ] ]
imgArray[i,j][0] #or imgArray[i,j,0] #R imgArray[i,j][1] #or imgArray[i,j,1] #G imgArray[i,j][2] #or imgArray[i,j,2] #B imgArray[i,j][3] #or imgArray[i,j,3] #A
グレースケール画像処理
3×4pixのグレースケール画像を配列として表示させると下のようになります。
import numpy import Image pilIN = Image.open("small.bmp").convert("L")#グレースケールに変換 imgArray = numpy.asarray(pilIN) print imgArray
この場合は直に[列][行]としてアクセスすれば値を書き換えられます。
[ [149 151 158 152]
[196 189 160 194]
[164 187 134 187] ]
グレースケール画像に対して50を閾値として2値化を行うコードです。
import numpy import Image pilIN = Image.open("small.bmp").convert("L") imgArray = numpy.asarray(pilIN) print imgArray maxcol , maxrow = pilIN.size imgArray.flags.writeable = True for i in range(maxrow): for j in range(maxcol): if(imgArray[i,j] > 50): imgArray[i,j] = 1 else: imgArray[i,j] = 0 pilOUT = Image.fromarray(numpy.uint8(imgArray)) pilOUT.show()
2値画像
2値画像の場合はbool型で値が格納されています。numpyではbool型はnumpy.bool8として定義されています。
下の例は一度配列に変換して戻した画像を、もう一度配列に直して出力したものです。
import numpy import Image pilIN = Image.open("small.bmp").convert("1") imgArray = numpy.asarray(pilIN,numpy.bool8) print imgArray pilOUT = Image.fromarray(numpy.uint8(imgArray)) imgArray2 = numpy.asarray(pilOUT,numpy.bool8) print imgArray2
配列に読み込む際には読み込みモードとしてbool8を指定します。画像に変換する場合はfromarrayでuint8を指定するとうまくいくみたいです。
[ [ True True True False]
[ True True True True]
[ True True True True] ][ [ True True True False]
[ True True True True]
[ True True True True] ]