Skip to main content
 首页 » 编程设计

python之无法去除透明度,PIL getbbox() 和 Numpy 都不起作用

2025年05月04日27dflying

在图像处理方面我非常菜鸟:( 我有一堆 PNG 文件(其中 300 个),它们具有我希望裁剪的大面积透明度。我显然想自动化这个过程,因此我尝试使用 python 和 PIL。

现在我看看下面的链接, Crop a PNG image to its minimum size ,并按照此链接的建议使用 Numpy,Automatically cropping an image with python/PIL , 都没有成功 :( 输出文件与输入文件相同!没有裁剪透明度,大小相同。getbbox 返回相同的宽度和高度。

这是其中一张图片的链接; 98x50button 该图像是一个钟形按钮图标。它是用白色绘制的,所以很难看清是哪个透明背景。预期的结果是一个 20x17 的按钮(20x17 盒子内的透明度保持完好)

这是我正在使用的代码;

#!/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('--\nroot = ' + 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 值为 (255, 255, 255, 0)。

在 autocrop_image2 中,您将获取 channel 值的 max。您可能只想直接使用 alpha channel 的值,因此请更改:

image_data_bw = image_data.max(axis=2) 

收件人:

image_data_bw = image_data[:,:,3] 

该函数的其余部分应该会按预期工作。

autocrop_image 函数也有同样的问题。 getbbox 方法返回非零像素的边界,透明白色像素不为零。要修复它,请尝试在找到边界框之前将图像从 "RGBA" 模式转换为预乘 alpha "RGBA" 模式:

bbox = image.convert("RGBa").getbbox()