Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/solr/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Python水平组合多个图像_Python_Python 3.x_Python Imaging Library_Python 2.x_Paste - Fatal编程技术网

使用Python水平组合多个图像

使用Python水平组合多个图像,python,python-3.x,python-imaging-library,python-2.x,paste,Python,Python 3.x,Python Imaging Library,Python 2.x,Paste,我试图在Python中水平组合一些JPEG图像 问题 我有3张图片-每张是148 x 95-见附件。我刚刚复制了3张相同的图片,这就是为什么它们是一样的 我的尝试 我尝试使用以下代码水平连接它们: 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 =

我试图在Python中水平组合一些JPEG图像

问题 我有3张图片-每张是148 x 95-见附件。我刚刚复制了3张相同的图片,这就是为什么它们是一样的

我的尝试 我尝试使用以下代码水平连接它们:

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')
但是,这将生成附加为
test.jpg
的输出

问题: 是否有方法水平连接这些图像,以便test.jpg中的子图像不会显示额外的部分图像

补充资料 我正在寻找一种水平连接n个图像的方法。我希望一般使用此代码,因此我更愿意:

  • 如果可能,不要硬编码图像尺寸
  • 在一行中指定尺寸,以便易于更改

您可以这样做:

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


xrange(0444,95)中i的嵌套for
将每个图像粘贴5次,间隔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('new_' + elem + '.jpg')

编辑:DTing的答案更适用于您的问题,因为它使用PIL,但如果您想知道如何使用numpy,我将保留此选项

这里是一个numpy/matplotlib解决方案,它应该适用于任意大小/形状的N个图像(仅彩色图像)

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
以下是使用示例:

>>> images = ["ronda.jpeg", "rhod.jpeg", "ronda.jpeg", "rhod.jpeg"]
>>> output = concat_n_images(images)
>>> import matplotlib.pyplot as plt
>>> plt.imshow(output)
>>> plt.show()
我想试试这个:

import numpy as np
import PIL
from PIL import Image

list_im = ['Test1.jpg', 'Test2.jpg', 'Test3.jpg']
imgs    = [ PIL.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( (np.asarray( i.resize(min_shape) ) for i in imgs ) )

# save that beautiful picture
imgs_comb = PIL.Image.fromarray( imgs_comb)
imgs_comb.save( 'Trifecta.jpg' )    

# for a vertical stacking it is simple: use vstack
imgs_comb = np.vstack( (np.asarray( i.resize(min_shape) ) for i in imgs ) )
imgs_comb = PIL.Image.fromarray( imgs_comb)
imgs_comb.save( 'Trifecta_vertical.jpg' )
只要所有图像具有相同的种类(所有RGB、所有RGBA或所有灰度),它就可以工作。如果再多写几行代码,就不难做到这一点。以下是我的示例图像和结果:

Test1.jpg

Test2.jpg

Test3.jpg

Trifecta.jpg:

Trifecta_vertical.jpg

根据DTing的回答,我创建了一个更易于使用的函数:

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
它允许选择背景颜色和图像对齐。递归也很容易:

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')

以下是一个函数,概括了以前的方法,在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
它将网格的每一行和每一列收缩到最小。使用pil_网格(图像)只能有一行,使用pil_网格(图像,1)只能有一列

使用基于PIL而非numpy阵列的解决方案的一个好处是,您可以处理不同结构的图像(如灰度或基于调色板的图像)

示例输出

pil\u网格(虚拟图像)

pil\u网格(虚拟图像,3)

pil\u网格(虚拟图像,1)


只是添加到已经建议的解决方案中。假定高度相同,不调整大小

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')

输出
如果所有图像的高度都相同

imgs = [‘a.jpg’, ‘b.jpg’, ‘c.jpg’]
concatenated = Image.fromarray(
  np.concatenate(
    [np.array(Image.open(x)) for x in imgs],
    axis=1
  )
)
也许你可以像这样在连接之前调整图像的大小

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
  )
)
以下是我的解决方案:

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
    )
对于这些图像:

images = [
    [Image.open('banana.png'), Image.open('apple.png')],
    [Image.open('lime.png'), Image.open('lemon.png')],
]
结果如下所示:




我的解决方案是:

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]

为什么在您的代码中有xrange(…)中i的
paste
是否应该处理您指定的三个图像文件?问题,您的图像是否总是相同大小?dermen的可能副本:是的,图像总是相同大小。msw:我不知道如何循环浏览图片,而不在图片之间留下空白-我的方法可能不是最好的使用方法。两个问题:1
x_offset=0
-这是图像中心之间的参差吗?2.对于垂直连接,您的方法如何更改?粘贴的第二个参数是框。“box参数要么是一个给出左上角的2元组,要么是一个定义左、上、右和下像素坐标的4元组,要么是无(与(0,0)相同)。”因此在2元组中,我们使用
x_offset
作为
left
。对于垂直concat,跟踪
y偏移
,或
顶部
。不要使用
sum(widths)
max(height)
,而是使用
sum(height)
max(widths)
并使用二元组框的第二个参数。通过
im.size[1]
增加
y\u偏移量
。很好的解决方案。请注意,在python3中,映射只能迭代一次,因此在第二次迭代图像之前,您必须再次执行images=map(Image.open,Image_文件)。Jaijaba I还遇到了您描述的问题,因此,我编辑了DTing的解决方案,使用列表理解而不是地图。我必须使用列表理解而不是python3.6Your
output=concat\u图像中的
map
(输出,
是我开始寻找的方法。谢谢。嗨,BallsatBallsdotball,我有一个关于你答案的问题。如果我想为每个子图像添加子标题,怎么做?谢谢。非常感谢。另一个很好的答案。如何
min_shape=…
imgs_comb…
c挂起进行垂直连接?你能在这里发表评论吗?或者在你的回复中?对于垂直连接,将
hstack
更改为
vstack
。还有一个问题:你的第一张图片(Test1.jpg)比其他图片大。在你的最终图片(水平或垂直)连接的图像,所有图像的大小都相同。您能解释一下在连接第一个图像之前如何收缩它吗?我使用了PIL中的
image.resize
min\u shape
是一个元组(min\u width,min\u height),然后是
(np.asarray(I.resize(min\u shape))表示imgs中的I)
会将所有图像缩小到该大小。事实上,
min\u shape
可以是任何
(宽度、高度)
如果您愿意,请记住,放大低分辨率图像会使图像模糊!如果您希望在没有任何细节的情况下将图像组合在一起,这可能是这里最简单、最灵活的答案。这可以解释不同的图像大小、任何图像以及不同的图像
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
    )
images = [
    [Image.open('banana.png'), Image.open('apple.png')],
    [Image.open('lime.png'), Image.open('lemon.png')],
]
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()
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]