33

画像の自動トリミング スクリプトで何が起こっているかを理解してくれる人はいますか? 大きな透明領域/スペースを持つ 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 に精通している人は、問題を解決するのに役立ちますか?

4

8 に答える 8

42

を取り付ける

pip install Pillow

として使用します

from PIL import Image
    
image=Image.open('L_2d.png')

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

で境界を検索するとmask=imageComponents[3]、青いチャネルのみで検索されます。

于 2013-01-08T09:30:26.617 に答える
34

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

結果は次のようになります トリミングされた画像

不明な点があれば、質問してください。

于 2013-01-08T09:21:59.043 に答える
21

この投稿で回答されたほとんどの回答をテストしましたが、最終的には独自の回答になりました。アナコンダ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()
于 2018-02-04T07:57:57.217 に答える
2

最近この投稿に出くわし、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)
于 2017-02-08T21:08:58.037 に答える
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)
于 2017-05-29T20:30:10.660 に答える