5
4

More than 3 years have passed since last update.

画像に様々な形のモザイクをかける(Python, OpenCV)

Last updated at Posted at 2020-02-03

画像の好きな場所にモザイクをかける(Python, OpenCV)

はじめに

サーバーレスWebアプリ Mosaicを開発して得た知見を振り返り定着させるためのハンズオン記事セットとは別記事にしてますが、画像にモザイクをかける実装についてです。

最初、検出できるのは顔だけだったのですが、この記事でも書きましたが、文言も検出できるようにしまして。
モザイク処理、顔だけの時は検出領域が長方形といいますか画像に対して並行だったのですが、文言の場合は検出領域が斜めってたりしてまして。

長方形ではない、斜めってる領域に対して(多角形もイケるかと)モザイクをかけるという実装をしましたので、忘れないうちに備忘録として記事を書いておきます。

やりたいこと

これがオリジナル画像。
photo-1484608856193-968d2be4080e.jpeg
この画像の、顔と「LIFEGUARD」という文字にモザイクをかけたい。
faces-photo-1484608856193-968d2be4080e.jpeg
検出結果はこんな感じ。顔は画像に対して並行だけど、文字は斜めってる。
photo-1484608856193-968d2be4080e-200203132846-458d11b515.jpeg
こんな感じのモザイク画像を作りたい。

どうやったか

  1. 画像全体にモザイクをかけた画像を作成する。
    fullmosaic.jpeg
  2. モザイクを入れたい箇所のマスク画像を作成する。
    mask.jpeg
  3. 元画像に対して、マスク処理で、モザイク画像を合成する。
    photo-1484608856193-968d2be4080e-200203132846-458d11b515.jpeg
    こんな感じのモザイク画像ができる。

コード

    try:
        height = image.shape[0]
        width = image.shape[1]

        # 1. 画像全体にモザイクをかけた画像を作成する。
        ratio=0.1
        imageSmall = cv2.resize(image, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
        imageMosaic = cv2.resize(imageSmall, image.shape[:2][::-1], interpolation=cv2.INTER_NEAREST)

        # 2. モザイクを入れたい箇所のマスク画像を作成する。
        imageMask = np.tile(np.uint8(0), (height, width, 1))
        for points in pointsList:
            pointAry = convertToArray(points)
            contours = np.array(
                [
                    [pointAry[0].x, pointAry[0].y],
                    [pointAry[1].x, pointAry[1].y],
                    [pointAry[2].x, pointAry[2].y],
                    [pointAry[3].x, pointAry[3].y],
                ]
            )
            cv2.fillConvexPoly(imageMask, contours, color=(255, 255, 255))

        # 3. 元画像に対して、マスク処理で、モザイク画像を合成する。
        # for y in range(height) :
        #     for x in range(width) :
        #         color = imageMask[y][x]
        #         if color != 0 :
        #             image[y][x] = imageMosaic[y][x]
        # ↑10秒のコード ↓80ミリ秒のコード (800x600)
        image = np.where(imageMask != 0, imageMosaic, image)

    except Exception as e:
        logger.exception(e)

ゆる募

ゆる募 1
3.元画像に対して、マスク処理で、モザイク画像を合成する。
これ、ループで1ピクセルずつ処理させてるのですが、遅くて。OpenCVでもっとサクッと効率よく実装できるのではないかと思っておりまして。どなたか。
@yousuke_papa さんからアドバイス頂きまして解決しました。800x600の画像での処理時間が10秒が80ミリ秒になりました!Pythonで長いループ、ダメ、絶対!!

ゆる募 2
「長方形といいますか画像に対して並行」や「斜めってる領域」このあたりの正式名称。どなたか!

  • Chuuiさんコメント頂きました!ありがとうございます!
    「長方形といいますか画像に対して並行」-> 「画像に対して並行な矩形」
    「斜めってる領域」-> 「多角形領域」/「ポリゴン」
    fillConvexPoly関数には『凸ポリゴンを描きます』と説明されておりまして。
    アルゴリズムの学術分野(非デジタル)では、多角形領域をConvex(凸)か非Convex(凹)かで大きく区分するそうです・・・:innocent:・・・。
5
4
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4