I have multiple different folders with the images have same naming like a.png etc. I want to modify the above code to read this same named files in different directories and give their opencv output using yolo at the same time. To be more specific I have 10 files which contains images transported with different categories like one folder contains rgb files and the other contains gray files etc. To compare their output, I want to show the images with same naming but in different folders. I know it should not be that hard but I am pretty confused. Thanks in advance!
import cv2
import numpy as np
import os
import matplotlib.pyplot as plt
import tkinter
from tkinter import filedialog
def cal_alpB(minMax):
minD = minMax[0]
maxD = minMax[1]
alpha = 255/(maxD-minD)
beta = -alpha*minD
return [alpha, beta]
def getMinMax(path):
with open(path+'/config') as f:
minMax = f.read().splitlines()
minMax = minMax[0].split(',')
minMax = [eval(x) for x in minMax]
return minMax
def normalizeData(minMax, img):
alpB = cal_alpB(minMax)
img[img>minMax[1]] = minMax[1]
img[img<0] = 0
return alpB
def boxDrawing(layerOutput, frameWidth, frameHeight, class_ids, confidences, boxes, img):
for output in layerOutput:
for detection in output:
score = detection[5:]
class_id = np.argmax(score)
confidence = score[class_id]
if confidence > 0.5:
center_x = int(detection[0] * frameWidth)
center_y = int(detection[1] * frameHeight)
width = int(detection[2] * frameWidth)
height = int(detection[3] * frameHeight)
left = int(center_x - width / 2)
top = int(center_y - height / 2)
class_ids.append(class_id)
confidences.append(float(confidence))
boxes.append([left, top, width, height])
indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.8, 0.7)
font = cv2.FONT_HERSHEY_PLAIN
colors = np.random.uniform(0, 255, size = (len(boxes),3))
for i in range(len(boxes)):
if i in indexes:
x,y,w,h = boxes[i]
label = str(classes[class_ids[i]])
confi = str(round(confidences[i],2))
color = colors[i]
cv2.rectangle(img, (x,y), (x+w,y+h), color,1)
cv2.putText(img, label+" "+ confi, (x,y+20), font, 1, (255,255,255),1)
def algorythmYolo():
tkinter.Tk().withdraw()
folder = filedialog.askdirectory()
minMax = getMinMax(folder)
for filename in sorted(os.listdir(folder)):
img = cv2.imread(os.path.join(folder,filename),-1)
if img is not None:
alpB = normalizeData(minMax,img)
img = cv2.convertScaleAbs(img, alpha=alpB[0], beta= alpB[1])
img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
frameHeight, frameWidth, channels = img.shape
blob = cv2.dnn.blobFromImage(img, 1/255, (frameWidth,frameHeight), (0,0,0), swapRB = True, crop = False)
yolo.setInput(blob)
layerOutput = yolo.forward(outputLayers)
boxes = []
confidences = []
class_ids = []
boxDrawing(layerOutput,frameWidth, frameHeight,class_ids,confidences,boxes,img)
cv2.imshow("window", img)
cv2.setWindowTitle('window', folder)
cv2.waitKey(1)
else:
break
cv2.destroyAllWindows()
yolo = cv2.dnn.readNet("./yolov3.weights","./yolov3.cfg")
with open("./coco.names","r") as f:
classes = f.read().splitlines()
layers_names = yolo.getLayerNames()
outputLayers = [layers_names[i-1] for i in yolo.getUnconnectedOutLayers()]
cv2.namedWindow("window", cv2.WINDOW_NORMAL)
algorythmYolo()
I'm trying to take a few png images add them an enumerated grid and save them each image by itself as a single tiff file
the output I get is, first image with grid and numbers as required,
the first image is shorter then the others if that matters
other images are only numbered but without a grid
this is my code
from PIL import Image, ImageDraw, ImageOps, ImageFont
import os
import glob
path = r'D:\in'
out = r"d:\1.tif"
font = ImageFont.truetype(r"D:\python1\New folder\keyer_layout\films.EPISODE1.ttf",32)
def add_grid(path):
im = Image.open(path)
im = ImageOps.expand(im, border=50, fill = 'rgb(255,255,255)') #add margin to the image
draw = ImageDraw.Draw(im)
y_start = 0
y_end = im.height
step_size = int(im.width / 10)
li = 0
for x in range(0, im.width, step_size):
line = ((x, y_start), (x, y_end))
draw.line(line, fill=200)
draw.text((x, y_start),str(li),'rgb(0,0,0)',font=font)
li+=1
x_start = 0
x_end = im.width
li = 0
for y in range(0, im.height, step_size):
line = ((x_start, y), (x_end, y))
draw.line(line, fill=128)
draw.text((x_start, y),str(li),'rgb(0,0,0)',font=font)
li+=1
del draw
return im
pics_path = os.path.join(path,"*.png")
pics = glob.glob(pics_path)
pics_arr = []
for i in pics:
pics_arr.append(add_grid(i))
pics_arr[0].save(r"d:\test.tif", append_images = pics_arr[1:],save_all = True)
I tried to add im.show() inside the function the images looked the same first one with grid others without
when I tried to skip the first image, non of the images had a grid on it
Thanks
Firstly, instead of the last line there should be something like this:
for i, pict in enumerate(pics_arr):
pict.save(r"d:\test" + str(i) + ".tif")
This way you will get all your images with the grid on them as a bunch of tif files.
After that you need to combine them into one big file. It can be done this way: Combine several images horizontally with Python
The final script could look like this:
from PIL import Image, ImageDraw, ImageOps, ImageFont
import os
import glob
path = r'd:\in'
out = r'd:\out'
# font = ImageFont.truetype() <-- sorry, I have no your font at hand
def add_grid(path):
im = Image.open(path)
im = ImageOps.expand(im, border=50, fill = 'rgb(255,255,255)') #add margin to the image
draw = ImageDraw.Draw(im)
y_start = 0
y_end = im.height
step_size = int(im.width / 10)
li = 0
for x in range(0, im.width, step_size):
line = ((x, y_start), (x, y_end))
draw.line(line, fill=(200,200,200)) # <----- light gray RGB color
draw.text((x, y_start),str(li),'rgb(0,0,0)') #,font=font)
li+=1
x_start = 0
x_end = im.width
li = 0
for y in range(0, im.height, step_size):
line = ((x_start, y), (x_end, y))
draw.line(line, fill=(128,128,128)) # <----- gray RGB color
draw.text((x_start, y),str(li),'rgb(0,0,0)') #,font=font)
li+=1
del draw
return im
pics_path = os.path.join(path,"*.png")
pics = glob.glob(pics_path)
pics_arr = []
for i in pics:
pics_arr.append(add_grid(i))
# save gridded images
for i, pict in enumerate(pics_arr):
pict.save(out +"\test" + str(i) + ".png")
# combine the gridded images into the one tif
pics_path = os.path.join(out, "*.png")
pics = glob.glob(pics_path)
images = [Image.open(x) for x in pics]
widths, heights = zip(*(i.size for i in images))
total_width = sum(widths)
max_height = max(heights)
new_im = Image.new('RGB', (total_width, max_height))
x_offset = 0
for im in images:
new_im.paste(im, (x_offset,0))
x_offset += im.size[0]
new_im.save(out + '/test.tif')
Input:
Step 1:
Output:
Is there any way i can make my own train set for face recognition in python ? To be more specific i want to make a train set like an AT&T Face database. I want my camera to take 20 images of each person(30 max) and store it in the separate folders by the name of each person.
import cv2, sys, numpy, os
size = 4
fn_haar = 'haarcascade_frontalface_default.xml'
fn_dir = 'att_faces'
fn_name = sys.argv[1]
path = os.path.join(fn_dir, fn_name)
if not os.path.isdir(path):
os.mkdir(path)
(im_width, im_height) = (112, 92)
haar_cascade = cv2.CascadeClassifier(fn_haar)
webcam = cv2.VideoCapture(0)
# The program loops until it has 20 images of the face.
count = 0
while count < 20:
(rval, im) = webcam.read()
im = cv2.flip(im, 1, 0)
gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
mini = cv2.resize(gray, (gray.shape[1] / size, gray.shape[0] / size))
faces = haar_cascade.detectMultiScale(mini)
faces = sorted(faces, key=lambda x: x[3])
if faces:
face_i = faces[0]
(x, y, w, h) = [v * size for v in face_i]
face = gray[y:y + h, x:x + w]
face_resize = cv2.resize(face, (im_width, im_height))
pin=sorted([int(n[:n.find('.')]) for n in os.listdir(path)
if n[0]!='.' ]+[0])[-1] + 1
cv2.imwrite('%s/%s.png' % (path, pin), face_resize)
cv2.rectangle(im, (x, y), (x + w, y + h), (0, 255, 0), 3)
cv2.putText(im, fn_name, (x - 10, y - 10), cv2.FONT_HERSHEY_PLAIN,
1,(0, 255, 0))
count += 1
cv2.imshow('OpenCV', im)
key = cv2.waitKey(10)
if key == 27:
break
For this, you just need to provide a particular path to save all the image with (.png) or (.bmp) or (.jpg) extension in a sorted manner.
# train.py
import cv2, sys, numpy, os
size = 4
fn_haar = 'haarcascade_frontalface_default.xml'
fn_dir = 'face_data'
fn_name = sys.argv[0]
path = os.path.join(fn_dir, fn_name)
(im_width, im_height) = (112, 92)
haar_cascade = cv2.CascadeClassifier(fn_haar)
webcam = cv2.VideoCapture(0)
# Generate name for image file
pin=sorted([int(n[:n.find('.')]) for n in os.listdir(path)
if n[0]!='.' ]+[0])[-1] + 1
# Beginning message
print("\n\033[94mThe program will save 20 samples. \
Move your head around to increase while it runs.\033[0m\n")
# The program loops until it has 20 images of the face.
count = 0
pause = 0
count_max = 20
while count < count_max:
# Loop until the camera is working
rval = False
while(not rval):
# Put the image from the webcam into 'frame'
(rval, frame) = webcam.read()
if(not rval):
print("Failed to open webcam. Trying again...")
# Get image size
height, width, channels = frame.shape
# Flip frame
frame = cv2.flip(frame, 1, 0)
# Convert to grayscale
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Scale down for speed
mini = cv2.resize(gray, (int(gray.shape[1] / size), int(gray.shape[0] / size)))
# Detect faces
faces = haar_cascade.detectMultiScale(mini)
# We only consider largest face
faces = sorted(faces, key=lambda x: x[3])
if faces:
face_i = faces[0]
(x, y, w, h) = [v * size for v in face_i]
face = gray[y:y + h, x:x + w]
face_resize = cv2.resize(face, (im_width, im_height))
# Draw rectangle and write name
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 3)
cv2.putText(frame, fn_name, (x - 10, y - 10), cv2.FONT_HERSHEY_PLAIN,
1,(0, 255, 0))
# Remove false positives
if(w * 6 < width or h * 6 < height):
print("Face too small")
else:
# To create diversity, only save every fith detected image
if(pause == 0):
print("Saving training sample "+str(count+1)+"/"+str(count_max))
# Save image file
cv2.imwrite('%s/%s.png' % (path, pin), face_resize)
pin += 1
count += 1
pause = 1
if(pause > 0):
pause = (pause + 1) % 5
cv2.imshow('OpenCV', frame)
key = cv2.waitKey(10)
if key == 27:
break
This code will help you to get the cropped images from the webcam and store them in a directory name as face_data for training purpose.
In case, you don't want to train your dataset from webcam, you can simply do one thing:
that just create a directory and create 5-6 sub-directory in it as in Happy, Sad, Angry, Neutral, Calm, etc.
Download the images and put them in corresponding folders for training purpose, now follow this code.
## This program first ensures if the face of a person exists in the given image or
not then if it exists, it crops
## the image of the face and saves to the given directory.
## Importing Modules
import cv2
import os
directory = "C:\\Users\\hp"
## directory where the images to be saved:
f_directory = "C:\\Users\\hp\\face_data/"
def facecrop(image):
## Crops the face of a person from an image!
## OpenCV XML FILE for Frontal Facial Detection using HAAR CASCADES.
facedata=
"C:\\opencv\\build\\etc\\haarcascades\\haarcascade_frontalface_default.xml"
cascade = cv2.CascadeClassifier(facedata)
## Reading the given Image with OpenCV
img = cv2.imread(image)
try:
minisize = (img.shape[1],img.shape[0])
miniframe = cv2.resize(img, minisize)
faces = cascade.detectMultiScale(miniframe)
for f in faces:
x, y, w, h = [ v for v in f ]
cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)
sub_face = img[y:y+h, x:x+w]
f_name = image.split('/')
f_name = f_name[-1]
## Change here the Desired directory.
cv2.imwrite(f_directory + f_name, sub_face)
print ("Writing: " + image)
except:
pass
if __name__ == '__main__':
images = os.listdir(directory)
i = 0
for img in images:
file = directory + img
print (i)
facecrop(file)
i += 1
I am trying to horizontally combine some JPEG images in Python.
Problem
I have 3 images - each is 148 x 95 - see attached. I just made 3 copies of the same image - that is why they are the same.
My attempt
I am trying to horizontally join them using the following code:
import sys
from PIL import Image
list_im = ['Test1.jpg','Test2.jpg','Test3.jpg']
# creates a new empty image, RGB mode, and size 444 by 95
new_im = Image.new('RGB', (444,95))
for elem in list_im:
for i in xrange(0,444,95):
im=Image.open(elem)
new_im.paste(im, (i,0))
new_im.save('test.jpg')
However, this is producing the output attached as test.jpg.
Question
Is there a way to horizontally concatenate these images such that the sub-images in test.jpg do not have an extra partial image showing?
Additional Information
I am looking for a way to horizontally concatenate n images. I would like to use this code generally so I would prefer to:
not to hard-code image dimensions, if possible
specify dimensions in one line so that they can be easily changed
You can do something like this:
import sys
from PIL import Image
images = [Image.open(x) for x in ['Test1.jpg', 'Test2.jpg', 'Test3.jpg']]
widths, heights = zip(*(i.size for i in images))
total_width = sum(widths)
max_height = max(heights)
new_im = Image.new('RGB', (total_width, max_height))
x_offset = 0
for im in images:
new_im.paste(im, (x_offset,0))
x_offset += im.size[0]
new_im.save('test.jpg')
Test1.jpg
Test2.jpg
Test3.jpg
test.jpg
The nested for for i in xrange(0,444,95): is pasting each image 5 times, staggered 95 pixels apart. Each outer loop iteration pasting over the previous.
for elem in list_im:
for i in xrange(0,444,95):
im=Image.open(elem)
new_im.paste(im, (i,0))
new_im.save('new_' + elem + '.jpg')
I would try this:
import numpy as np
import PIL
from PIL import Image
list_im = ['Test1.jpg', 'Test2.jpg', 'Test3.jpg']
imgs = [ Image.open(i) for i in list_im ]
# pick the image which is the smallest, and resize the others to match it (can be arbitrary image shape here)
min_shape = sorted( [(np.sum(i.size), i.size ) for i in imgs])[0][1]
imgs_comb = np.hstack([i.resize(min_shape) for i in imgs])
# save that beautiful picture
imgs_comb = Image.fromarray( imgs_comb)
imgs_comb.save( 'Trifecta.jpg' )
# for a vertical stacking it is simple: use vstack
imgs_comb = np.vstack([i.resize(min_shape) for i in imgs])
imgs_comb = Image.fromarray( imgs_comb)
imgs_comb.save( 'Trifecta_vertical.jpg' )
It should work as long as all images are of the same variety (all RGB, all RGBA, or all grayscale). It shouldn't be difficult to ensure this is the case with a few more lines of code. Here are my example images, and the result:
Test1.jpg
Test2.jpg
Test3.jpg
Trifecta.jpg:
Trifecta_vertical.jpg
Edit: DTing's answer is more applicable to your question since it uses PIL, but I'll leave this up in case you want to know how to do it in numpy.
Here is a numpy/matplotlib solution that should work for N images (only color images) of any size/shape.
import numpy as np
import matplotlib.pyplot as plt
def concat_images(imga, imgb):
"""
Combines two color image ndarrays side-by-side.
"""
ha,wa = imga.shape[:2]
hb,wb = imgb.shape[:2]
max_height = np.max([ha, hb])
total_width = wa+wb
new_img = np.zeros(shape=(max_height, total_width, 3))
new_img[:ha,:wa]=imga
new_img[:hb,wa:wa+wb]=imgb
return new_img
def concat_n_images(image_path_list):
"""
Combines N color images from a list of image paths.
"""
output = None
for i, img_path in enumerate(image_path_list):
img = plt.imread(img_path)[:,:,:3]
if i==0:
output = img
else:
output = concat_images(output, img)
return output
Here is example use:
>>> images = ["ronda.jpeg", "rhod.jpeg", "ronda.jpeg", "rhod.jpeg"]
>>> output = concat_n_images(images)
>>> import matplotlib.pyplot as plt
>>> plt.imshow(output)
>>> plt.show()
Here is a function generalizing previous approaches, creating a grid of images in PIL:
from PIL import Image
import numpy as np
def pil_grid(images, max_horiz=np.iinfo(int).max):
n_images = len(images)
n_horiz = min(n_images, max_horiz)
h_sizes, v_sizes = [0] * n_horiz, [0] * (n_images // n_horiz)
for i, im in enumerate(images):
h, v = i % n_horiz, i // n_horiz
h_sizes[h] = max(h_sizes[h], im.size[0])
v_sizes[v] = max(v_sizes[v], im.size[1])
h_sizes, v_sizes = np.cumsum([0] + h_sizes), np.cumsum([0] + v_sizes)
im_grid = Image.new('RGB', (h_sizes[-1], v_sizes[-1]), color='white')
for i, im in enumerate(images):
im_grid.paste(im, (h_sizes[i % n_horiz], v_sizes[i // n_horiz]))
return im_grid
It will shrink each row and columns of the grid to the minimum. You can have only a row by using pil_grid(images), or only a column by using pil_grid(images, 1).
One benefit of using PIL over numpy-array based solutions is that you can deal with images structured differently (like grayscale or palette-based images).
Example outputs
def dummy(w, h):
"Produces a dummy PIL image of given dimensions"
from PIL import ImageDraw
im = Image.new('RGB', (w, h), color=tuple((np.random.rand(3) * 255).astype(np.uint8)))
draw = ImageDraw.Draw(im)
points = [(i, j) for i in (0, im.size[0]) for j in (0, im.size[1])]
for i in range(len(points) - 1):
for j in range(i+1, len(points)):
draw.line(points[i] + points[j], fill='black', width=2)
return im
dummy_images = [dummy(20 + np.random.randint(30), 20 + np.random.randint(30)) for _ in range(10)]
pil_grid(dummy_images):
pil_grid(dummy_images, 3):
pil_grid(dummy_images, 1):
Based on DTing's answer I created a function that is easier to use:
from PIL import Image
def append_images(images, direction='horizontal',
bg_color=(255,255,255), aligment='center'):
"""
Appends images in horizontal/vertical direction.
Args:
images: List of PIL images
direction: direction of concatenation, 'horizontal' or 'vertical'
bg_color: Background color (default: white)
aligment: alignment mode if images need padding;
'left', 'right', 'top', 'bottom', or 'center'
Returns:
Concatenated image as a new PIL image object.
"""
widths, heights = zip(*(i.size for i in images))
if direction=='horizontal':
new_width = sum(widths)
new_height = max(heights)
else:
new_width = max(widths)
new_height = sum(heights)
new_im = Image.new('RGB', (new_width, new_height), color=bg_color)
offset = 0
for im in images:
if direction=='horizontal':
y = 0
if aligment == 'center':
y = int((new_height - im.size[1])/2)
elif aligment == 'bottom':
y = new_height - im.size[1]
new_im.paste(im, (offset, y))
offset += im.size[0]
else:
x = 0
if aligment == 'center':
x = int((new_width - im.size[0])/2)
elif aligment == 'right':
x = new_width - im.size[0]
new_im.paste(im, (x, offset))
offset += im.size[1]
return new_im
It allows choosing a background color and image alignment. It's also easy to do recursion:
images = map(Image.open, ['hummingbird.jpg', 'tiger.jpg', 'monarch.png'])
combo_1 = append_images(images, direction='horizontal')
combo_2 = append_images(images, direction='horizontal', aligment='top',
bg_color=(220, 140, 60))
combo_3 = append_images([combo_1, combo_2], direction='vertical')
combo_3.save('combo_3.png')
If all image's heights are same,
import numpy as np
imgs = ['a.jpg', 'b.jp', 'c.jpg']
concatenated = Image.fromarray(
np.concatenate(
[np.array(Image.open(x)) for x in imgs],
axis=1
)
)
Maybe you can resize images before the concatenation like this,
import numpy as np
imgs = ['a.jpg', 'b.jpg', 'c.jpg']
concatenated = Image.fromarray(
np.concatenate(
[np.array(Image.open(x).resize((640,480)) for x in imgs],
axis=1
)
)
Here's my solution:
from PIL import Image
def join_images(*rows, bg_color=(0, 0, 0, 0), alignment=(0.5, 0.5)):
rows = [
[image.convert('RGBA') for image in row]
for row
in rows
]
heights = [
max(image.height for image in row)
for row
in rows
]
widths = [
max(image.width for image in column)
for column
in zip(*rows)
]
tmp = Image.new(
'RGBA',
size=(sum(widths), sum(heights)),
color=bg_color
)
for i, row in enumerate(rows):
for j, image in enumerate(row):
y = sum(heights[:i]) + int((heights[i] - image.height) * alignment[1])
x = sum(widths[:j]) + int((widths[j] - image.width) * alignment[0])
tmp.paste(image, (x, y))
return tmp
def join_images_horizontally(*row, bg_color=(0, 0, 0), alignment=(0.5, 0.5)):
return join_images(
row,
bg_color=bg_color,
alignment=alignment
)
def join_images_vertically(*column, bg_color=(0, 0, 0), alignment=(0.5, 0.5)):
return join_images(
*[[image] for image in column],
bg_color=bg_color,
alignment=alignment
)
For these images:
images = [
[Image.open('banana.png'), Image.open('apple.png')],
[Image.open('lime.png'), Image.open('lemon.png')],
]
Results will look like:
join_images(
*images,
bg_color='green',
alignment=(0.5, 0.5)
).show()
join_images(
*images,
bg_color='green',
alignment=(0, 0)
).show()
join_images(
*images,
bg_color='green',
alignment=(1, 1)
).show()
There is also skimage.util.montage to create a montage of images of the same shape:
import numpy as np
import PIL
from PIL import Image
from skimage.util import montage
list_im = ['Test1.jpg', 'Test2.jpg', 'Test3.jpg']
imgs = [ np.array(Image.open(i)) for i in list_im ]
montage(imgs)
"""
merge_image takes three parameters first two parameters specify
the two images to be merged and third parameter i.e. vertically
is a boolean type which if True merges images vertically
and finally saves and returns the file_name
"""
def merge_image(img1, img2, vertically):
images = list(map(Image.open, [img1, img2]))
widths, heights = zip(*(i.size for i in images))
if vertically:
max_width = max(widths)
total_height = sum(heights)
new_im = Image.new('RGB', (max_width, total_height))
y_offset = 0
for im in images:
new_im.paste(im, (0, y_offset))
y_offset += im.size[1]
else:
total_width = sum(widths)
max_height = max(heights)
new_im = Image.new('RGB', (total_width, max_height))
x_offset = 0
for im in images:
new_im.paste(im, (x_offset, 0))
x_offset += im.size[0]
new_im.save('test.jpg')
return 'test.jpg'
from __future__ import print_function
import os
from pil import Image
files = [
'1.png',
'2.png',
'3.png',
'4.png']
result = Image.new("RGB", (800, 800))
for index, file in enumerate(files):
path = os.path.expanduser(file)
img = Image.open(path)
img.thumbnail((400, 400), Image.ANTIALIAS)
x = index // 2 * 400
y = index % 2 * 400
w, h = img.size
result.paste(img, (x, y, x + w, y + h))
result.save(os.path.expanduser('output.jpg'))
Output
Just adding to the solutions already suggested. Assumes same height, no resizing.
import sys
import glob
from PIL import Image
Image.MAX_IMAGE_PIXELS = 100000000 # For PIL Image error when handling very large images
imgs = [ Image.open(i) for i in list_im ]
widths, heights = zip(*(i.size for i in imgs))
total_width = sum(widths)
max_height = max(heights)
new_im = Image.new('RGB', (total_width, max_height))
# Place first image
new_im.paste(imgs[0],(0,0))
# Iteratively append images in list horizontally
hoffset=0
for i in range(1,len(imgs),1):
**hoffset=imgs[i-1].size[0]+hoffset # update offset**
new_im.paste(imgs[i],**(hoffset,0)**)
new_im.save('output_horizontal_montage.jpg')
my solution would be :
import sys
import os
from PIL import Image, ImageFilter
from PIL import ImageFont
from PIL import ImageDraw
os.chdir('C:/Users/Sidik/Desktop/setup')
print(os.getcwd())
image_list= ['IMG_7292.jpg','IMG_7293.jpg','IMG_7294.jpg', 'IMG_7295.jpg' ]
image = [Image.open(x) for x in image_list] # list
im_1 = image[0].rotate(270)
im_2 = image[1].rotate(270)
im_3 = image[2].rotate(270)
#im_4 = image[3].rotate(270)
height = image[0].size[0]
width = image[0].size[1]
# Create an empty white image frame
new_im = Image.new('RGB',(height*2,width*2),(255,255,255))
new_im.paste(im_1,(0,0))
new_im.paste(im_2,(height,0))
new_im.paste(im_3,(0,width))
new_im.paste(im_4,(height,width))
draw = ImageDraw.Draw(new_im)
font = ImageFont.truetype('arial',200)
draw.text((0, 0), '(a)', fill='white', font=font)
draw.text((height, 0), '(b)', fill='white', font=font)
draw.text((0, width), '(c)', fill='white', font=font)
#draw.text((height, width), '(d)', fill='white', font=font)
new_im.show()
new_im.save('BS1319.pdf')
[![Laser spots on the edge][1]][1]
#**How to merge cropped images back to original image**
images = [Image.open(x) for x in images_list]
print("Length:: ", len(images))
widths, heights = zip(*(i.size for i in images))
print(widths, heights)
total_width = sum(widths)
max_height = sum(heights)
print(total_width,max_height)
new_im = Image.new('RGB', (5*384, 5*216))
x_offset = 0
y_offset = 0
img_size = [384,216]
def grouped(iterable, n):
return zip(*[iter(iterable)]*n)
for x,y,a,b,c in grouped(images, 5):
temp = []
temp.append([x,y,a,b,c])
print(temp[0])
print(len(temp[0]))
for lsingle_img in temp[0]:
# print(lsingle_img)
print("x_y_offset: ", (x_offset, y_offset))
new_im.paste(lsingle_img, (x_offset, y_offset))
x_offset += img_size[0]
temp = []
x_offset = 0
y_offset += img_size[1]
new_im.save('test.jpg')