How to cut off the blank border area of a PNG image and shrink it to its m开发者_Go百科inimum size using Python?
NB: The border size is not a fixed value, but may vary per image.
PIL's getbbox is working for me
im.getbbox() => 4-tuple or None
Calculates the bounding box of the non-zero regions in the image. The bounding box is returned as a 4-tuple defining the left, upper, right, and lower pixel coordinate. If the image is completely empty, this method returns None.
Code Sample that I tried, I have tested with bmp, but it should work for png too.
import Image
im = Image.open("test.bmp")
im.size # (364, 471)
im.getbbox() # (64, 89, 278, 267)
im2 = im.crop(im.getbbox())
im2.size # (214, 178)
im2.save("test2.bmp")
I had the same problem today. Here is my solution to crop the transparent borders. Just throw this script in your folder with your batch .png files:
from PIL import Image
import numpy as np
from os import listdir
def crop(png_image_name):
pil_image = Image.open(png_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)
Here is ready-to-use solution:
import numpy as np
from PIL import Image
def bbox(im):
a = np.array(im)[:,:,:3] # keep RGB only
m = np.any(a != [255, 255, 255], axis=2)
coords = np.argwhere(m)
y0, x0, y1, x1 = *np.min(coords, axis=0), *np.max(coords, axis=0)
return (x0, y0, x1+1, y1+1)
im = Image.open('test.png')
print(bbox(im)) # (33, 12, 223, 80)
im2 = im.crop(bbox(im))
im2.save('test_cropped.png')
Example input (download link if you want to try):
Output:
https://gist.github.com/3141140
import Image
import sys
import glob
# Trim all png images with alpha in a folder
# Usage "python PNGAlphaTrim.py ../someFolder"
try:
folderName = sys.argv[1]
except :
print "Usage: python PNGPNGAlphaTrim.py ../someFolder"
sys.exit(1)
filePaths = glob.glob(folderName + "/*.png") #search for all png images in the folder
for filePath in filePaths:
image=Image.open(filePath)
image.load()
imageSize = image.size
imageBox = image.getbbox()
imageComponents = image.split()
if len(imageComponents) < 4: continue #don't process images without alpha
rgbImage = Image.new("RGB", imageSize, (0,0,0))
rgbImage.paste(image, mask=imageComponents[3])
croppedBox = rgbImage.getbbox()
if imageBox != croppedBox:
cropped=image.crop(croppedBox)
print filePath, "Size:", imageSize, "New Size:",croppedBox
cropped.save(filePath)
You can use PIL to find rows and cols of your image that are made up purely of your border color.
Using this information, you can easily determine the extents of the inlaid image.
PIL again will then allow you to crop the image to remove the border.
I think it's necessary to supplement @Frank Krueger's answer. He makes a good point, but it doesn't include how to properly crop extra border color out of an image. I found that here. Specifically, I found this useful:
from PIL import Image, ImageChops
def trim(im):
bg = Image.new(im.mode, im.size, im.getpixel((0,0)))
diff = ImageChops.difference(im, bg)
diff = ImageChops.add(diff, diff, 2.0, -100)
bbox = diff.getbbox()
if bbox:
return im.crop(bbox)
im = Image.open("bord3.jpg")
im = trim(im)
im.show()
The other answers did not work for me while writing a Blender script (cannot use PIL), so maybe someone else will find this useful.
import numpy as np
def crop(crop_file):
"""crop the image, removing invisible borders"""
image = bpy.data.images.load(crop_file, check_existing=False)
w, h = image.size
print("Original size: " + str(w) + " x " + str(h))
linear_pixels = image.pixels[:]
pixels4d = np.reshape(linear_pixels, (h, w, 4))
mask = pixels4d [:,:,3] != 0.
coords = np.argwhere(mask)
y0, x0 = coords.min(axis=0)
y1, x1 = coords.max(axis=0) + 1
cropped_box = pixels4d[y0:y1, x0:x1, :]
w1, h1 = x1 - x0, y1 - y0
print("Crop size: " + str(w1) + " x " + str(h1))
temp_image = bpy.data.images.new(crop_file, alpha=True, width=w1, height=h1)
temp_image.pixels[:] = cropped_box.ravel()
temp_image.filepath_raw = crop_file
temp_image.file_format = 'PNG'
temp_image.alpha_mode = 'STRAIGHT'
temp_image.save()
精彩评论