首页 > 解决方案 > 如何将用于创建单个图像的随机选择图像的文件名附加到 csv 文件?

问题描述

非常感谢 Paul M,他发布了以下代码,以回应我关于如何将随机选择的图像“堆栈”编译成唯一图像的第一个问题:

from pathlib import Path
from random import choice

layers = [list(Path(directory).glob("*.png")) for directory in ("bigcircle/", "mediumcircle/")]

selected_paths = [choice(paths) for paths in layers]

img = Image.new("RGB", (4961, 4961), color=(0, 220, 15))
for path in selected_paths:
    layer = Image.open(str(path), "r")
    img.paste(layer, (0, 0), layer)

我将代码for _ in itertools.repeat(None, num):放在num定义正在生成的不同图像数量的位置。我用以下内容结束循环,以使用唯一(增量)文件名保存每个图像:

i = 0
while os.path.exists("Finished Pieces/image %s.png" % i):
    i += 1
img.save("Finished Pieces/image %s.png" % i,)

到现在为止还挺好。我现在面临的挑战是如何将data.csv创建的每个图像的详细信息附加到文件中。

例如,在循环 1bigcircle1.png中选择 from bigcircle/folder and mediumcircle6.pngfrom mediumcircle/,循环 2 使用bigcircle3.pngand mediumcircle2.png,依此类推。在此循环结束时,data.csv文件将读取:

Filename,bigcircle,mediumcircle
image 0,bigcircle1.png,mediumcircle6.png
image 1,bigcircle3.png,mediumcircle2.png

我尝试了以下方法,我知道它不会给出想要的结果,但我认为这可能是我运行和调整直到正确的一个好的开始,但它不会产生任何输出(我正在导入numpynp):

np.savetxt('data.csv', [p for p in zip(img, layer)], delimiter=',', fmt='%s')

如果不是太多要求,理想情况下,循环的第一次迭代将创建data.csv并存储第一条记录,然后第二次迭代将附加此文件。

标签: pythonimagenumpycsv

解决方案


又是我 ;)

我认为将程序的功能拆分为单独的功能是有意义的。我可能会从一个名为类似的函数开始discover_image_paths,它发现(通过glob)所有图像路径。根据它们代表的圆圈类型来存储路径可能是有意义的 - 我正在设想一个带有"big""medium"键的字典,以及作为关联值的路径列表:

def discover_image_paths():
    from pathlib import Path
    keys = ("bigcircle", "mediumcircle")
    return dict(zip(keys, (list(Path(directory).glob("*.png")) for directory in (key+"/" for key in keys))))


def main():

    global paths

    paths = discover_image_paths()
    
    return 0


if __name__ == "__main__":
    import sys
    sys.exit(main())

在终端:

>>> paths["bigcircle"]
[WindowsPath('bigcircle/big1.png'), WindowsPath('bigcircle/big2.png'), WindowsPath('bigcircle/big3.png')]
>>> paths["mediumcircle"]
[WindowsPath('mediumcircle/med1.png'), WindowsPath('mediumcircle/med2.png'), WindowsPath('mediumcircle/med3.png')]
>>> 

如您所见,为了测试脚本,我创建了一些虚拟图像文件 - 每个类别三个。

通过添加一个生成输出图像的函数(给定要组合的可迭代路径和输出文件名)和一个生成num_images图像数量的主循环来扩展它(对不起,我不熟悉 numpy):

def generate_image(paths, color, output_filename):
    from PIL import Image

    dimensions = (4961, 4961)

    image = Image.new("RGB", dimensions, color=color)
    for path in paths:
        layer = Image.open(path, "r")
        image.paste(layer, (0, 0), layer)
    image.save(output_filename)

def discover_image_paths(keys):
    from pathlib import Path
    return dict(zip(keys, (list(Path(directory).glob("*.png")) for directory in (key+"/" for key in keys))))

def main():

    from random import choice, choices
    from csv import DictWriter

    field_names = ["filename", "color"]
    keys = ["bigcircle", "mediumcircle"]
    paths = discover_image_paths(keys)

    num_images = 5

    with open("data.csv", "w", newline="") as file:
        writer = DictWriter(file, fieldnames=field_names+keys)
        writer.writeheader()

        for image_no in range(1, num_images + 1):
            selected_paths = {key: choice(category_paths) for key, category_paths in paths.items()}
            file_name = "output_{}.png".format(image_no)

            color = tuple(choices(range(0, 256), k=3))
            
            generate_image(map(str, selected_paths.values()), color, file_name)

            row = {**dict(zip(field_names, [file_name, color])), **{key: path.name for key, path in selected_paths.items()}}

            writer.writerow(row)

    return 0


if __name__ == "__main__":
    import sys
    sys.exit(main())

CSV 中的示例输出:

filename,color,bigcircle,mediumcircle
output_1.png,"(49, 100, 190)",big3.png,med1.png
output_2.png,"(228, 37, 227)",big2.png,med3.png
output_3.png,"(251, 14, 193)",big1.png,med1.png
output_4.png,"(35, 12, 196)",big1.png,med3.png
output_5.png,"(62, 192, 170)",big2.png,med2.png


推荐阅读