【Python】画像外の領域を含むクロップ処理【OpenCV, Pillow】

OpenCV

PythonのOpenCVで画像処理をしているときに、画像の一部分をクロップしたいことがあるかと思います。

しかし、以下の図のようにクロップしたい領域が画像領域外を含む場合、OpenCVで実装するのは難しいです。

本記事では、上記のような画像外の領域を含むクロップの実装例について紹介します。

実装例

画像領域外を含むクロップはPillowを使用すると比較的簡単に実装できます。

ですので、ndarray(OpenCV)をPillowで扱える形に変換し、クロップした後にまたndarrayに変換してあげることで、画像領域外を含むクロップができます。

以下が実装例です。

import cv2
import numpy as np
from PIL import Image

if __name__ == '__main__':
    img = cv2.imread("test.jpg")

    # Pillow型への変換
    pil_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    pil_img = Image.fromarray(pil_img)

    crop_img = pil_img.crop((120, -100, 1190, 950))

    # OpenCVで使用可能なnumpy型への変換
    cv_crop_img = np.array(crop_img, dtype=np.uint8)
    cv_crop_img = cv2.cvtColor(cv_crop_img, cv2.COLOR_RGB2BGR)

    cv2.imshow("crop", cv_crop_img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

ndarrayではBGR、PillowではRGBで画像を扱うので、その変換を忘れないでください。(9行目と16行目)

また、Pillowでクロップした場合は領域外のピクセルは0埋めされて黒になります。

以下の画像が領域外を指定してクロップした例です。

画像領域外を黒以外にしたい場合

画像外の領域を0以外の値で埋めたい場合はnp.whereを使うことで実現できます。np.whereを使用した後はデータをuint8型に戻してあげましょう。

    black = [0, 0, 0]
    change_color = [255, 0, 0]

    cv_crop_img = np.where(cv_crop_img == black, change_color, cv_crop_img)
    cv_crop_img = np.array(cv_crop_img, dtype=np.uint8)

しかし、上記処理では画像領域内のblackもchange_colorに変換されてしまいます。(下図参照)

これを回避するには、クロップする前に画像内のblackを適当な色に変換し、クロップ後に元に戻してあげます。

    img = cv2.imread("test.jpg")

    black = [0, 0, 0]
    tmp_color = [12, 34, 56]
    change_color = [255, 0, 0]

    # 画像内のblackを適当な色(tmp_color)に変換
    img = np.where(img == black, tmp_color, img)
    img = np.array(img, dtype=np.uint8)
    
    ### ~~~~~~~~~~~~~~~~~
    ### クロップ処理は省略
    ### ~~~~~~~~~~~~~~~~~
    
    # 領域外のblackをchange_colorに変換
    cv_crop_img = np.where(cv_crop_img == black, change_color, cv_crop_img)
    # tmp_colorをblackに戻す
    cv_crop_img = np.where(cv_crop_img == tmp_color, black, cv_crop_img)
    cv_crop_img = np.array(cv_crop_img, dtype=np.uint8)

上記コードによって、以下の画像のように黒部分を変換できました。tmp_colorの値を適切に設定しないとうまくいかないので注意してください。

本記事で紹介したサンプルコードは以下で公開していますので、参考にしてみてください。https://github.com/kengo519/materials/blob/main/cropping-outside-area/cropping-outside-area.py

コメント

タイトルとURLをコピーしました