Pynote

Python、機械学習、画像処理について

OpenCV - 画像をグリッド上に分割する方法について

概要

画像をグリッド上に分割する方法について紹介する。



サンプル画像

import cv2
import matplotlib.pyplot as plt
import numpy as np

def imshow(img):
    if img.ndim == 2:
        plt.imshow(img, cmap='gray')
    else:
        plt.imshow(img[...,::-1])
    plt.axis('off')
    plt.show()

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

分割する際に画像の幅、高さが分割する数で割り切れないと都合が悪いので、端数がでないように画像をクロップする。

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

num_vsplits = 5  # 垂直方向の分割数
num_hsplits = 7  # 水平方向の分割数

# 均等に分割できないと np.spllt() が使えないので、
# 除算したときに余りがでないように画像の端数を切り捨てる。
h, w = img.shape[:2]
crop_img = img[:h // num_vsplits * num_vsplits, :w // num_hsplits * num_hsplits]
print('{} -> {}'.format(img.shape, crop_img.shape))  # (480, 640, 3) -> (480, 637, 3)

1. numpy.vsplit() で画像を縦方向に分割する。

2. numpy.hsplit() で縦方向に分割した各画像を横方向に分割する。


# 分割する。
out_imgs = []
for h_img in np.vsplit(crop_img, num_vsplits):  # 垂直方向に分割する。
    for v_img in np.hsplit(h_img, num_hsplits):  # 水平方向に分割する。
        out_imgs.append(v_img)
out_imgs = np.array(out_imgs)
print(out_imgs.shape)  # (35, 96, 91, 3)

結果を描画する。

# 描画する。
fig, ax_list = plt.subplots(num_vsplits, num_hsplits, figsize=(5, 5))
for sub_img, ax in zip(out_imgs, ax_list.ravel()):
    ax.imshow(sub_img[..., ::-1])
    ax.set_axis_off()

plt.show()

分割後のサイズを指定して分割する場合

分割する際に画像の幅、高さが分割する数で割り切れないと都合が悪いので、端数がでないように画像をクロップする。

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

vsize, hsize = 64, 64
h, w = img.shape[:2]
num_vsplits = h // vsize  # 垂直方向の分割数
num_hsplits = w // hsize  # 水平方向の分割数

# 均等に分割できないと np.spllt() が使えないので、
# 除算したときに余りがでないように画像の端数を切り捨てる。
crop_img = img[:h // num_vsplits * num_vsplits, :w // num_hsplits * num_hsplits]
print('{} -> {}'.format(img.shape, crop_img.shape))  # (480, 640, 3) -> (476, 640, 3)
# 分割する。
out_imgs = []
for h_img in np.vsplit(crop_img, num_vsplits):  # 垂直方向に分割する。
    for v_img in np.hsplit(h_img, num_hsplits):  # 水平方向に分割する。
        out_imgs.append(v_img)
out_imgs = np.array(out_imgs)
print(out_imgs.shape)  # (35, 96, 91, 3)

結果を描画する。

# 描画する。
fig, ax_list = plt.subplots(num_vsplits, num_hsplits, figsize=(5, 5))
for sub_img, ax in zip(out_imgs, ax_list.ravel()):
    ax.imshow(sub_img[..., ::-1])
    ax.set_axis_off()

plt.show()

結果画像

分割した画像を元に戻す

グリッド上に分割した画像を結合するには、分割したときと逆の処理を行う。

1. numpy.hstack() で画像を横方向に結合する。


2. numpy.vstack() で横方向に結合した各画像を横方向に分割する。


# まず水平方向に結合し、それらを垂直方向に結合する。
vsize, hsize, ch = out_imgs.shape[1:]
split_imgs = out_imgs.reshape(num_vsplits, num_hsplits, vsize, hsize, ch)
print(split_imgs.shape)  # (5, 7, 96, 91, 3)

merged_img = np.vstack([np.hstack(h_imgs) for h_imgs in split_imgs])
print(merged_img.shape)  # (480, 637, 3)

imshow(merged_img)