使用 python 将多张图片连接成一张图片
Concatenate multiple pieces of an image to a single image using python
我有 15 张图片(从 1 到 15)。我想将这些图像拼接在一起,以便形成一个图像。到目前为止我尝试了什么?
import numpy as np
import PIL
from PIL import Image
import os
filenames = [os.path.abspath(os.path.join(directory, p)) for p in os.listdir(directory) if p.endswith(('jpg', 'png'))]
imgs = [PIL.Image.open(i) for i in filenames]
min_shape = sorted( [(np.sum(i.size), i.size ) for i in imgs])[0][1]
imgs_comb = np.hstack( (np.asarray( i.resize(min_shape) ) for i in imgs ) )
imgs_comb = PIL.Image.fromarray( imgs_comb)
imgs_comb.save( 'stitched_image.jpg' )
这会水平拼接图像,而不是完美的图像。输出如下所示:
但所需的输出应该是:
我该怎么做?
既然您已经提到它们的尺寸都相同,那么您可以创建一个新图像:
c, h, w = image.shape
new_image = np.zeros((5 * h, 3 * w))
现在我们有一个正确大小的空图像。
下一步是将图像复制到大图像中(请原谅我,因为我没有测试这段代码,但稍作更改/修复它应该可以工作,重要的部分是想法)
row = -1
for i, img in enumerate(list_of_images):
if i % 3:
col = 0
row += 1
new_image[:, row * h: (row + 1) * h, col * w: (col + 1) * w] = img
col += 1
本质上,您是将图像平铺成大图像,结果应该如您所愿。
这些是水平缝合在一起的,因为当您实际上只想 hstack
一次只 hstack
成行然后 vstack
将它们垂直缝合在一起时,您已经将它们与 np.hstack()
粘在一起。用下面的内容替换这一行应该可以满足您的需要。
img_rows = []
for min_id in range(0, 15, 3):
img_row = np.hstack( (np.asarray( i.resize(min_shape) ) for i in imgs[min_id: min_id+3] ) )
img_rows.append(img_row)
imgs_comb = np.vstack( ( i for i in img_rows ) )
我尝试了和Dr. Prof. Patrick一样的方法,做了更通用的功能。在此版本中,图像数量可以少于行数 * 列数。
#!/usr/bin/env python3
import numpy as np
from imageio import imread, imwrite
from pathlib import Path
import math
def tile_images(images, cols=None, bg_val=None, tile_size=None):
"""Tile images to grid with given number of columns.
Args:
images (list of np.arrays)
cols (int): 1 = vertical, None = horizontal stitch
bg_val (int or tuple): color of empty background
Returns:
np.array: stitched image
"""
im1 = np.atleast_3d(images[0]) # add 3rd dim to grey image
h, w, ch = im1.shape
if tile_size is not None:
h, w = tile_size
if not cols:
cols = len(images)
rows = math.ceil(len(images) / cols)
# make empty array
new = np.zeros((h * rows, w * cols, ch), dtype=im1.dtype)
# change bg color
if len(images) < rows * cols and bg_val is not None:
new = np.add(new, bg_val)
# paste images into array
c, r = 0, 0
for i, im in enumerate(images):
x, y = r * h, c * w
new[x : x + im.shape[0], y : y + im.shape[1]] = np.atleast_3d(im)
c += 1
if not (i+1) % cols:
r += 1 # next row
c = 0
return new
def main():
paths = sorted(f for f in Path().glob("*.*") if f.suffix in (".jpg", ".png") and f.stem != "new")
images = [imread(f) for f in paths]
new = tile_images(images, cols=3, bg_val=(127,150,127))
imwrite("new.png", new)
if __name__ == "__main__":
main()
编辑:我已经删除了使用 np.atleast_3d 函数检查图像是否有 2 或 3 个暗淡的需要。
参数tile_size允许手动设置网格大小,如果省略,将使用第一张图像。
在此版本中,输入图像的大小不必相同。图片可以叠加,但不能溢出。
我有 15 张图片(从 1 到 15)。我想将这些图像拼接在一起,以便形成一个图像。到目前为止我尝试了什么?
import numpy as np
import PIL
from PIL import Image
import os
filenames = [os.path.abspath(os.path.join(directory, p)) for p in os.listdir(directory) if p.endswith(('jpg', 'png'))]
imgs = [PIL.Image.open(i) for i in filenames]
min_shape = sorted( [(np.sum(i.size), i.size ) for i in imgs])[0][1]
imgs_comb = np.hstack( (np.asarray( i.resize(min_shape) ) for i in imgs ) )
imgs_comb = PIL.Image.fromarray( imgs_comb)
imgs_comb.save( 'stitched_image.jpg' )
这会水平拼接图像,而不是完美的图像。输出如下所示:
但所需的输出应该是:
我该怎么做?
既然您已经提到它们的尺寸都相同,那么您可以创建一个新图像:
c, h, w = image.shape
new_image = np.zeros((5 * h, 3 * w))
现在我们有一个正确大小的空图像。
下一步是将图像复制到大图像中(请原谅我,因为我没有测试这段代码,但稍作更改/修复它应该可以工作,重要的部分是想法)
row = -1
for i, img in enumerate(list_of_images):
if i % 3:
col = 0
row += 1
new_image[:, row * h: (row + 1) * h, col * w: (col + 1) * w] = img
col += 1
本质上,您是将图像平铺成大图像,结果应该如您所愿。
这些是水平缝合在一起的,因为当您实际上只想 hstack
一次只 hstack
成行然后 vstack
将它们垂直缝合在一起时,您已经将它们与 np.hstack()
粘在一起。用下面的内容替换这一行应该可以满足您的需要。
img_rows = []
for min_id in range(0, 15, 3):
img_row = np.hstack( (np.asarray( i.resize(min_shape) ) for i in imgs[min_id: min_id+3] ) )
img_rows.append(img_row)
imgs_comb = np.vstack( ( i for i in img_rows ) )
我尝试了和Dr. Prof. Patrick一样的方法,做了更通用的功能。在此版本中,图像数量可以少于行数 * 列数。
#!/usr/bin/env python3
import numpy as np
from imageio import imread, imwrite
from pathlib import Path
import math
def tile_images(images, cols=None, bg_val=None, tile_size=None):
"""Tile images to grid with given number of columns.
Args:
images (list of np.arrays)
cols (int): 1 = vertical, None = horizontal stitch
bg_val (int or tuple): color of empty background
Returns:
np.array: stitched image
"""
im1 = np.atleast_3d(images[0]) # add 3rd dim to grey image
h, w, ch = im1.shape
if tile_size is not None:
h, w = tile_size
if not cols:
cols = len(images)
rows = math.ceil(len(images) / cols)
# make empty array
new = np.zeros((h * rows, w * cols, ch), dtype=im1.dtype)
# change bg color
if len(images) < rows * cols and bg_val is not None:
new = np.add(new, bg_val)
# paste images into array
c, r = 0, 0
for i, im in enumerate(images):
x, y = r * h, c * w
new[x : x + im.shape[0], y : y + im.shape[1]] = np.atleast_3d(im)
c += 1
if not (i+1) % cols:
r += 1 # next row
c = 0
return new
def main():
paths = sorted(f for f in Path().glob("*.*") if f.suffix in (".jpg", ".png") and f.stem != "new")
images = [imread(f) for f in paths]
new = tile_images(images, cols=3, bg_val=(127,150,127))
imwrite("new.png", new)
if __name__ == "__main__":
main()
编辑:我已经删除了使用 np.atleast_3d 函数检查图像是否有 2 或 3 个暗淡的需要。 参数tile_size允许手动设置网格大小,如果省略,将使用第一张图像。
在此版本中,输入图像的大小不必相同。图片可以叠加,但不能溢出。