使用python / PIL自动裁剪图像
image
image-processing
python
python-imaging-library
4
0

谁能帮我弄清楚我的图像自动裁剪脚本中发生了什么?我的png图像具有较大的透明区域/空间。我希望能够自动裁剪出该空间并保留必需品。原始图像具有一个方形的画布,最好是矩形,仅封装分子。

这是原始图片: 原始图片

进行一些谷歌搜索时,我遇到了据说可以工作的PIL / python代码,但是在我手中,运行下面的代码会使图像过分裁剪。

import Image
import sys

image=Image.open('L_2d.png')
image.load()

imageSize = image.size
imageBox = image.getbbox()

imageComponents = image.split()

rgbImage = Image.new("RGB", imageSize, (0,0,0))
rgbImage.paste(image, mask=imageComponents[3])
croppedBox = rgbImage.getbbox()
print imageBox
print croppedBox
if imageBox != croppedBox:
    cropped=image.crop(croppedBox)
    print 'L_2d.png:', "Size:", imageSize, "New Size:",croppedBox
    cropped.save('L_2d_cropped.png')

输出是这样的: 脚本的输出

谁能更熟悉图像处理/ PLI,谁能帮助我解决这个问题?

参考资料:
Stack Overflow
收藏
评论
共 5 个回答
高赞 时间 活跃

最近浏览了此帖子,并注意到PIL库已更改。我用openCV重新实现了这一点:

import cv2

def crop_im(im, padding=0.1):
    """
    Takes cv2 image, im, and padding % as a float, padding,
    and returns cropped image.
    """
    bw = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
    rows, cols = bw.shape
    non_empty_columns = np.where(bw.min(axis=0)<255)[0]
    non_empty_rows = np.where(bw.min(axis=1)<255)[0]
    cropBox = (min(non_empty_rows) * (1 - padding),
                min(max(non_empty_rows) * (1 + padding), rows),
                min(non_empty_columns) * (1 - padding),
                min(max(non_empty_columns) * (1 + padding), cols))
    cropped = im[cropBox[0]:cropBox[1]+1, cropBox[2]:cropBox[3]+1 , :]

    return cropped

im = cv2.imread('testimage.png')
cropped = crop_im(im)
cv2.imshow('', cropped)
cv2.waitKey(0)
收藏
评论

对我来说,它的工作方式是:

import Image

image=Image.open('L_2d.png')

imageBox = image.getbbox()
cropped=image.crop(imageBox)
cropped.save('L_2d_cropped.png')

通过mask=imageComponents[3]搜索边界时,仅按蓝色通道搜索。

收藏
评论

这是另一个使用pyvips的版本。

这有点幻想:它查看(0,0)处的像素,假设它是背景色,然后进行中值过滤,找到包含与该像素相差更多像素的第一行和最后一行超过阈值。这种额外的处理意味着它还可以处理摄影或压缩图像,在这种情况下,简单的修整可能会被噪声或压缩伪影所抛弃。

import sys
import pyvips

# An equivalent of ImageMagick's -trim in libvips ... automatically remove
# "boring" image edges.

# We use .project to sum the rows and columns of a 0/255 mask image, the first
# non-zero row or column is the object edge. We make the mask image with an
# amount-differnt-from-background image plus a threshold.

im = pyvips.Image.new_from_file(sys.argv[1])

# find the value of the pixel at (0, 0) ... we will search for all pixels 
# significantly different from this
background = im(0, 0)

# we need to smooth the image, subtract the background from every pixel, take 
# the absolute value of the difference, then threshold
mask = (im.median(3) - background).abs() > 10

# sum mask rows and columns, then search for the first non-zero sum in each
# direction
columns, rows = mask.project()

# .profile() returns a pair (v-profile, h-profile) 
left = columns.profile()[1].min()
right = columns.width - columns.fliphor().profile()[1].min()
top = rows.profile()[0].min()
bottom = rows.height - rows.flipver().profile()[0].min()

# and now crop the original image

im = im.crop(left, top, right - left, bottom - top)

im.write_to_file(sys.argv[2])

在这里,它运行在8k x 8k像素的NASA地球图像上

$ time ./trim.py /data/john/pics/city_lights_asia_night_8k.jpg x.jpg
real    0m1.868s
user    0m13.204s
sys     0m0.280s
peak memory: 100mb

之前:

播种前晚上地球

后:

耕种后的地球

这里有一篇博客文章,其中有更多讨论

收藏
评论

我测试了本文中回答的大多数答案,但是最终还是自己回答了。我使用了蟒蛇python3。

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)
    #Bounding box given as a 4-tuple defining the left, upper, right, and lower pixel coordinates.
    #If the image is completely empty, this method returns None.
    bbox = diff.getbbox()
    if bbox:
        return im.crop(bbox)

if __name__ == "__main__":
    bg = Image.open("test.jpg") # The image to be cropped
    new_im = trim(bg)
    new_im.show()
收藏
评论

您可以使用numpy,将图像转换为数组,找到所有非空的列和行,然后根据以下内容创建图像:

import Image
import numpy as np

image=Image.open('L_2d.png')
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)
new_image.save('L_2d_cropped.png')

结果看起来像裁剪图像

如果不清楚,请问。

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号