note.nkmk.me

Python, OpenCVで画像にモザイク処理(全面、一部、顔など)

Date: 2018-02-28 / Modified: 2018-09-02 / tags: Python, OpenCV, 画像処理

Python, OpenCVを使って画像にモザイク処理を行う。

  • 画像全体にモザイク処理
  • 画像の一部をモザイク処理
  • 顔検出して顔部分にモザイク処理
  • 徐々にモザイクがかかるGIFアニメ作成

についてサンプルコードとともに説明する。

スポンサーリンク

画像全体にモザイク処理

モザイク処理といっても複雑なアルゴリズムは必要なく、画像を一旦縮小してから拡大して元のサイズに戻すだけでOK。

以下のように実現できる。

import cv2

src = cv2.imread('data/src/lena.jpg')

def mosaic(src, ratio=0.1):
    small = cv2.resize(src, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
    return cv2.resize(small, src.shape[:2][::-1], interpolation=cv2.INTER_NEAREST)

dst_01 = mosaic(src)
cv2.imwrite('data/dst/opencv_mosaic_01.jpg', dst_01)

dst_005 = mosaic(src, ratio=0.05)
cv2.imwrite('data/dst/opencv_mosaic_005.jpg', dst_005)

画像を縮小する際のcv2.resize()では、第二引数に縮小後のサイズを指定するのではなく、倍率を指定する引数fx, fyを使っている。第二引数は省略できないのでNoneを渡している。

拡大する際は第二引数に元の画像のサイズを渡す。

OpenCVの画像のサイズはshape(NumPy配列ndarrayの属性)で(高さ, 幅[, 色数])のかたちで取得できるが、cv2.resize()の引数に渡すときは(幅、高さ)である必要があるのでスライスを利用して変換している。

詳細は以下の記事を参照。

また、引数interpolationでニアレストネイバー法cv2.INTER_NEARESTを指定して、滑らかにリサイズしないようにしている。

結果は以下の通り。縮小率ratioによってモザイクの粗さを制御できる。

ratio=0.1の場合。

Python OpenCV mosaic 1

ratio=0.05の場合。

Python OpenCV mosaic 2

画像の一部をモザイク処理

画像の一部だけにモザイクをかけたい場合は、スライスで領域を指定してその領域に上述のモザイク処理の関数を適用すればよい。

例ではモザイク領域の左上の点の座標と領域の幅と高さを指定するようにしている。

def mosaic_area(src, x, y, width, height, ratio=0.1):
    dst = src.copy()
    dst[y:y + height, x:x + width] = mosaic(dst[y:y + height, x:x + width], ratio)
    return dst

dst_area = mosaic_area(src, 100, 50, 100, 150)
cv2.imwrite('data/dst/opencv_mosaic_area.jpg', dst_area)

結果は以下の通り。

Python OpenCV mosaic area

顔検出して顔部分にモザイク処理

画像の一部領域にモザイク処理ができれば、顔検出と組み合わせて顔にモザイクをかけるのも簡単。

face_cascade_path = '/usr/local/opt/opencv/share/'\
                    'OpenCV/haarcascades/haarcascade_frontalface_default.xml'
face_cascade = cv2.CascadeClassifier(face_cascade_path)

src_gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)

faces = face_cascade.detectMultiScale(src_gray)

for x, y, w, h in faces:
    dst_face = mosaic_area(src, x, y, w, h)

cv2.imwrite('data/dst/opencv_mosaic_face.jpg', dst_face)

Python OpenCV mosaic face

顔検出については以下の記事を参照。

徐々にモザイクがかかるGIFアニメ作成

画像処理ライブラリPillowを使うと複数の静止画からアニメーションGIF画像を作成できる。

モザイクの粗さを徐々に変化させた静止画のリストを生成し、GIFとして保存するサンプルコードは以下の通り。

import cv2
from PIL import Image

def mosaic(src, ratio=0.1):
    small = cv2.resize(src, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
    return cv2.resize(small, src.shape[:2][::-1], interpolation=cv2.INTER_NEAREST)

src = cv2.cvtColor(cv2.imread('data/src/lena.jpg'), cv2.COLOR_BGR2RGB)

imgs = [Image.fromarray(mosaic(src, 1 / i)) for i in range(1, 25)]
imgs += imgs[-2::-1] + [Image.fromarray(src)] * 5

imgs[0].save('data/temp/opencv_mosaic.gif',
             save_all=True, append_images=imgs[1:], optimize=False, duration=50, loop=0)

OpenCVで読み込んだ画像はBGRの並びで、Pillowで保存するにはRGBの並びにする必要があるので注意。

画像のリストの作成にはリスト内包表記を使っている。自分で定義した関数mosaic()の結果をImage.fromarray()でNumPy配列ndarrayからPillow(PIL)のImageに変換してリスト化。

負数を使ったスライスで逆順のリストを作成し連結してエンドレスループするようにしている。-2からスタートしているのは最終画像が2枚連続するのを防ぐため。さらに、モザイク無し画像を複数枚追加し、モザイクのない状態の間隔を長くしている。

結果は以下の通り。

OpenCV Pillow mosaic animation gif

スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事