Warning: Undefined variable $position in /home/pystyles/pystyle.info/public_html/wp/wp-content/themes/lionblog/functions.php on line 4897

OpenCV – 画像をグリッド上に分割する、複数の画像をグリッド上に結合する方法

OpenCV – 画像をグリッド上に分割する、複数の画像をグリッド上に結合する方法

概要

numpy を使用して、1枚の画像をグリッド上に分割して複数枚の画像にする、また同じサイズの複数枚の画像をグリッド上に並べて1枚の画像にする方法について解説します。

Advertisement

1枚の画像をグリッド上に分割して複数枚の画像にする

sample.jpg

行数、列数を指定して、分割する場合

OpenCV で読み込んだ画像は2次元または3次元配列なので、numpy.array_split() を使用して、分割します。

画像と axis の対応

まず indices_or_sections=行数, axis=0 として、画像を行方向に分割します。

次に indices_or_sections=列数, axis=1 として、画像を列方向に分割します。

In [1]:
from pathlib import Path

import cv2
import numpy as np

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

rows = 5  # 行数
cols = 7  # 列数

chunks = []
for row_img in np.array_split(img, rows, axis=0):
    for chunk in np.array_split(row_img, cols, axis=1):
        chunks.append(chunk)
print(len(chunks))
35

行数を5、列数を7としたので、全部で35枚の画像に分割されました。

分割した画像は output ディレクトリを作成して、そこに保存します。

In [2]:
# 保存する。
output_dir = Path("output")
output_dir.mkdir(exist_ok=True)
for i, chunk in enumerate(chunks):
    save_path = output_dir / f"chunk_{i:02d}.png"
    cv2.imwrite(str(save_path), chunk)

分割後の画像の大きさを指定して分割する場合

分割後の画像の大きさから、行数、列数を逆算します。

  • 行数 = 画像の高さ / 分割後の画像の高さ
  • 列数 = 画像の幅 / 分割後の画像の幅

除算の結果は、端数を切り捨てる場合は numpy.floor()、切り捨てない場合は numpy.ceil() を使って整数にします。

それ以外の部分は先のコードと同じです。

In [3]:
from pathlib import Path

import cv2
import numpy as np

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

size = (64, 64)  # 分割後の大きさ
rows = int(np.ceil(img.shape[0] / size[0]))  # 行数
cols = int(np.ceil(img.shape[1] / size[1]))  # 列数

chunks = []
for row_img in np.array_split(img, rows, axis=0):
    for chunk in np.array_split(row_img, cols, axis=1):
        chunks.append(chunk)
print(len(chunks))

# 保存する。
output_dir = Path("output")
output_dir.mkdir(exist_ok=True)
for i, chunk in enumerate(chunks):
    save_path = output_dir / f"chunk_{i:02d}.png"
    cv2.imwrite(str(save_path), chunk)
20
Advertisement

同じサイズの複数枚の画像をグリッド上に並べて1枚の画像にする

同じサイズの複数枚の画像をグリッド上に並べて1枚の画像にするには、分割したときと逆に、numpy.concatenate() を使用して、結合します。

今回は例として、sklearn.datasets.fetch_openml() で大きさが (28, 28) の100枚の手書き数字画像を10行10列のグリッド上に並べて、1枚の画像にします。

In [4]:
from sklearn.datasets import fetch_openml

# ダウンロードが発生するので、実行に少し時間がかかります。
mnist = fetch_openml("mnist_784", version=1)

imgs = mnist.data.reshape(-1, 28, 28).astype(np.uint8)[:100]
print(imgs.shape)
(100, 28, 28)

結合する画像の一覧を配置する形状に numpy.ndarray.reshape() で変更します。

In [5]:
rows = 10  # 行数
cols = 10  # 列数

imgs = imgs.reshape(rows, cols, *imgs.shape[1:])
print(imgs.shape)
(10, 10, 28, 28)

まず axis=1 として、画像を列方向に結合します。

次に axis=0 として、画像を行方向に結合します。

In [6]:
# 列方向に結合する。
row_imgs = [np.concatenate(col_imgs, axis=1) for col_imgs in imgs]
# 行方向に結合する。
concat_img = np.concatenate(row_imgs, axis=0)
imshow(concat_img)