英文:
How can I use os.walk and PIL to save an edited image in a new directory but with the same subdirectories as in the original source?
问题
我试图使用PIL编辑指定目录(包括子目录)中的所有图像,然后将编辑后的版本保存在不同位置但具有相同的子目录结构下。
例如 输入:
根目录
|
|---------子目录 1
| |---图像_1
| |---图像_2
| |---图像_3
|
|---------子目录 2
| |---图像_1
| |---图像_2
输出:
{指定目录}
|
|---------子目录 1
| |---编辑后的图像_1
| |---编辑后的图像_2
| |---编辑后的图像_3
|
|---------子目录 2
| |---编辑后的图像_1
| |---编辑后的图像_2
子目录具有相同的名称,并在运行os.walk时创建。
我将其构建为一个函数,以便稍后在Linux终端中调用该函数时更改选项。
```python
from PIL import Image, ImageDraw, ImageOps
import os
from os.path import isfile, join
def editimage(image_directory="image_directory",
version="B", #指定要进行哪个版本的ImageDraw编辑
resize=False, #选择是否调整图像大小
new_size=(800,428), #选择新大小
output_directory="output_directory"):
for directory, subdirs, files in os.walk(image_directory):
for dirname in subdirs:
if not os.path.exists(output_directory + dirname):
os.mkdir(output_directory + image_directory + dirname) #这正是我想要的
for directory, subdirs, files in os.walk(image_directory):
for f in files:
if f.endswith('.JPG'):
img = Image.open(directory + f)
draw= ImageDraw.Draw(img)
if version=="A":
draw.ellipse((1823, 1472, 2033, 1536), fill = (0,0,0), outline=None)
draw.rectangle((0, 0, 2048, 32), fill = (0,0,0), outline=None)
draw.rectangle((0, 1504, 2048, 1536), fill = (0,0,0), outline=None)
img=ImageOps.pad(img, size=(2731,1536), color="grey")
elif version=="B":
draw.rectangle((0, 1231, 2304, 1296), fill = (0,0,0), outline=None)
if resize==True:
img = img.resize(new_size)
else:
pass
img.save(output_directory + "/" + f + ".png")
这样用户可以输入:
editimage("输入路径/", version="A", resize= False, output_directory="输出路径/")
我尝试过使用img.save(output_directory + subdirs + ".png"
或为此创建一个变量,但Python返回:TypeError: can only concatenate list (not "str") to list
,或者希望在输出目录中包含输入目录。它似乎没有遍历每个子目录。
我之前使用了
imagelist = [join(directory, f)
for directory, subdirs, files in os.walk(image_directory)
for f in files
if isfile
if f.endswith('.JPG')]
for f in imagelist:
img = Image.open(f) #等等..
来构建读取和编辑图像,但然后img.save(f)
会保留整个路径,并且无法将图像保存到新位置。
函数的其余部分完全正常工作,如果我在img.save行中删除output_directory参数,则会覆盖原始目录(包括子目录)中的图像。直到意识到未使用输出目录时,我没有任何问题。
由于版本A的图像在文件夹之间没有唯一的名称,因此我需要能够重构目录路径。
我该如何修复这个问题?
谢谢!
<details>
<summary>英文:</summary>
I'm trying to edit all images within a specified directory (and subdirs) using PIL, and then save the edited versions in a different location but under the same subdirectory structure.
ie. Input:
Root directory
|
|---------Subdir 1
| |---Image_1
| |---Image_2
| |---Image_3
|
|---------Subdir 2
| |---Image_1
| |---Image_2
And Output:
{Specified directory}
|
|---------Subdir 1
| |---Edited_Image_1
| |---Edited_Image_2
| |---Edited_Image_3
|
|---------Subdir 2
| |---Edited_Image_1
| |---Edited_Image_2
Where the subdirs share same names, and are created when os.walk is run.
I've constructed this as a function so I can later run it in a Linux terminal with options changed upon calling the function.
from PIL import Image, ImageDraw, ImageOps
import os
from os.path import isfile, join
def editimage(image_directory="image_directory",
version="B", #Specify which version of ImageDraw edit to do
resize=False, #choose whether or not to resize image
new_size=(800,428), #choose new size
output_directory="output_directory"):
for directory, subdirs, files in os.walk(image_directory):
for dirname in subdirs:
if not os.path.exists(output_directory + dirname):
os.mkdir(output_directory + image_directory + dirname) #This does exactly what I want it to do
for directory, subdirs, files in os.walk(image_directory):
for f in files:
if f.endswith('.JPG'):
img = Image.open(directory + f)
draw= ImageDraw.Draw(img)
if version=="A":
draw.ellipse((1823, 1472, 2033, 1536), fill = (0,0,0), outline=None)
draw.rectangle((0, 0, 2048, 32), fill = (0,0,0), outline=None)
draw.rectangle((0, 1504, 2048, 1536), fill = (0,0,0), outline=None)
img=ImageOps.pad(img, size=(2731,1536), color="grey")
elif version=="B":
draw.rectangle((0, 1231, 2304, 1296), fill = (0,0,0), outline=None)
if resize==True:
img = img.resize(new_size)
else:
pass
img.save(output_directory + "/" + f + ".png")
This would let the user enter:
editimage("Path/to/input/", version="A", resize= False, output_directory="Path/to/output/")
I've tried using `img.save(output_directory + subdirs + ".png"` or creating a variable for that, but Python returns: `TypeError: can only concatenate list (not "str") to list`, or otherwise wants the input directory within the output directory. It doesn't seem to walk every subdirectory.
I previously used
imagelist = [join(directory, f)
for directory, subdirs, files in os.walk(image_directory)
for f in files
if isfile
if f.endswith('.JPG')]
for f in imagelist:
img = Image.open(f) #etc..
to construct read and edit the images, but then `img.save(f)` keeps the entire path and cannot save the image to a new location.
The rest of the function works perfectly, and will overwrite images within the original directory (and subdirs) if I remove the output_directory argument in the img.save line. I had no issues until realising that the output directory wasn't being used.
Because the version A set of images are not named uniquely between folders, I need to be able to reconstruct the directory paths.
How can I fix this?
Thanks!
</details>
# 答案1
**得分**: 1
以下是代码的翻译部分:
```python
# 导入需要的库
from pathlib import Path
from PIL import Image, ImageDraw
# 定义函数 editimage
def editimage(
image_directory="image_directory",
version="B", # 指定要进行的 ImageDraw 编辑版本
resize=False, # 选择是否调整图像大小
new_size=(800, 428), # 选择新的图像尺寸
output_directory="output_directory",
):
for jpg_file in image_directory.rglob("*.jpg"):
# 将输入文件路径转换为相应的输出文件路径
relative_path = jpg_file.relative_to(image_directory)
output_file_path = output_directory / relative_path
# 如果输出目录不存在,则创建
output_file_path.parent.mkdir(parents=True, exist_ok=True)
# 对图像进行标注并保存(简化示例)
with Image.open(jpg_file) as img:
draw = ImageDraw.Draw(img)
draw.ellipse((0, 0, 300, 300), fill=(255, 0, 0), outline=None)
img.save(output_file_path)
# 调用 editimage 函数
editimage(
image_directory=Path("Path/to/input/"),
version="A",
resize=False,
output_directory=Path("Path/to/output/"),
)
请注意,我已经将代码中的 HTML 实体编码(如 "
)还原为普通的引号。
英文:
The function below will create a new directory for annotated images with the same tree structure as the input directory. I used pathlib
from the core Python library even though you asked how to use os.walk()
. I like its object-oriented methods and find that the code is cleaner. PEP428 provides more detail on the rationale behind pathlib.
from pathlib import Path
from PIL import Image, ImageDraw
def editimage(
image_directory="image_directory",
version="B", # Specify which version of ImageDraw edit to do
resize=False, # choose whether or not to resize image
new_size=(800, 428), # choose new size
output_directory="output_directory",
):
for jpg_file in image_directory.rglob("*.jpg"):
# Translate the input file path to the corresponding output file_path
relative_path = jpg_file.relative_to(image_directory)
output_file_path = output_directory / relative_path
# Create the output directory if it doesn't exist
output_file_path.parent.mkdir(parents=True, exist_ok=True)
# Annotate the image and save it (simplified example)
with Image.open(jpg_file) as img:
draw = ImageDraw.Draw(img)
draw.ellipse((0, 0, 300, 300), fill=(255, 0, 0), outline=None)
img.save(output_file_path)
editimage(
image_directory=Path("Path/to/input/"),
version="A",
resize=False,
output_directory=Path("Path/to/output/"),
)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论