2013-01-08 12 views
10

के साथ एक छवि को स्वचालित रूप से क्रॉप करना क्या कोई मेरी छवि ऑटो-क्रॉपिंग स्क्रिप्ट में क्या हो रहा है यह जानने में मेरी सहायता कर सकता है? मेरे पास एक बड़े पारदर्शी क्षेत्र/स्थान के साथ एक पीएनजी छवि है। मैं उस जगह को स्वचालित रूप से फसल करने और आवश्यक वस्तुओं को छोड़ने में सक्षम होना चाहता हूं। मूल छवि में एक स्क्वायर कैनवास होता है, सबसे अच्छा यह आयताकार होगा, केवल अणु को encapsulating। Original Imageपाइथन/पीआईएल

, कुछ Googling मैं जनहित याचिका/अजगर कोड है कि काम करने के लिए सूचित किया गया था भर में आया कर तथापि मेरे हाथ में कोड के नीचे से अधिक फसलों छवि चल:

यहाँ मूल छवि है। script's output

छवि प्रसंस्करण से अधिक परिचित किसी को भी/पीएलआई मदद कर सकते हैं कर सकते हैं मुझे इस मुद्दे को यह पता लगाने:

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

उत्पादन है?

उत्तर

14

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

परिणाम लग रहा है cropped image

तो कुछ भी की तरह अस्पष्ट है, बस पूछो।

+4

'(...) cropBox [2]: cropBox [3] +1,:]' <- +1 इस मुस्कान के लिए :) मैं नए अजगर को हूँ ...: पी – cubuspl42

+0

यह पाइथन 3 के साथ 'छवि' आयात करने के रूप में पाइथन 3 के साथ विधि काम करता है (पायथन 3 के लिए [' PILLOW'] (https://python-pillow.org/) स्थापित किया गया है)। – ryanjdillon

+0

यह आरजीबी और आरजीबीए छवियों के लिए एक आकर्षण की तरह काम करता है लेकिन पी मोड छवियों के साथ काम नहीं करता .. क्या आप कृपया सलाह दे सकते हैं? – user12345

25

मेरे लिए यह रूप में काम करता है:

import Image 

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

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

आप mask=imageComponents[3] द्वारा सीमाओं की खोज करते हैं, आप नीले चैनल द्वारा केवल खोज करते हैं।

+0

अपवोट, हालांकि, numpy-find-all-blank-cols-row रास्ता बहुत अधिक दिलचस्प है। –

2

हाल ही में इस पोस्ट में आया और देखा कि पीआईएल पुस्तकालय बदल गया है। मैं 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) 
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) 
2

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 pixel NASA earth image पर चल रहा है:

$ 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 

से पहले:

Earth at night before crop

के बाद:

Earth after crop

एक blog post with some more discussion here है।

1

मैंने इस पोस्ट में दिए गए अधिकांश उत्तरों का परीक्षण किया, हालांकि, मैं अपना जवाब समाप्त कर चुका था। मैंने एनाकोंडा पायथन 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) 
    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()