OpenCV – 画像を横、縦、格子状に結合する方法

目次

概要

OpenCV で複数の画像を横方向、または縦方向に結合する方法について解説します。

横方向に結合する

横方向に結合する場合、結合するすべての画像が収まる大きさの画像を作成し、そこに各画像を貼り付ける形で作成します。 その際、結合後の画像の大きさは以下のようになります。

  • 結合後の幅: 結合する画像の幅の合計値
  • 結合後の幅: 結合する画像の高さの最大値
In [1]:
import cv2
import numpy as np
from IPython.display import Image, display


def imshow(img):
    """ndarray 配列をインラインで Notebook 上に表示する。"""
    ret, encoded = cv2.imencode(".jpg", img)
    display(Image(encoded))
In [2]:
img1 = cv2.imread("samples/sample01.jpg", cv2.IMREAD_COLOR)
img2 = cv2.imread("samples/sample02.jpg", cv2.IMREAD_COLOR)
img3 = cv2.imread("samples/sample03.jpg", cv2.IMREAD_COLOR)


def concat_w(*imgs, background=(255, 255, 255)):
    """画像を横方向に結合する。

    Args:
        background: 背景色

    Returns:
        結合した画像
    """
    img_h = max(x.shape[0] for x in imgs)
    img_w = sum(x.shape[1] for x in imgs)

    dst = np.full((img_h, img_w, 3), background, dtype=np.uint8)
    x = 0
    for img in imgs:
        dst[: img.shape[0], x : x + img.shape[1]] = img
        x += img.shape[1]

    return dst


dst = concat_w(img1, img2, img3)
imshow(dst)

縦方向に結合する

縦方向に結合する場合、結合するすべての画像が収まる大きさの画像を作成し、そこに各画像を貼り付ける形で作成します。 その際、結合後の画像の大きさは以下のようになります。

  • 結合後の幅: 結合する画像の幅の最大値
  • 結合後の幅: 結合する画像の高さの合計値
In [3]:
img1 = cv2.imread("samples/sample01.jpg", cv2.IMREAD_COLOR)
img2 = cv2.imread("samples/sample02.jpg", cv2.IMREAD_COLOR)
img3 = cv2.imread("samples/sample03.jpg", cv2.IMREAD_COLOR)


def concat_h(*imgs, background=(255, 255, 255)):
    """画像を縦に結合する。

    Args:
        background: 背景色

    Returns:
        結合した画像
    """
    img_w = max(x.shape[1] for x in imgs)
    img_h = sum(x.shape[0] for x in imgs)

    dst = np.full((img_h, img_w, 3), background, dtype=np.uint8)
    y = 0
    for img in imgs:
        dst[y : y + img.shape[0], : img.shape[1]] = img
        y += img.shape[0]

    return dst


dst = concat_h(img1, img2, img3)
imshow(dst)

画像を格子状に並べる

画像を格子状に並べるコードを紹介します。

In [4]:
import math
from pathlib import Path

# 画像を読み込む。
imgs = []
for img_path in Path("samples").glob("*.jpg"):
    img = cv2.imread(str(img_path), cv2.IMREAD_COLOR)
    imgs.append(img)


def concat_grid(imgs, cols, background=(255, 255, 255), gap=5):
    """画像を格子状に配置する。

    Args:
        imgs: 画像一覧
        cols: 1行あたりの画像枚数
        background: 背景色
        gap: 画像間の隙間の大きさ

    Returns:
        結合した画像
    """
    rows = math.ceil(len(imgs) / cols)

    # 各行、各列の幅及び高さを計算する。
    row_hs, col_ws = [], []
    for i in range(rows):
        row_h = max(x.shape[0] for x in imgs[i * cols : (i + 1) * cols])
        row_hs.append(row_h)
    for i in range(cols):
        col_w = max(x.shape[1] for x in imgs[i::cols])
        col_ws.append(col_w)

    # 出力画像の大きさを計算する。
    img_w = sum(col_ws) + gap * (cols - 1)
    img_h = sum(row_hs) + gap * (rows - 1)
    dst = np.full((img_h, img_w, 3), background, dtype=np.uint8)

    # 画像を配置する。
    for i, img in enumerate(imgs):
        row = i // cols
        col = i % cols
        x = sum(col_ws[:col]) + col * gap
        y = sum(row_hs[:row]) + row * gap
        dst[y : y + img.shape[0], x : x + img.shape[1]] = img

    return dst


dst = concat_grid(imgs, cols=3)
imshow(dst)

コメント

コメントする

目次