Pythonで画像処理 (PIL, OpenCV)
目次
読み込み
OpenCVで画像を読み込むと、NumPyのndarray型のインスタンスが得られる。
PILで画像を読み込むと、PIL.Image型のインスタンスが得られる。
RGB画像
PASCAL VOC 2012から
PIL
from PIL import Image image = Image.open('image_rgb.jpg') print(type(image)) # -> <class 'PIL.JpegImagePlugin.JpegImageFile'> print(image.size) # -> (500, 375) print(image.mode) # -> RGB
OpenCV
OpenCVでは、画像を読み込んだときにBGRの順のndarrayが得られる。
PILでは非ASCII文字を含むパスの画像ファイルも開くことができるが、OpenCVでは非ASCII文字を含むパスを開こうとするとエラーが発生するので注意が必要。
import cv2 image = cv2.imread('image_rgb.jpg') print(type(image)) # -> <class 'numpy.ndarray'> print(image.shape) # -> (375, 500, 3)
相互変換
image_cv = np.array(image_pil) # PIL -> NumPy(OpenCV) image_cv = cv2.cvtColor(image_cv, cv2.COLOR_RGB2BGR) image_pil = cv2.cvtColor(image_cv, cv2.COLOR_BGR2RGB) image_pil = Image.fromarray(image_pil) # NumPy(OpenCV) -> PIL
グレースケール画像
PIL
from PIL import Image image = Image.open('image_l.png') print(type(image)) # -> <class 'PIL.PngImagePlugin.PngImageFile'> print(image.size) # -> (500, 375) print(image.mode) # -> L
OpenCV
import cv2 image = cv2.imread('image_l.png', cv2.IMREAD_GRAYSCALE) print(type(image)) # -> <class 'numpy.ndarray'> print(image.shape) # -> (375, 500)
相互変換
image_cv = np.array(image_pil) # PIL -> OpenCV(NumPy) image_pil = Image.fromarray(image_cv) # OpenCV(NumPy) -> PIL
インデックスカラー画像
PIL
from PIL import Image image = Image.open('image_p.png') print(type(image)) # -> <class 'PIL.PngImagePlugin.PngImageFile'> print(image.size) # -> (500, 375) print(image.mode) # -> P print(image.getpalette()) # -> [0, 0, 0, 128, 0, 0, 0, 128, 0, 128, 128, 0, ... ]
OpenCV
OpenCVでインデックスカラー画像のインデックスを直接読み込むことはできない。
(パレット情報が各ピクセルに展開されて、3チャンネルのカラー画像として読み込まれる)
相互変換
from PIL import Image image_pil = Image.open('image_p.png') palette = image_pil.getpalette() # パレットを保持(別途定義する場合はこの行は不要) image_cv = np.array(image_pil) # PIL -> NumPy(OpenCV) image_pil = Image.fromarray(image_cv, mode='P') # NumPy(OpenCV) -> PIL image_pil.putpalette(palette) # パレット情報を付与
保存
PIL
画像のmodeに応じた形式で保存される
image.save('output.png')
グレースケール画像(1チャンネル)をインデックスカラー画像として保存する場合
image = Image.fromarray(image, mode='P') # NumPy -> PIL image.putpalette(palette) # 長さ768の配列paletteを与える image.save('output.png')
OpenCV
3チャンネルならカラー画像として、1チャンネルならグレースケール画像として保存される。
cv2.imwrite('output.png', image)
画像変換
データ拡張に使う主な変換が、PIL・OpenCVでどのように実装されているか紹介する。
リサイズ
new_w, new_h = 500, 150 # PIL pil_image = pil_image.resize((new_w, new_h)) # 指定しなければNEAREST pil_image = pil_image.resize((new_w, new_h), Image.BILINEAR) # OpenCV cv_image = cv2.resize(cv_image, (new_w, new_h), interpolation=cv2.INTER_NEAREST) cv_image = cv2.resize(cv_image, (new_w, new_h)) # 指定しなければINTER_LINEAR(バイリニア)
回転
expand=Trueの場合
angle = 10 fillcolor = (124, 115, 104) # 回転によって生じた隙間を埋める色を指定する(指定しなければ(0, 0, 0)で埋められる) # PIL pil_image = pil_image.rotate(angle, resample=Image.BILINEAR, fillcolor=fillcolor) # expand=0(デフォルト)でOpenCVと同じ動作 pil_image = pil_image.rotate(angle, expand=True, resample=Image.BILINEAR, fillcolor=fillcolor) # expand=Trueにすると回転画像全体を覆うサイズで出力される # OpenCV h, w, _ = cv_image.shape matrix = cv2.getRotationMatrix2D((w/2, h/2), angle, 1) cv_image = cv2.warpAffine(cv_image, matrix, (w, h), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT, borderValue=fillcolor[::-1])
左右反転
# PIL from PIL import ImageOps pil_image = ImageOps.mirror(pil_image) # OpenCV cv_image = cv2.flip(cv_image, 1)
ぼかし
sigma = 3 # PIL from PIL import ImageFilter pil_image = pil_image.filter(ImageFilter.GaussianBlur(sigma)) # 標準偏差σを指定 # OpenCV cv_image = cv2.GaussianBlur(cv_image, (15, 15), sigma) # 半径と標準偏差σを指定
Padding
fillcolor = (124, 115, 104) border_pil = (10, 20, 10, 40) # 左上右下の順 border_cv = (20, 40, 10, 10) # 上下左右の順 # PIL from PIL import ImageOps pil_image = ImageOps.expand(pil_image, border=border_pil, fill=fillcolor) # OpenCV cv_image = cv2.copyMakeBorder(cv_image, *border_cv, borderType=cv2.BORDER_CONSTANT, value=fillcolor[::-1])
切り取り
offset_y = 100 offset_x = 150 crop_h = 100 crop_w = 300 # PIL pil_image = pil_image.crop((offset_x, offset_y, offset_x + crop_w, offset_y + crop_h)) # OpenCV cv_image = cv_image[offset_y:offset_y + crop_h, offset_x:offset_x + crop_w]