LoginSignup
12
9

More than 5 years have passed since last update.

OpenCVで透過画像を任意の画像に張り付ける

Posted at

OpenCVの公式ドキュメントに、透過画像を張り付けるチュートリアルが存在するが、縁取りとか回転とかの方法までは書かれていなかったので記事を作成した。

結果

チュートリアルそのまま

test1.jpg

縁取り

どうしても透過画像をそのまま張り付けると画像の縁がジャギジャギになってしまうので、以下の画像では透過情報を膨張・縮小して縁を調整している。

test2.jpg

ランダム回転とランダム移動

以下の画像のように、ランダムに回転・移動ができると画像のバリエーションが簡単に増やせる。Deep Learningなどでデータを水増ししたい場合に利用することが多い。

test3.jpg

解説

以下がメイン文。二枚の画像(前景hoge.pngと背景huga.png)を読み込み、縁取りや回転・移動のフラグを設定すると合成された画像が表示される。cv2.imread()の第二引数にはアルファチャンネルまで読み込むように-1を設定する。縁取りしたい場合は一つ目のFalseTrueに、ランダム回転・移動をしたい場合は二つ目のFalseTrueにする。

main.py
import cv2
from paste import paste


if __name__ == '__main__':
    img = paste(
        cv2.imread('hoge.png', -1),# 前景
        cv2.imread('huga.png', -1),# 背景
        False, False # 縁フラグ、回転・移動フラグ
    )

    cv2.imshow('test', img) # 画像の表示
    cv2.waitKey(0)

前景と背景の合成

基本的にはチュートリアルと同じ。

paste.py
import cv2
import numpy as np
from rotate import rotateR

def paste(fg, bg, mask_flg=True, random_flg=True):
    """
    背景に前景を重ね合せる
    [in]  fg:         重ね合せる背景
    [in]  bg:         重ね合せる前景
    [in]  mask_flg:   マスク処理を大きめにするフラグ
    [in]  random_flg: 前景をランダムに配置するフラグ
    [out] 重ね合せた画像
    """

    # Load two images
    img1 = bg.copy()
    if random_flg:# ランダム回転
        img2, _ = rotateR(fg, [-90, 90], 1.0)
    else:
        img2 = fg.copy()

    # I want to put logo on top-left corner, So I create a ROI
    w1, h1 = img1.shape[:2]
    w2, h2 = img2.shape[:2]
    if random_flg:# ランダム移動
        x = np.random.randint(0, w1 - w2 + 1)
        y = np.random.randint(0, w1 - w2 + 1)
    else:
        x = 0
        y = 0

    roi = img1[x:x + w2, y:y + h2]

    # Now create a mask of logo and create its inverse mask also
    mask = img2[:, :, 3]
    ret, mask_inv = cv2.threshold(
        cv2.bitwise_not(mask),
        200, 255, cv2.THRESH_BINARY
    )

    if mask_flg:# 縁を膨張・収縮で作成(膨張大きめ)
        kernel1 = np.ones((5, 5), np.uint8)
        kernel2 = np.ones((3, 3), np.uint8)
        mask_inv = cv2.dilate(mask_inv, kernel1, iterations=1)
        mask_inv = cv2.erode(mask_inv, kernel2, iterations=1)

    # Now black-out the area of logo in ROI
    img1_bg = cv2.bitwise_and(roi, roi, mask=mask_inv)

    # Take only region of logo from logo image.
    img2_fg = cv2.bitwise_and(img2, img2, mask=mask)

    # Put logo in ROI and modify the main image
    dst = cv2.add(img1_bg, img2_fg)
    img1[x:x + w2, y:y + h2] = dst
    return img1

ランダム回転

ランダム回転に使用している自作関数は、cv2.warpAffine()を利用している。

rotate.py
import cv2
import numpy as np

def rotate(img, angle, scale):
    """
    画像を回転(反転)させる
    [in]  img:   回転させる画像
    [in]  angle: 回転させる角度
    [in]  scale: 拡大率
    [out] 回転させた画像
    """

    size = img.shape[:2]
    mat = cv2.getRotationMatrix2D((size[0] // 2, size[1] // 2), angle, scale)
    return cv2.warpAffine(img, mat, size, flags=cv2.INTER_CUBIC)


def rotateR(img, level=[-10, 10], scale=1.2):
    """
    ランダムに画像を回転させる
    [in]  img:   回転させる画像
    [in]  level: 回転させる角度の範囲
    [out] 回転させた画像
    [out] 回転させた角度
    """

    angle = np.random.randint(level[0], level[1])
    return rotate(img, angle, scale), angle

以上。

12
9
0

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
12
9