2016-06-21 51 views
1

当涉及到图像处理时,我非常喜欢noobot :( 我有一堆PNG文件(其中300个)有很大的区域我希望显然自动化过程,所以为什么我尝试使用python和PIL。无法裁剪透明度,PIL getbbox()和Numpy都不能正常工作

现在我看看下面的链接, 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) 

谢谢大家的帮助:)

+0

你能上什么“没有成功”是指详细点吗?当您在文件上使用代码时会发生什么? – Blckknght

+0

输出文件与外观和大小上的输入文件相同。 – sayo9394

+0

作物的透明度?删除透明度?保存为JPG格式? – YOU

回答

4

您遇到的问题是,你的图像包含透明的白色像素,并且你的代码只会作物是既透明像素黑色。示例图像中大部分像素的RGBA值为(255, 255, 255, 0)

autocrop_image2中,您将采用通道值的max。你可能只是想Alpha通道的价值直接,所以更改:

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() 
+0

我会接受你的答案,因为它比我刚刚提出的答案更清洁。在autocrop_image函数中,我用一个执行以下操作的函数替换了image.getbbox(); def getbbox(image): alphaData = image.tostring(“raw”,“A”) alphaImage = Image.fromstring(“L”,image.size,alphaData) return alphaImage.getbbox() – sayo9394

0

这里是一个解决方案以裁剪透明边界。
只要将您的文件夹,在该脚本与批处理.png文件:

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)