Concatenate Multiple Pieces Of An Image To A Single Image Using Python
Solution 1:
These are stitched together horizontally because you have stuck them together with np.hstack()
when you actually want to hstack
only three at a time into rows and then vstack
them together vertically. Replacing that one line with the below should do what you need.
img_rows = []
for min_id inrange(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 ) )
Solution 2:
Since you've mentioned they are all the same size you can create a new image:
c, h, w = image.shapenew_image= np.zeros((5 * h, 3 * w))
Now we have an empty image in the correct size.
The next step is copying the images into the big image (forgive me cause i didnt test this bit of code but with minor changes / fixes it should work, the important part is the idea)
row=-1for i, img in enumerate(list_of_images):
if i %3:
col =0row+=1
new_image[:, row* h: (row+1) * h, col * w: (col +1) * w] = img
col +=1
essentially you are tiling the images into the big image and the result should be as you hoped for.
Solution 3:
I tried the same approach as Dr. Prof. Patrick and made more universal function. Number of images can be less than rows * cols in this version.
#!/usr/bin/env python3import numpy as np
from imageio import imread, imwrite
from pathlib import Path
import math
deftile_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 isnotNone:
h, w = tile_size
ifnot 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 coloriflen(images) < rows * cols and bg_val isnotNone:
new = np.add(new, bg_val)
# paste images into array
c, r = 0, 0for i, im inenumerate(images):
x, y = r * h, c * w
new[x : x + im.shape[0], y : y + im.shape[1]] = np.atleast_3d(im)
c += 1ifnot (i+1) % cols:
r += 1# next row
c = 0return new
defmain():
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()
EDIT: I have removed the need to check if image has 2 or 3 dim with np.atleast_3d function. Parameter tile_size allows to set grid size manually, if omitted, first image will be used.
In this version input images need not to be of the same size. Images can overlay, but they must not overflow.
Post a Comment for "Concatenate Multiple Pieces Of An Image To A Single Image Using Python"