问题
I have four images and I want to concatenate them into 1 image.I tried using concatenate function but there are multiple images and from them i need only in a batch of 4 images.
Actually the images are named as 0.jpg, 1.jpg,2.jpg and 3.jpg
Below is the code which contains four images and concatenates them to be one image. But i am having around 500 images in a folder and I want to group them in a pair of four based on the range like first4 then second 4 and so on.
import numpy as np
import glob,os
import cv2
directory = "./image/"
for image in sorted(glob.glob(directory + '*.jpg'),key=os.path.getmtime):
name = image.split('/')[-1]
iname = name.split('.')[0]
print(iname)
img1 = cv2.imread('0.jpg')
img2 = cv2.imread('1.jpg')
vis1 = np.concatenate((img1, img2), axis=1)
img3 = cv2.imread('2.jpg')
img4 = cv2.imread('3.jpg')
vis2 = np.concatenate((img3, img4), axis=1)
vis = np.concatenate((vis1, vis2), axis=0)
cv2.imwrite(iname+'.jpg', vis1)
回答1:
This should do the trick, or at least get you started. It chooses red as the background colour, and makes a 1x1 filler (padding) image the same colour. It then groups your images by four and pad-fills the final group if not a multiple of 4. It then iterates over the list and opens 4 images on each iteration. It gets their sizes and then determines the width and height of the output image. Then it creates the output image filled with the background colour and then pastes the images onto the background and saves the result.
You may choose to improve the layout, but that is just fiddling around with aesthetics, so you can do that bit!
#!/usr/bin/env python3
import cv2
import os, glob
from itertools import zip_longest
def grouper(iterable, n, fillvalue=None):
"""
Group items of list in groups of "n" padding with "fillvalue"
"""
args = [iter(iterable)] * n
return zip_longest(*args, fillvalue=fillvalue)
# Go to where the images are instead of managing a load of complicated paths
os.chdir('images')
# Get list of filenames sorted by mtime
filenames = sorted(glob.glob('*.jpg'),key=os.path.getmtime)
# Define a background colour onto which you will paste the images
bg = [0,0,255] # background = red
# Make a 1x1 filler image as a PNG so that it doesn't appear in your globbed list of JPEGs
# Make it same as background colour so it doesn't show
fill = np.full((1,1,3), bg, dtype=np.uint8)
cv2.imwrite('fill.png', fill)
# Iterate over the files in groups of 4
out = 1
for f1, f2, f3, f4 in grouper(filenames, 4, 'fill.png'):
outfile = f'montage-{out}.jpg'
print(f'DEBUG: Merging {f1},{f2},{f3},{f4} to form {outfile}')
out += 1
# Load all 4 images
i1 = cv2.imread(f1)
i1h, i1w = i1.shape[:2]
i2 = cv2.imread(f2)
i2h, i2w = i2.shape[:2]
i3 = cv2.imread(f3)
i3h, i3w = i3.shape[:2]
i4 = cv2.imread(f4)
i4h, i4w = i4.shape[:2]
# Decide width of output image
w = max(i1w+i2w, i3w+i4w)
# Decide height of output image
h = max(i1h,i2h) + max(i3h,i4h)
# Make background image of background colour onto which to paste 4 images
res = np.full((h,w,3), bg, dtype=np.uint8)
# There are fancier layouts, but I will just paste into the 4 corners
res[0:i1h, 0:i1w, :] = i1 # image 1 into top-left
res[0:i2h, w-i2w:, :] = i2 # image 2 into top-right
res[h-i3h:,0:i3w, :] = i3 # image 3 into bottom-left
res[h-i4h:,w-i4w:, :] = i4 # image 4 into bottom-right
# Save result image
cv2.imwrite(outfile, res)
It creates output images like this:
Note you can do the same thing just using a couple of lines of bash shell script if you use ImageMagick:
#!/bin/bash
# Build list of images
images=(*.jpg)
out=1
# Keep going till there are fewer than 4 left in list
while [ ${#images[@]} -gt 3 ] ; do
# Montage first 4 images from list
magick montage -geometry +0+0 -tile 2x2 -background yellow "${images[@]:0:4}" "montage-${out}.png"
# Delete first 4 images from list
images=(${images[@]:4})
((out+=1))
done
Keywords: Python, OpenCV, montage, group, grouped, by four, by fours.
来源:https://stackoverflow.com/questions/61356657/to-concatenate-4-images-using-np-concatenate-two-vertically-and-two-horizontall