Unable to crop away transparency, Neither PIL getbbox() nor Numpy are working
在图像处理方面,我非常喜欢菜鸟:(
我有一堆PNG文件(其中300个),我希望裁剪大面积的透明度。 我想显然自动化这个过程,因此我尝试使用python和PIL。
现在我来看看以下链接,
裁剪PNG图像到其最小尺寸,并使用此链接建议的Numpy,使用python / PIL自动裁剪图像,两者都没有成功:(输出文件与输入文件相同!没有裁剪透明度, 相同的大小.getbbox返回相同的宽度和高度。
这是其中一个图像的链接;98x50button
图像是钟形按钮图标。 它是用白色绘制的,因此很难看出哪个透明背景。 预期的结果将是一个20x17的按钮(内部透明度为20x17的盒子保持不变)
这是我正在使用的代码;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | #!/usr/bin/env python import sys import os import Image import numpy as np def autocrop_image2(image): image.load() image_data = np.asarray(image) image_data_bw = image_data.max(axis=2) non_empty_columns = np.where(image_data_bw.max(axis=0) > 0)[0] non_empty_rows = np.where(image_data_bw.max(axis=1) > 0)[0] cropBox = (min(non_empty_rows), max(non_empty_rows), min(non_empty_columns), max(non_empty_columns)) image_data_new = image_data[cropBox[0]:cropBox[ 1] + 1, cropBox[2]:cropBox[3] + 1, :] new_image = Image.fromarray(image_data_new) return new_image def autocrop_image(image, border=0): # Get the bounding box bbox = image.getbbox() # Crop the image to the contents of the bounding box image = image.crop(bbox) # Determine the width and height of the cropped image (width, height) = image.size # Add border width += border * 2 height += border * 2 # Create a new image object for the output image cropped_image = Image.new("RGBA", (width, height), (0, 0, 0, 0)) # Paste the cropped image onto the new image cropped_image.paste(image, (border, border)) # Done! return cropped_image walk_dir = sys.argv[1] print('walk_dir = ' + walk_dir) # If your current working directory may change during script execution, it's recommended to # immediately convert program arguments to an absolute path. Then the variable root below will # be an absolute path as well. Example: # walk_dir = os.path.abspath(walk_dir) print('walk_dir (absolute) = ' + os.path.abspath(walk_dir)) for root, subdirs, files in os.walk(walk_dir): print('-- root = ' + root) list_file_path = os.path.join(root, 'my-directory-list.txt') print('list_file_path = ' + list_file_path) with open(list_file_path, 'wb') as list_file: for subdir in subdirs: print('\t- subdirectory ' + subdir) for filename in files: file_path = os.path.join(root, filename) print('\t- file %s (full path: %s)' % (filename, file_path)) filename, file_extension = os.path.splitext(filename) if file_extension.lower().endswith('.png'): # Open the input image image = Image.open(file_path) # Do the cropping # image = autocrop_image(image, 0) new_image = autocrop_image2(image) # Save the output image output = os.path.join("output", filename +".png") print output new_image.save(output) |
谢谢大家的帮助:)
您遇到的问题是您的图像包含透明的白色像素,而您的代码只会裁剪透明和黑色的像素。示例图像中大多数像素的RGBA值为
在
1 | image_data_bw = image_data.max(axis=2) |
至:
1 | image_data_bw = image_data[:,:,3] |
然后该功能的其余部分应按预期工作。
1 | bbox = image.convert("RGBa").getbbox() |
这是一个新的解决方案;我刚遇到这个问题:
你有一个RGBA图像:
- 当像素的A为0时,单元格应该是完全透明的,
- 但有些像素的A为0,RGB值不为零。
- Pillow的getbbox()和其他函数现在都失败了。
- 你想在alpha为0时强制你的RGB为0
所以:
- 制作纯黑色RGBA图像,每个像素为(0,0,0,0)
-
使用您的图像和图像以及RGBA黑色图像进行合成
图像作为面具。 - 无论你的A是0,你的RGB现在都是零
- 这是一个解决方案;可能存在内存较低的解决方案。
这是代码:
1 2 3 | black = Image.new('RGBA', myImage.size) myImage = Image.composite(myImage, black, myImage) myCroppedImage = myImage.crop(myImage.getbbox()) |
这是一种裁剪透明边框的解决方案。
只需将此脚本与批量.png文件一起放在您的文件夹中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | from PIL import Image import numpy as np from os import listdir def crop(image_name): pil_image = Image.open(image_name) np_array = np.array(pil_image) blank_px = [255, 255, 255, 0] mask = np_array != blank_px coords = np.argwhere(mask) x0, y0, z0 = coords.min(axis=0) x1, y1, z1 = coords.max(axis=0) + 1 cropped_box = np_array[x0:x1, y0:y1, z0:z1] pil_image = Image.fromarray(cropped_box, 'RGBA') print(pil_image.width, pil_image.height) pil_image.save(png_image_name) print(png_image_name) for f in listdir('.'): if f.endswith('.png'): crop(f) |