Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/image/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用python/PIL自动裁剪图像_Python_Image_Image Processing_Python Imaging Library_Crop - Fatal编程技术网

使用python/PIL自动裁剪图像

使用python/PIL自动裁剪图像,python,image,image-processing,python-imaging-library,crop,Python,Image,Image Processing,Python Imaging Library,Crop,有人能帮我弄清楚我的图像自动裁剪脚本中发生了什么吗?我有一个png图像,有一个很大的透明区域/空间。我想能够自动裁剪出空间,并留下基本的东西。原始图像是正方形的画布,最好是矩形的,只封装分子 这是原始图像: 在谷歌上搜索时,我发现了一些PIL/python代码,据报告这些代码可以正常工作,但我手里拿着这些代码,在图片上运行下面的代码 import Image import sys image=Image.open('L_2d.png') image.load() imageSize = i

有人能帮我弄清楚我的图像自动裁剪脚本中发生了什么吗?我有一个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的人能帮我解决这个问题吗?

您可以使用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')
结果看起来像

如果有什么不清楚的地方,就问。

对我来说,它的作用如下:

import Image

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

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

当您通过
mask=imageComponents[3]
搜索边界时,您只能通过蓝色通道进行搜索。

最近看到这篇文章,并注意到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 = (int(min(non_empty_rows) * (1 - padding)),
                int(min(max(non_empty_rows) * (1 + padding), rows)),
                int(min(non_empty_columns) * (1 - padding)),
                int(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)
导入cv2
def裁剪_im(im,填充=0.1):
"""
将cv2图像、im和padding%作为浮点、padding、,
并返回裁剪后的图像。
"""
bw=cv2.CVT颜色(im、cv2.COLOR\u BGR2GRAY)
行,cols=bw.shape

non_empty_columns=np.where(bw.min(axis=0)我知道这篇文章很旧,但由于某种原因,建议的答案都不适合我。因此我从现有答案中修改了自己的版本:

import Image
import numpy as np
import glob
import shutil
import os

grey_tolerance = 0.7 # (0,1) = crop (more,less)

f = 'test_image.png'
file,ext = os.path.splitext(f)

def get_cropped_line(non_empty_elms,tolerance,S):
    if (sum(non_empty_elms) == 0):
        cropBox = ()
    else:
        non_empty_min = non_empty_elms.argmax()
        non_empty_max = S - non_empty_elms[::-1].argmax()+1
        cropBox = (non_empty_min,non_empty_max)
    return cropBox

def get_cropped_area(image_bw,tol):
    max_val = image_bw.max()
    tolerance = max_val*tol
    non_empty_elms = (image_bw<=tolerance).astype(int)
    S = non_empty_elms.shape
    # Traverse rows
    cropBox = [get_cropped_line(non_empty_elms[k,:],tolerance,S[1]) for k in range(0,S[0])]
    cropBox = filter(None, cropBox)
    xmin = [k[0] for k in cropBox]
    xmax = [k[1] for k in cropBox]
    # Traverse cols
    cropBox = [get_cropped_line(non_empty_elms[:,k],tolerance,S[0]) for k in range(0,S[1])]
    cropBox = filter(None, cropBox)
    ymin = [k[0] for k in cropBox]
    ymax = [k[1] for k in cropBox]
    xmin = min(xmin)
    xmax = max(xmax)
    ymin = min(ymin)
    ymax = max(ymax)
    ymax = ymax-1 # Not sure why this is necessary, but it seems to be.
    cropBox = (ymin, ymax-ymin, xmin, xmax-xmin)
    return cropBox

def auto_crop(f,ext):
    image=Image.open(f)
    image.load()
    image_data = np.asarray(image)
    image_data_bw = image_data[:,:,0]+image_data[:,:,1]+image_data[:,:,2]
    cropBox = get_cropped_area(image_data_bw,grey_tolerance)
    image_data_new = image_data[cropBox[0]:cropBox[1]+1, cropBox[2]:cropBox[3]+1 , :]
    new_image = Image.fromarray(image_data_new)
    f_new = f.replace(ext,'')+'_cropped'+ext
    new_image.save(f_new)
导入图像
将numpy作为np导入
导入glob
进口舒蒂尔
导入操作系统
灰色公差=0.7(0,1)=裁剪(多,少)
f='test_image.png'
文件,ext=os.path.splitext(f)
def get_裁剪线(非空、公差、S):
如果(总和(非空值)=0):
cropBox=()
其他:
non_empty_min=non_empty_elms.argmax()
non_empty_max=S-non_empty_elms[::-1].argmax()+1
cropBox=(非空的最小值,非空的最大值)
返回cropBox
def获取裁剪区域(图像宽度,tol):
max_val=image_bw.max()
公差=最大值*公差

non_empty_elms=(image_bw这里是另一个使用的版本

导入系统 进口pyvips image=pyvips.image.new\u,来自\u文件(sys.argv[1]) 左、上、宽、高=图像。查找修剪(阈值=2,背景=[255、255、255]) image=image.crop(左、上、宽、高) image.write_到_文件(sys.argv[2])
pyvips修剪器对摄影图像非常有用。它进行中值滤波,减去背景,查找超过阈值的像素,并删除此集合之外的第一行和最后一行和第列。中值和阈值意味着它不会被JPEG压缩之类的事情所抛弃,因为在JPEG压缩中,噪声或不可见的压缩伪影会影响图像质量熔断其他微调器

如果不提供
background
参数,它将使用(0,0)处的像素。
threshold
默认值为10,这对于JPEG来说几乎是正确的

在这里,它运行在:

之前:

之后:


有一个。

我测试了这篇文章中回答的大部分答案,但最终我得到了自己的答案。我使用了蟒蛇3

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

这是对snew的回复的改进,该回复适用于透明背景。使用
数学形态学
我们可以使用以下代码使其适用于白色背景(而不是透明):

from PIL import Image
from skimage.io import imread
from skimage.morphology import convex_hull_image
im = imread('L_2d.jpg')
plt.imshow(im)
plt.title('input image')
plt.show()
# create a binary image
im1 = 1 - rgb2gray(im)
threshold = 0.5
im1[im1 <= threshold] = 0
im1[im1 > threshold] = 1
chull = convex_hull_image(im1)
plt.imshow(chull)
plt.title('convex hull in the binary image')
plt.show()
imageBox = Image.fromarray((chull*255).astype(np.uint8)).getbbox()
cropped = Image.fromarray(im).crop(imageBox)
cropped.save('L_2d_cropped.jpg')
plt.imshow(cropped)
plt.show()
从PIL导入图像
从skimage.io导入imread
从skimage.形态学导入凸面_外壳_图像
im=imread('L_2d.jpg'))
plt.imshow(im)
plt.title('输入图像')
plt.show()
#创建一个二进制图像
im1=1-RGB2灰色(im)
阈值=0.5
im1[im1阈值]=1
chull=凸面外壳图像(im1)
plt.imshow(chull)
plt.title('二值图像中的凸包')
plt.show()
imageBox=Image.fromarray((chull*255).astype(np.uint8)).getbbox()
裁剪=Image.fromarray(im).crop(imageBox)
crapped.save('L_2d_crapped.jpg'))
plt.imshow(裁剪)
plt.show()

pilkit
已经包含用于自动裁剪的处理器
TrimBorderColor
。类似的功能应该可以工作:

从pilkit.lib导入图像
从pilkit.com导入TrimBorderColor
img=Image.open('/path/to/my/Image.png')
处理器=TrimBorderColor()
new_img=处理器进程(img)

(…)cropBox[2]:cropBox[3]+1,:]
如果从PIL导入图像导入
图像
作为
(已为Python3安装),则此方法适用于Python3。这对RGB和RGBA图像很有吸引力,但对P模式图像不起作用。你能建议一下吗?@user12345,我不知道你说的P模式图像是什么意思。请解释一下。你有什么例子吗?在边缘情况下对我做了一些轻微的修正:更改
image\u data\u bw=image\u data.max(axis=2)
image\u data\u bw=image\u data。取(3,axis=2)
这样它实际上会查看透明度值upvote,不过,numpy查找所有空cols行的方式更有趣。如果这不起作用,可能是因为图像的“空白”区域是不透明的白色(255)而不是透明的(0).FYI,任何想知道的人:
pip install pillow
在安装
pillow
后使用
from PIL import Image
。此代码对于任何颜色和alpha都有很大的优势。我在处理低颜色图像时遇到了这一特殊代码位的问题,特别是使用单笔和单画布的图像颜色。如果左上角的像素恰好是笔的颜色,它不会正确生成遮罩(您称之为diff)。我通过替换
im.getpixel((0,0))解决了这个问题
带有一个表示纸张颜色的元组。我使用了这种方法,但发现当我的背景颜色为白色,并且图像内容接近白色时,它会被剪掉。我通过将
-100
常量更改为
0
,对其进行了修复。这种方法给出的结果与
convert image.png-f完全相同
from PIL import Image
from skimage.io import imread
from skimage.morphology import convex_hull_image
im = imread('L_2d.jpg')
plt.imshow(im)
plt.title('input image')
plt.show()
# create a binary image
im1 = 1 - rgb2gray(im)
threshold = 0.5
im1[im1 <= threshold] = 0
im1[im1 > threshold] = 1
chull = convex_hull_image(im1)
plt.imshow(chull)
plt.title('convex hull in the binary image')
plt.show()
imageBox = Image.fromarray((chull*255).astype(np.uint8)).getbbox()
cropped = Image.fromarray(im).crop(imageBox)
cropped.save('L_2d_cropped.jpg')
plt.imshow(cropped)
plt.show()