首页 > 解决方案 > 如何使用 Python 在网格中连接 * 最多 * 4 个图像?

问题描述

我正在学习如何使用 PIL,我想将 4 个单独的图像连接成一个网格(所有256x256PNG)。使用 PIL(以及可选的 NumPy)。通过我发现的几个示例,当我正好有 4 张图像时,我已经能够通过将它们全部水平/垂直堆叠作为网格堆叠来连接图像。

我现在想要做的是将最多4 个图像组合成一个网格,即将 1 到 4 个图像之间的任何地方传递到一个函数中。

图像1 img2 图像3 img4

用例:

1 张图片 2 张图片 3 张图片 4 张图片
或者

我的第一个想法是将图像列表分成对,水平连接每个,然后垂直连接两个结果,但感觉效率低下。

编辑:我已经使用 OpenCV 进行了上述工作,因为它比 PIL 更容易使用。这是我的代码:

images = ["images/img1.png", "images/img2.png", "images/img3.png", "images/img4.png"]

def combine(images):
    if len(images) == 1:
        img1 = cv2.imread(images[0])
        return cv2.imwrite("Combined.png", img1)
    elif len(images) == 2:
        img1 = cv2.imread(images[0])
        img2 = cv2.imread(images[1])

        combined_image = cv2.hconcat([img1, img2])
        return cv2.imwrite("Combined.png", combined_image)
    elif len(images) == 3:
        img1 = cv2.imread(images[0])
        img2 = cv2.imread(images[1])
        img3 = cv2.imread(images[2])
        img4 = cv2.imread("images/Blank.png") # Just a transparent PNG

        image_row_1 = cv2.hconcat([img1, img2])
        image_row_2 = cv2.hconcat([img3, img4])
        combined_image = cv2.vconcat([image_row_1, image_row_2])

        return cv2.imwrite("Combined.png", combined_image)
    elif len(images) == 4:
        img1 = cv2.imread(images[0])
        img2 = cv2.imread(images[1])
        img3 = cv2.imread(images[2])
        img4 = cv2.imread(images[3])

        image_row_1 = cv2.hconcat([img1, img2])
        image_row_2 = cv2.hconcat([img3, img4])
        combined_image = cv2.vconcat([image_row_1, image_row_2])

        return cv2.imwrite("Combined.png", combined_image)


combine(images)

有没有更好的办法?

标签: pythonpython-3.xnumpypython-imaging-library

解决方案


如果您对 NumPy 中的替代方案感兴趣。这是将14 个图像平铺在2x2网格上的一种方法。

考虑x定义为形状数组的输入,(n, c, h, w)其中n是图像的数量(可以是1234)、c通道数(此处为3)以及h, w图像的高度和宽度(我们将坚持2x2,但它适用于任何尺寸。

出于演示目的,x定义为:

x = np.array([
    np.arange(1, 5).reshape((2,2))*1,
    np.arange(1, 5).reshape((2,2))*10,
    np.arange(1, 5).reshape((2,2))*100,
    np.arange(1, 5).reshape((2,2))*1000,
])
x = np.stack([x]*3, axis=1) # make it 3-channel

首先用零填充输入作为丢失图像的占位符。这将确保我们有一个形状,4, c, h, w即四个图像dim=0

x_fill = np.concatenate([x, np.zeros((4-n, c, h, w))])

首先广播到2x2x...形状(按列!使用order='F'):

x_fill = x_fill.reshape((2, 2, c, h, w), order='F')

最后连接axis=3then axis=1

grid = np.concatenate(np.concatenate(x_fill, axis=3), axis=1)

以下是输出(仅显示 的第一个通道grid):

  • 1 张图片:

    array([[[  1.,   2.,   0.,   0.],
            [  3.,   4.,   0.,   0.],
            [  0.,   0.,   0.,   0.],
            [  0.,   0.,   0.,   0.]]])
    
  • 2 张图片:

    array([[[  1.,   2.,  10.,  20.],
            [  3.,   4.,  30.,  40.],
            [  0.,   0.,   0.,   0.],
            [  0.,   0.,   0.,   0.]]])
    
  • 3 张图片:

    array([[[  1.,   2.,  10.,  20.],
            [  3.,   4.,  30.,  40.],
            [100., 200.,   0.,   0.],
            [300., 400.,   0.,   0.]]])
    
  • 4 张图片:

    array([[[  1.,   2.,  10.,  20.],
            [  3.,   4.,  30.,  40.],
            [100., 200.,1000.,2000.],
            [300., 400.,3000.,4000.]]])
    

这是输入的x样子:

array([[[[   1,    2],
         [   3,    4]],

        [[   1,    2],
         [   3,    4]],

        [[   1,    2],
         [   3,    4]]],


       [[[  10,   20],
         [  30,   40]],

        [[  10,   20],
         [  30,   40]],

        [[  10,   20],
         [  30,   40]]],


       [[[ 100,  200],
         [ 300,  400]],

        [[ 100,  200],
         [ 300,  400]],

        [[ 100,  200],
         [ 300,  400]]],


       [[[1000, 2000],
         [3000, 4000]],

        [[1000, 2000],
         [3000, 4000]],

        [[1000, 2000],
         [3000, 4000]]]])

推荐阅读