我正在处理约50MB(约19000像素x 25500像素)的图像文件,并将它们裁剪为4705像素x 8375像素的图像。我编写了一个for循环,该循环遍历了95张图像的文件夹。在大多数情况下,裁剪效果很好,但是在随机图像上,当代码裁剪图像时,其子图像将显示为空白图像。发生这种情况时,12张图像中的第一张将正常显示(正确裁剪),而其余11张图像将空白显示。如果没有发生此问题,则可以正确裁剪所有12张图像。
我正在MBP 10.14.5上的Spyder 3.3.4上运行代码。 PIL是版本1.1.7和Python 3.6。我检查过我是否在图像之间正确循环。重新运行失败的图像(裁剪不正确),当我在其上裁剪而不是for循环的一部分时,它们可以正常工作。
stepCounter = 4705
for folder in os.listdir(location):
if folder == "MyFolder":
for file in os.listdir(location+folder):
resetCounter = -8375
for i in range(12):
print("Iteration", i, " on file", file)
if i%4 == 0:
resetCounter += 8375
left = 0
top = 0 + resetCounter
right = 4705
bottom = 8375 + resetCounter
fileLocation = location + folder + "/" + file
newLocation = location + folder + "/" + file[:-4] + str(i+1) + ".jpg"
img = Image.open(fileLocation)
img = img.crop((left, top, right, bottom))
img.save(newLocation)
img.close()
else:
left = left + stepCounter
top = top
right = right + stepCounter
bottom = bottom
fileLocation = location + folder + "/" + file
newLocation = location + folder + "/" + file[:-4] + str(i+1) + ".jpg"
img = Image.open(fileLocation)
img = img.crop((left, top, right, bottom))
img.save(newLocation)
img.close()
else:
print("Skipping", folder)
我再次希望这些图像是较大图像的子图像,而不是空白图像。不知道这是内存问题还是其他与代码无关的问题。
答案 0 :(得分:1)
从看程序很难分辨- 如果每个图像都像您所描述的那样,它将正常工作-但是,您的代码 用于命名目标图像的程序没有使用防错的编程模式,因为它们没有充分利用某些语言工具的优势。该代码现在可以运行,但是可能要经过反复试验才能到达那里。所以,我敢打赌,在某个时间点, 该脚本已运行,在生成 目标切片文件。此运行确实覆盖了一些图像,这些图像现在是 单个切片的大小。
实际上,如果在PIL图像对象上超出图像像素大小的地方调用crop
方法,则不会出现错误:会自动创建一个零位(黑色)图像。
您没有提及,但是如果您要检查切片的图像 现在失败了,原因是您的原件可能已经裁切成较小的尺寸。
此外,由于不会检查要裁剪的 张图像,因此,如果您多次运行此代码,则已保存的裁剪图像将再次被处理为大图像。
>也就是说,在此脚本的第一次运行中,将保存一个“ image.jpg”并通过“ image12.jpg”将其裁剪为“ image1.jpg”-但是在第二次运行中,将分别使用这些“ imageN”。 jpg”将变为“ imageNM.jpg”-“ M”再次从“ 1”变为“ 12”。同样,第一次运行的“ image11.jpg”和“ image12.jpg”的第11和第12张图像将替换为第二次运行的第一和第二输出。
因此,如果您仍可以使用25500 x 19000像素的图像还原原始文件夹,并且只有这些像素,则可以运行此代码的重构版本,以确保不重新处理已制成的切片。一次检查图像宽度可以避免这种情况,并且更明确的命名架构也可能更好。
此外,作为一些编码建议:
pathlib.Path
来操纵文件夹名称并获取图像文件(这是Python 3.5的新功能,并且周围有稀疏的示例),由于图像较大,您还有可能确实遇到了PIL中的错误,并且第二次以后无法加载大图像-但这不太可能。与此相关的问题宁可通过MemoryError停止程序。
import pathlib
from PIL import Image
# Whatever code you have to get the "location" variable
...
x_step = 8375
y_step = 4705
full_width = 25500
for image_path in pathlib.Path(location).glob("**/*.jpg"):
# the Path.glob method automatically iterates in subfolders, for
# all files matching the expressions
if "MyFolder" not in image_path.parts:
# Skips processing if "MyFolder" not in the relative path to the image file
continue
# Loads the original image a single time:
img = Image.open(image_path)
if img.width < full_width:
if "crop" not in image_path.name:
# Do not print warnings for slices - just skip then
print(f"Image at {image_path} has width of only {img.width}. Skipping")
continue
for y in range(3):
for x in range(4):
print(f"Iteration {y * 4 + x} on file {image_path.name}")
# Store the cropped image object into a new variable - the original image is kept on "img"
left = x_step * x
top = y_step * y
sliced_img = img.crop((left, top, left + x_step, top + y_step))
new_path = image_path.with_name(f"{image_path.stem}_crop_{y * 4 + x + 1}{image_path.suffix}")
sliced_img.save(new_path)