在 PIL 中制作拼贴画

问题描述 投票:0回答:2

我。是。卡住。

我已经为此工作了一个多星期了,但我似乎无法让我的代码正确运行。我对 PIL 和 Python 整体来说还很陌生。我正在尝试制作一些图片的 2x3 拼贴画。下面列出了我的代码。我试图让我的照片适合新创建的拼贴画中的任何访问黑色空间,但是当我运行代码时,我只能将 2 张图片放入拼贴画中,而不是我想要的 6 张图片。任何的意见都将会有帮助。

*代码已编辑

from PIL import Image
im= Image.open('Tulips.jpg')




out=im.convert("RGB", (
    0.412453, 0.357580, 0.180423, 0,
    0.212671, 0.715160, 0.072169, 0,
    0.019334, 0.119193, 0.950227, 0 ))
out.save("Image2" + ".jpg")

out2=im.convert("RGB", (
    0.9756324, 0.154789, 0.180423, 0,
    0.212671, 0.715160, 0.254783, 0,
    0.123456, 0.119193, 0.950227, 0 ))
out2.save("Image3" + ".jpg")



out3= im.convert("1")
out3.save("Image4"+".jpg")


out4=im.convert("RGB", (
    0.986542, 0.154789, 0.756231, 0,
    0.212671, 0.715160, 0.254783, 0,
    0.123456, 0.119193, 0.112348, 0 ))
out4.save("Image5" + ".jpg")


out5=Image.blend(im, out4, 0.5)
out5.save("Image6" + ".jpg")

listofimages=['Tulips.jpg', 'Image2.jpg', 'Image3.jpg', 'Image4.jpg', 'Image5.jpg', 'Image6.jpg']

def create_collage(width, height, listofimages):
    Picturewidth=width//3
    Pictureheight=height//2
    size=Picturewidth, Pictureheight
    new_im=Image.new('RGB', (450, 300))
    for p in listofimages:
        Image.open(p)
    for col in range(0,width):
        for row in range(0, height):
                image=Image.eval(p, lambda x: x+(col+row)/30)
                new_im.paste(p, (col,row))
                new_im.save("Collage"+".jpg")

create_collage(450,300,listofimages)
python image python-imaging-library copy-paste
2个回答
15
投票

这是一些工作代码。

  1. 当您调用

    Image.open(p)
    时,会返回一个 Image 对象,因此您需要将其存储在变量中:
    im = Image.open(p)

  2. 我不确定

    image=Image.eval(p, lambda x: x+(col+row)/30)
    的含义,所以我将其删除了。

  3. size
    是缩略图的大小,但您没有使用该变量。打开图像后,应将其大小调整为
    size

  4. 我将Picturewidth和Pictureheight重命名为thumbnail_width和thumbnail_height,以明确它们是什么并遵循Python命名约定。

  5. 我还将列数和行数移至变量中,以便可以在没有幻数的情况下重复使用它们。

  6. 第一个循环将每个图像打开为

    im
    ,对其进行缩略图并将其放入
    ims
    列表中。

  7. 在下一个循环之前,我们初始化

    i,
    x
    , and
    y` 变量来跟踪我们正在查看的图像,以及将缩略图粘贴到更大画布中的 x 和 y 坐标。它们将在下一个循环中更新。

  8. 第一个循环针对列 (

    cols
    ),而不是像素 (
    width
    )。 (
    range(0, thing)
    range(thing)
    的作用相同。)

  9. 类似地,第二个循环是针对行而不是像素。在这个循环中,我们将

    ims[i]
    处的当前图像粘贴到
    new_im
    处的大
    x, y
    中。这些是像素位置,而不是行/列位置。

  10. 在内循环结束时,增加

    i
    计数器,并将
    thumbnail_height
    添加到
    y

  11. 类似地,在外循环结束时,将

    thumnnail_width
    添加到
    x
    并将
    y
    重置为零。

  12. 这些循环完成后,您只需保存

    new_im
    一次。

  13. 无需连接

    "Image2" + ".jpg"
    等,只需执行“Image2.jpg”即可。

这会导致这样的结果:

这段代码还可以改进。例如,如果您不需要它们做其他任何事情,则无需保存中间 ImageX.jpg 文件,并且不要将这些文件名放在

listofimages
中,而是将图像直接放在那里:
listofimages = [im, out1, out2, etc...]
,然后替换
for p in listofimages:
for im in listofimages:
并移除
im = Image.open(p)

您还可以计算图像的一些填充,使黑色空间均匀。

from PIL import Image
im= Image.open('Tulips.jpg')

out=im.convert("RGB", (
    0.412453, 0.357580, 0.180423, 0,
    0.212671, 0.715160, 0.072169, 0,
    0.019334, 0.119193, 0.950227, 0 ))
out.save("Image2.jpg")

out2=im.convert("RGB", (
    0.9756324, 0.154789, 0.180423, 0,
    0.212671, 0.715160, 0.254783, 0,
    0.123456, 0.119193, 0.950227, 0 ))
out2.save("Image3.jpg")

out3= im.convert("1")
out3.save("Image4.jpg")

out4=im.convert("RGB", (
    0.986542, 0.154789, 0.756231, 0,
    0.212671, 0.715160, 0.254783, 0,
    0.123456, 0.119193, 0.112348, 0 ))
out4.save("Image5.jpg")

out5=Image.blend(im, out4, 0.5)
out5.save("Image6.jpg")

listofimages=['Tulips.jpg', 'Image2.jpg', 'Image3.jpg', 'Image4.jpg', 'Image5.jpg', 'Image6.jpg']

def create_collage(width, height, listofimages):
    cols = 3
    rows = 2
    thumbnail_width = width//cols
    thumbnail_height = height//rows
    size = thumbnail_width, thumbnail_height
    new_im = Image.new('RGB', (width, height))
    ims = []
    for p in listofimages:
        im = Image.open(p)
        im.thumbnail(size)
        ims.append(im)
    i = 0
    x = 0
    y = 0
    for col in range(cols):
        for row in range(rows):
            print(i, x, y)
            new_im.paste(ims[i], (x, y))
            i += 1
            y += thumbnail_height
        x += thumbnail_width
        y = 0

    new_im.save("Collage.jpg")

create_collage(450, 300, listofimages)

1
投票

我做了一个受@Hugo的答案启发的解决方案,它只需要输入图像列表。该功能会根据输入的图像数量自动创建网格。

import os
from typing import List, Tuple

from PIL import Image


def find_multiples(number : int):
    multiples = set()
    for i in range(number - 1, 1, -1):
        mod = number % i
        if mod == 0:
            tup = (i, int(number / i))
            if tup not in multiples and (tup[1], tup[0]) not in multiples:
                multiples.add(tup)
                
    if len(multiples) == 0:
        mod == number % 2
        div = number // 2
        multiples.add((2, div + mod))
        
    return list(multiples)

def get_smallest_multiples(number : int, smallest_first = True) -> Tuple[int, int]:
    multiples = find_multiples(number)
    smallest_sum = number
    index = 0
    for i, m in enumerate(multiples):
        sum = m[0] + m[1]
        if sum < smallest_sum:
            smallest_sum = sum
            index = i
            
    result = list(multiples[i])
    if smallest_first:
        result.sort()
        
    return result[0], result[1]
    

def create_collage(listofimages : List[str], n_cols : int = 0, n_rows: int = 0, 
                   thumbnail_scale : float = 1.0, thumbnail_width : int = 0, thumbnail_height : int = 0):
    
    n_cols = n_cols if n_cols >= 0 else abs(n_cols)
    n_rows = n_rows if n_rows >= 0 else abs(n_rows)
    
    if n_cols == 0 and n_rows != 0:
        n_cols = len(listofimages) // n_rows
        
    if n_rows == 0 and n_cols != 0:
        n_rows = len(listofimages) // n_cols
        
    if n_rows == 0 and n_cols == 0:
        n_cols, n_rows = get_smallest_multiples(len(listofimages))
    
    thumbnail_width = 0 if thumbnail_width == 0 or n_cols == 0 else round(thumbnail_width / n_cols)
    thumbnail_height = 0 if thumbnail_height == 0 or n_rows == 0 else round(thumbnail_height/n_rows)
    
    all_thumbnails : List[Image.Image] = []
    for p in listofimages:
        thumbnail = Image.open(p)
        if thumbnail_width * thumbnail_scale < thumbnail.width:
            thumbnail_width = round(thumbnail.width * thumbnail_scale)
        if thumbnail_height * thumbnail_scale < thumbnail.height:
            thumbnail_height = round(thumbnail.height * thumbnail_scale)
        
        thumbnail.thumbnail((thumbnail_width, thumbnail_height))
        all_thumbnails.append(thumbnail)

    new_im = Image.new('RGB', (thumbnail_width * n_cols, thumbnail_height * n_rows), 'white')
    
    i, x, y = 0, 0, 0
    for col in range(n_cols):
        for row in range(n_rows):
            if i > len(all_thumbnails) - 1:
                continue
            
            print(i, x, y)
            new_im.paste(all_thumbnails[i], (x, y))
            i += 1
            y += thumbnail_height
        x += thumbnail_width
        y = 0

    extension = os.path.splitext(listofimages[0])[1]
    if extension == "":
        extension = ".jpg"
    destination_file = os.path.join(os.path.dirname(listofimages[0]), f"Collage{extension}")
    new_im.save(destination_file)

使用示例:

listofimages=['Tulips.jpg', 'Image2.jpg', 'Image3.jpg', 'Image4.jpg', 'Image5.jpg', 'Image6.jpg']
create_collage(listofimages)

在本例中,由于输入图像为 6 个,因此该函数返回 3x2(3 行,2 列)图像拼贴画。

为此,该函数找到图形输入列表长度的两个最小整数倍(例如,对于 12,它返回 3 和 4,而不是 2 和 6)并创建一个网格,其中第一个数字始终是最小的倍数,它被视为列数(即默认情况下,网格的列数少于行数;对于 12 个图像,您将得到一个 4x3 矩阵:4 行,3 列)。可以通过

smallest_first
参数进行自定义(仅在
get_smallest_multiples()
中公开)。
可选参数还允许强制多个行/列。

最终图像大小是单个图像大小的总和,但可选的

thumbnail_scale
参数允许指定所有缩略图的缩放百分比(默认为 1.0,即 100%,不缩放)。

当图像大小大致相同时,此功能效果很好。我没有涵盖更复杂的场景。

© www.soinside.com 2019 - 2024. All rights reserved.