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

目次
概要
numpy を使用して、1枚の画像をグリッド上に分割して複数枚の画像にする、また同じサイズの複数枚の画像をグリッド上に並べて1枚の画像にする方法について解説します。
Advertisement
1枚の画像をグリッド上に分割して複数枚の画像にする
行数、列数を指定して、分割する場合
OpenCV で読み込んだ画像は2次元または3次元配列なので、numpy.array_split() を使用して、分割します。
まず 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)

-
前の記事
OpenCV – 画像処理の2値化の仕組みと cv2.threshold() の使い方 2020.03.04
-
次の記事
OpenCV で画像のヒストグラムを作成する方法 2020.03.20