python - 如何将用于创建单个图像的随机选择图像的文件名附加到 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.png
from mediumcircle/
,循环 2 使用bigcircle3.png
and mediumcircle2.png
,依此类推。在此循环结束时,data.csv
文件将读取:
Filename,bigcircle,mediumcircle
image 0,bigcircle1.png,mediumcircle6.png
image 1,bigcircle3.png,mediumcircle2.png
我尝试了以下方法,我知道它不会给出想要的结果,但我认为这可能是我运行和调整直到正确的一个好的开始,但它不会产生任何输出(我正在导入numpy
为np
):
np.savetxt('data.csv', [p for p in zip(img, layer)], delimiter=',', fmt='%s')
如果不是太多要求,理想情况下,循环的第一次迭代将创建data.csv
并存储第一条记录,然后第二次迭代将附加此文件。
解决方案
又是我 ;)
我认为将程序的功能拆分为单独的功能是有意义的。我可能会从一个名为类似的函数开始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