2012-10-23 44 views
6

आप एक पारदर्शी छवि को स्केल करना चाहते हैं, लेकिन अभी तक पृष्ठभूमि का रंग (रों) नहीं जानते कि तुम समग्र इसे बाद में पर होगा कहो। दुर्भाग्य से पीआईएल पूरी तरह से पारदर्शी पिक्सल के रंग मूल्यों को शामिल करता है जो खराब परिणामों की ओर अग्रसर होते हैं। क्या पूरी तरह से पारदर्शी पिक्सेल को अनदेखा करने के लिए पीआईएल-आकार बदलने का कोई तरीका है?पारदर्शिता और रंग को संरक्षित करने वाले पीआईएल के साथ स्केल छवियां?

import PIL.Image 

filename = "trans.png" # http://qrc-designer.com/stuff/trans.png 
size = (25,25) 

im = PIL.Image.open(filename) 
print im.mode # RGBA 

im = im.resize(size, PIL.Image.LINEAR) # the same with CUBIC, ANTIALIAS, transform 
# im.show() # does not use alpha 
im.save("resizelinear_"+filename) 


# PIL scaled image has dark border 

original image with (0,0,0,0) black but fully transparent background output image with black halo proper output scaled with gimp

साथ (0,0,0,0) (काला लेकिन पूरी तरह से पारदर्शी) पृष्ठभूमि (बाएं)

उत्पादन छवि काला प्रभामंडल (मध्य) के साथ

मूल छवि

उचित उत्पादन जिम्प (दाएं) के साथ बढ़ाया

संपादित करें: ऐसा लगता है कि मैं जो खोज रहा हूं उसे हासिल करना मुझे आकार बदलने के फ़ंक्शन के नमूने को संशोधित करना होगा जैसे कि यह पूर्ण पारदर्शिता वाले पिक्सेल को अनदेखा कर देगा।

EDIT2: मैं एक बहुत ही बदसूरत समाधान मिल गया है। यह आकार बदलने के दौरान पूरी तरह से पारदर्शी पिक्सेल रंगों के प्रभाव को कम करने के लिए आसपास के गैर पूरी तरह से पारदर्शी पिक्सल के औसत तक पूरी तरह से पारदर्शी पिक्सल के रंग मान सेट करता है। यह सरल रूप में धीमा है लेकिन अगर कोई अन्य समाधान नहीं है तो मैं इसे पोस्ट करूंगा। केवल आवश्यक पिक्सल को संसाधित करने के लिए एक पतला ऑपरेशन का उपयोग कर इसे तेजी से बनाना संभव हो सकता है।

edit3: premultiplied अल्फा जाने का रास्ता है - मार्क के जवाब

+0

क्या मोड अपनी फ़ाइल जब छवि में लोड किया जाता? शायद अल्फा चैनल गिरा दिया गया है? – Ber

+0

यह कहता है कि आरजीबीए और स्केल की गई छवि भी सीमा के अलावा जिंप में ठीक दिखती है। – Gonzo

+0

क्या आपने सफेद पृष्ठभूमि की तरह किसी और चीज़ पर स्केल की गई छवि को मिश्रित करने का प्रयास किया था? क्या स्केलिंग ठीक है तो अंधेरा सीमा गायब हो जाएगी। – Ber

उत्तर

4

ऐसा लगता है कि जनहित याचिका का आकार बदलने, जो उचित परिणाम प्राप्त करने के लिए आवश्यक है से पहले अल्फा पूर्व गुणा नहीं करता है। सौभाग्य से ब्रूट फोर्स द्वारा करना आसान है। इसके बाद आपको आकार के परिणाम के विपरीत करना होगा।

def premultiply(im): 
    pixels = im.load() 
    for y in range(im.size[1]): 
     for x in range(im.size[0]): 
      r, g, b, a = pixels[x, y] 
      if a != 255: 
       r = r * a // 255 
       g = g * a // 255 
       b = b * a // 255 
       pixels[x, y] = (r, g, b, a) 

def unmultiply(im): 
    pixels = im.load() 
    for y in range(im.size[1]): 
     for x in range(im.size[0]): 
      r, g, b, a = pixels[x, y] 
      if a != 255 and a != 0: 
       r = 255 if r >= a else 255 * r // a 
       g = 255 if g >= a else 255 * g // a 
       b = 255 if b >= a else 255 * b // a 
       pixels[x, y] = (r, g, b, a) 

परिणाम: result of premultiply, resize, unmultiply

+0

मेरे समाधान से काफी बेहतर रखना चाहता हूं। मुझे आश्चर्य है कि जानकारी का नुकसान कितना बुरा है। इन्हें नमस्ते सरणी के साथ अच्छी तरह से गति देना संभव होना चाहिए। – Gonzo

+0

प्रीमिलीप्लाइड अल्फा हानि पर: http://www.quasimondo.com/archives/000665.php निष्कर्ष: केवल अंतिम आउटपुट पर उपयोग करने के लिए सबसे अच्छा – Gonzo

+1

@ फ़ेलिक्स सटीकता का नुकसान केवल एक समस्या है यदि आप कुछ के लिए पारदर्शिता को कम कर रहे हैं कारण। ज्यादातर लोग ऐसा नहीं करते हैं। –

2

देख आप प्रत्येक बैंड अलग-अलग resample कर सकते हैं: तो जैसे उच्च पारदर्शिता मूल्यों से परहेज द्वारा हो सकता है कि

im.load() 
bands = im.split() 
bands = [b.resize(size, Image.LINEAR) for b in bands] 
im = Image.merge('RGBA', bands) 

संपादित

(जरूरत numpy)

import numpy as np 

# ... 

im.load() 
bands = list(im.split()) 
a = np.asarray(bands[-1]) 
a.flags.writeable = True 
a[a != 0] = 1 
bands[-1] = Image.fromarray(a) 
bands = [b.resize(size, Image.LINEAR) for b in bands] 
a = np.asarray(bands[-1]) 
a.flags.writeable = True 
a[a != 0] = 255 
bands[-1] = Image.fromarray(a) 
im = Image.merge('RGBA', bands) 
+0

फिर भी वही समस्या। – Gonzo

+0

दूसरा सुझाव सभी पारदर्शिता को हटा देता है। लेकिन मैं चिकनी सीमाओं को रखना चाहता हूं। – Gonzo

+0

मुझे दूसरे संस्करण में कुछ ट्रांसपेरेंसी दिखाई देती है, हालांकि इसे बाइनरी मास्क में बनाया जाता है। –

0

शायद आप पूरी छवि को अपने इच्छित रंग से भर सकते हैं, और केवल अल्फा चैनल में आकार बना सकते हैं?

+0

यदि मैं आपको सही ढंग से समझता हूं, तो यह सीमा पर एंटीअलाइजिंग खो देगा। मैं अभी भी एक चिकनी संक्रमण के लिए पृष्ठभूमि छवि पर चिपका हुआ छवि बनना चाहता हूं। – Gonzo

+0

एए अल्फा चैनल में किया जा सकता है (जब तक कि यह पहले से नहीं है) – Ber

+0

यही समस्या है, मैं मूल छवि से एंटीअलाइजिंग को जितना संभव हो सके – Gonzo

0

अपने आप को जवाब देने के लिए खेद है, लेकिन यह केवल काम कर समाधान है कि मैं के बारे में पता है। यह आकार बदलने के दौरान पूरी तरह से पारदर्शी पिक्सेल रंगों के प्रभाव को कम करने के लिए आसपास के गैर पूरी तरह से पारदर्शी पिक्सल के औसत तक पूरी तरह से पारदर्शी पिक्सल के रंग मान सेट करता है। ऐसे विशेष मामले हैं जहां उचित परिणाम प्राप्त नहीं किया जाएगा।

यह बहुत बदसूरत और धीमी है। अगर आप कुछ बेहतर तरीके से आ सकते हैं तो मुझे आपका जवाब स्वीकार करने में खुशी होगी।

# might be possible to speed this up by only processing necessary pixels 
# using scipy dilate, numpy where 

import PIL.Image 

filename = "trans.png" # http://qrc-designer.com/stuff/trans.png 
size = (25,25) 

import numpy as np 

im = PIL.Image.open(filename) 

npImRgba = np.asarray(im, dtype=np.uint8) 
npImRgba2 = np.asarray(im, dtype=np.uint8) 
npImRgba2.flags.writeable = True 
lenY = npImRgba.shape[0] 
lenX = npImRgba.shape[1] 
for y in range(npImRgba.shape[0]): 
    for x in range(npImRgba.shape[1]): 
     if npImRgba[y, x, 3] != 0: # only change completely transparent pixels 
      continue   
     colSum = np.zeros((3), dtype=np.uint16) 
     i = 0 
     for oy in [-1, 0, 1]: 
      for ox in [-1, 0, 1]: 
       if not oy and not ox: 
        continue 
       iy = y + oy 
       if iy < 0: 
        continue 
       if iy >= lenY: 
        continue 
       ix = x + ox 
       if ix < 0: 
        continue 
       if ix >= lenX: 
        continue 
       col = npImRgba[iy, ix] 
       if not col[3]: 
        continue 
       colSum += col[:3] 
       i += 1 
     npImRgba2[y, x, :3] = colSum/i 

im = PIL.Image.fromarray(npImRgba2) 
im = im.transform(size, PIL.Image.EXTENT, (0,0) + im.size, PIL.Image.LINEAR) 
im.save("slime_"+filename) 

परिणाम: enter image description here