আরজিবিএ পিএনজি কে পিআইএল দিয়ে আরজিবিতে রূপান্তর করুন


103

আমি পিআইএল ব্যবহার করছি জ্যাঙ্গোর সাথে আপলোড করা একটি স্বচ্ছ পিএনজি চিত্রকে জেপিজি ফাইলে রূপান্তর করতে। আউটপুটটি ভাঙা দেখায়।

উত্স ফাইল

স্বচ্ছ উত্স ফাইল

কোড

Image.open(object.logo.path).save('/tmp/output.jpg', 'JPEG')

বা

Image.open(object.logo.path).convert('RGB').save('/tmp/output.png')

ফলাফল

উভয় উপায়ে, ফলস্বরূপ চিত্রটি দেখতে এরকম দেখাচ্ছে:

ফলাফল ফাইল

এই সমাধানের জন্য একটি উপায় আছে কি? আমি সাদা ব্যাকগ্রাউন্ড রাখতে চাই যেখানে স্বচ্ছ পটভূমি ব্যবহৃত হত।


সমাধান

দুর্দান্ত উত্তরের জন্য ধন্যবাদ, আমি নিম্নলিখিত ফাংশন সংগ্রহ নিয়ে এসেছি:

import Image
import numpy as np


def alpha_to_color(image, color=(255, 255, 255)):
    """Set all fully transparent pixels of an RGBA image to the specified color.
    This is a very simple solution that might leave over some ugly edges, due
    to semi-transparent areas. You should use alpha_composite_with color instead.

    Source: http://stackoverflow.com/a/9166671/284318

    Keyword Arguments:
    image -- PIL RGBA Image object
    color -- Tuple r, g, b (default 255, 255, 255)

    """ 
    x = np.array(image)
    r, g, b, a = np.rollaxis(x, axis=-1)
    r[a == 0] = color[0]
    g[a == 0] = color[1]
    b[a == 0] = color[2] 
    x = np.dstack([r, g, b, a])
    return Image.fromarray(x, 'RGBA')


def alpha_composite(front, back):
    """Alpha composite two RGBA images.

    Source: http://stackoverflow.com/a/9166671/284318

    Keyword Arguments:
    front -- PIL RGBA Image object
    back -- PIL RGBA Image object

    """
    front = np.asarray(front)
    back = np.asarray(back)
    result = np.empty(front.shape, dtype='float')
    alpha = np.index_exp[:, :, 3:]
    rgb = np.index_exp[:, :, :3]
    falpha = front[alpha] / 255.0
    balpha = back[alpha] / 255.0
    result[alpha] = falpha + balpha * (1 - falpha)
    old_setting = np.seterr(invalid='ignore')
    result[rgb] = (front[rgb] * falpha + back[rgb] * balpha * (1 - falpha)) / result[alpha]
    np.seterr(**old_setting)
    result[alpha] *= 255
    np.clip(result, 0, 255)
    # astype('uint8') maps np.nan and np.inf to 0
    result = result.astype('uint8')
    result = Image.fromarray(result, 'RGBA')
    return result


def alpha_composite_with_color(image, color=(255, 255, 255)):
    """Alpha composite an RGBA image with a single color image of the
    specified color and the same size as the original image.

    Keyword Arguments:
    image -- PIL RGBA Image object
    color -- Tuple r, g, b (default 255, 255, 255)

    """
    back = Image.new('RGBA', size=image.size, color=color + (255,))
    return alpha_composite(image, back)


def pure_pil_alpha_to_color_v1(image, color=(255, 255, 255)):
    """Alpha composite an RGBA Image with a specified color.

    NOTE: This version is much slower than the
    alpha_composite_with_color solution. Use it only if
    numpy is not available.

    Source: http://stackoverflow.com/a/9168169/284318

    Keyword Arguments:
    image -- PIL RGBA Image object
    color -- Tuple r, g, b (default 255, 255, 255)

    """ 
    def blend_value(back, front, a):
        return (front * a + back * (255 - a)) / 255

    def blend_rgba(back, front):
        result = [blend_value(back[i], front[i], front[3]) for i in (0, 1, 2)]
        return tuple(result + [255])

    im = image.copy()  # don't edit the reference directly
    p = im.load()  # load pixel array
    for y in range(im.size[1]):
        for x in range(im.size[0]):
            p[x, y] = blend_rgba(color + (255,), p[x, y])

    return im

def pure_pil_alpha_to_color_v2(image, color=(255, 255, 255)):
    """Alpha composite an RGBA Image with a specified color.

    Simpler, faster version than the solutions above.

    Source: http://stackoverflow.com/a/9459208/284318

    Keyword Arguments:
    image -- PIL RGBA Image object
    color -- Tuple r, g, b (default 255, 255, 255)

    """
    image.load()  # needed for split()
    background = Image.new('RGB', image.size, color)
    background.paste(image, mask=image.split()[3])  # 3 is the alpha channel
    return background

কর্মক্ষমতা

সাধারণ নন-কম্পোজিটিং alpha_to_colorফাংশনটি হ'ল দ্রুত সমাধান, তবে কুৎসিত সীমানার পিছনে ফেলে কারণ এটি আধা স্বচ্ছ অঞ্চলগুলি পরিচালনা করে না।

খাঁটি পিআইএল এবং নামী সংমিশ্রণ সমাধান উভয়ই দুর্দান্ত ফলাফল দেয়, তবে alpha_composite_with_color অনেক দ্রুত তুলনায় (8.93 msec) হল pure_pil_alpha_to_color(79.6 msec)।যদি নিমপটি আপনার সিস্টেমে উপলভ্য থাকে তবে সেটাই উপায়। (আপডেট: নতুন খাঁটি পিআইএল সংস্করণটি উল্লিখিত সমস্ত সমাধানগুলির মধ্যে দ্রুততম।)

$ python -m timeit "import Image; from apps.front import utils; i = Image.open(u'logo.png'); i2 = utils.alpha_to_color(i)"
10 loops, best of 3: 4.67 msec per loop
$ python -m timeit "import Image; from apps.front import utils; i = Image.open(u'logo.png'); i2 = utils.alpha_composite_with_color(i)"
10 loops, best of 3: 8.93 msec per loop
$ python -m timeit "import Image; from apps.front import utils; i = Image.open(u'logo.png'); i2 = utils.pure_pil_alpha_to_color(i)"
10 loops, best of 3: 79.6 msec per loop
$ python -m timeit "import Image; from apps.front import utils; i = Image.open(u'logo.png'); i2 = utils.pure_pil_alpha_to_color_v2(i)"
10 loops, best of 3: 1.1 msec per loop

কিছুটা বেশি গতির জন্য, আমি বিশ্বাস করি ফলাফল পরিবর্তন না করেই im = image.copy()সরিয়ে ফেলা যায় be pure_pil_alpha_to_color_v2(পরে পরবর্তী দৃষ্টান্ত পরিবর্তন imকরতে image, অবশ্যই।)
unutbu

@ ইউনতবু আহ, অবশ্যই :) ধন্যবাদ
ড্যানিলো বার্গেন

উত্তর:


135

এখানে এমন একটি সংস্করণ যা অনেক সহজ - এটি কতটা পারফরম্যান্ট তা নিশ্চিত নয়। RGBA -> JPG + BGসরল থাম্বনেইলগুলির জন্য সমর্থন তৈরি করার সময় আমি পেয়েছি কিছু জ্যাঙ্গো স্নিপেটের উপর ভিত্তি করে ।

from PIL import Image

png = Image.open(object.logo.path)
png.load() # required for png.split()

background = Image.new("RGB", png.size, (255, 255, 255))
background.paste(png, mask=png.split()[3]) # 3 is the alpha channel

background.save('foo.jpg', 'JPEG', quality=80)

ফলাফল @ 80%

এখানে চিত্র বর্ণনা লিখুন

ফলাফল @ 50%
এখানে চিত্র বর্ণনা লিখুন


4
দেখে মনে হচ্ছে আপনার সংস্করণটি দ্রুততম: পেস্টবিন . com / এমসি 4 ডব্লিউজিকিজেভি ধন্যবাদ! আপনার পোস্ট সম্পর্কে দুটি জিনিস যদিও: পিএনজি.লোড () কমান্ডটি অপ্রয়োজনীয় বলে মনে হচ্ছে, এবং লাইন 4 হওয়া উচিত background = Image.new("RGB", png.size, (255, 255, 255))
ড্যানিলো বার্গেন

4
pasteসঠিক মিশ্রণটি কীভাবে করা যায় তা নির্ধারণের জন্য অভিনন্দন ।
মার্ক রান্সম

@ ড্যানিলোবার্গেন, আহ! প্রকৃতপক্ষে এটা আকার অনুপস্থিত ছিল, কিন্তু loadপদ্ধতির জন্য প্রয়োজন বোধ করা হয় splitপদ্ধতি। এটি শুনতে খুব অসাধারণ যে এটি আসলে দ্রুত / এবং / সাধারণ!
যুজি 'টোমিটা' টোমিতা

@ ইউজিটোমিটা: এর জন্য আপনাকে ধন্যবাদ!
unutbu

12
এই কোড আমার জন্য একটি ত্রুটি ঘটাচ্ছে ছিল: tuple index out of range। আমি অন্য একটি প্রশ্ন অনুসরণ করে এটি ঠিক করেছি ( স্ট্যাকওভারফ্লো . com/ জিজ্ঞাসা / ১৯19629595৯/২ )। আমাকে পিএনজিটি প্রথমে আরজিবিএতে রূপান্তর করতে হয়েছিল এবং তারপরে এটি কেটে ফেলা হয়েছিল: alpha = img.split()[-1]তারপরে পটভূমির মুখোশটি ব্যবহার করুন।
জোহাঁদ

39

ব্যবহারের Image.alpha_composite, Yuji 'Tomita' Tomita দ্বারা সমাধান সহজ হয়ে যায়। এই কোডটি কোনও tuple index out of rangeত্রুটি এড়াতে পারে যদি পিএনজি-তে কোনও আলফা চ্যানেল না থাকে।

from PIL import Image

png = Image.open(img_path).convert('RGBA')
background = Image.new('RGBA', png.size, (255,255,255))

alpha_composite = Image.alpha_composite(background, png)
alpha_composite.save('foo.jpg', 'JPEG', quality=80)

এটি আমার পক্ষে সেরা সমাধান কারণ আমার সমস্ত চিত্রের আলফা চ্যানেল নেই।
lenhhoxung

4
আমি যখন এই কোডটি ব্যবহার করি তখন
পিএনজি

4
@ লজিক ১৯76। .convert("RGB")এটিকে সংরক্ষণের আগে কেবল একটি নিক্ষেপ করুন
জোছ

13

স্বচ্ছ অংশগুলির বেশিরভাগই আরজিবিএ মান (0,0,0,0) থাকে। যেহেতু জেপিজির কোনও স্বচ্ছতা নেই, তাই জেপিগ মানটি (0,0,0) সেট করা হয়েছে, যা কালো।

বিজ্ঞপ্তি আইকনটির চারপাশে ননজারো আরজিবি মানগুলির সাথে পিক্সেল রয়েছে যেখানে A = 0 রয়েছে তাই তারা পিএনজিতে স্বচ্ছ দেখায়, তবে জেপিজিতে মজাদার রঙিন।

আপনি সমস্ত পিক্সেল সেট করতে পারেন যেখানে A == 0 থেকে আর = জি = বি = 255 নাম্বার ব্যবহার করে এভাবে ব্যবহার করতে পারেন:

import Image
import numpy as np

FNAME = 'logo.png'
img = Image.open(FNAME).convert('RGBA')
x = np.array(img)
r, g, b, a = np.rollaxis(x, axis = -1)
r[a == 0] = 255
g[a == 0] = 255
b[a == 0] = 255
x = np.dstack([r, g, b, a])
img = Image.fromarray(x, 'RGBA')
img.save('/tmp/out.jpg')

এখানে চিত্র বর্ণনা লিখুন


নোট করুন যে লোগোতে শব্দের এবং আইকনটির চারপাশে প্রান্তগুলি মসৃণ করতে কিছু আধা স্বচ্ছ পিক্সেল রয়েছে। জেপিগে সংরক্ষণ করা অর্ধ-স্বচ্ছতা উপেক্ষা করে, ফলস্বরূপ জেপিগটিকে বেশ দাগযুক্ত দেখায়।

চিত্রম্যাগিকের convertআদেশটি ব্যবহার করে আরও উন্নত মানের ফলাফল তৈরি করা যেতে পারে :

convert logo.png -background white -flatten /tmp/out.jpg

এখানে চিত্র বর্ণনা লিখুন


নিম্পি ব্যবহার করে সুন্দর মানের মিশ্রণ তৈরি করতে আপনি আলফা রচনা ব্যবহার করতে পারেন :

import Image
import numpy as np

def alpha_composite(src, dst):
    '''
    Return the alpha composite of src and dst.

    Parameters:
    src -- PIL RGBA Image object
    dst -- PIL RGBA Image object

    The algorithm comes from http://en.wikipedia.org/wiki/Alpha_compositing
    '''
    # http://stackoverflow.com/a/3375291/190597
    # http://stackoverflow.com/a/9166671/190597
    src = np.asarray(src)
    dst = np.asarray(dst)
    out = np.empty(src.shape, dtype = 'float')
    alpha = np.index_exp[:, :, 3:]
    rgb = np.index_exp[:, :, :3]
    src_a = src[alpha]/255.0
    dst_a = dst[alpha]/255.0
    out[alpha] = src_a+dst_a*(1-src_a)
    old_setting = np.seterr(invalid = 'ignore')
    out[rgb] = (src[rgb]*src_a + dst[rgb]*dst_a*(1-src_a))/out[alpha]
    np.seterr(**old_setting)    
    out[alpha] *= 255
    np.clip(out,0,255)
    # astype('uint8') maps np.nan (and np.inf) to 0
    out = out.astype('uint8')
    out = Image.fromarray(out, 'RGBA')
    return out            

FNAME = 'logo.png'
img = Image.open(FNAME).convert('RGBA')
white = Image.new('RGBA', size = img.size, color = (255, 255, 255, 255))
img = alpha_composite(img, white)
img.save('/tmp/out.jpg')

এখানে চিত্র বর্ণনা লিখুন


আপনাকে ধন্যবাদ, এই ব্যাখ্যাটি পুরোপুরি বোঝায় :)
ড্যানিলো বার্গেন

@ ড্যানিলোবার্গেন, আপনি কি লক্ষ্য করেছেন যে রূপান্তরটির মানটি খারাপ? এই সমাধানটি আংশিক স্বচ্ছতার জন্য অ্যাকাউন্ট করে না।
মার্ক রান্সম

@ মার্কারান্সম: সত্য। আপনি কিভাবে এটি ঠিক করতে জানেন?
আনবুবু

এটির জন্য আলফা মানের উপর ভিত্তি করে একটি পূর্ণ মিশ্রণ (সাদা সহ) প্রয়োজন। আমি এটি করার একটি প্রাকৃতিক উপায়ে পিআইএল অনুসন্ধান করছি এবং আমি খালি এসেছি।
মার্ক রান্সম

@ মার্করানসম হ্যাঁ, আমি এই সমস্যাটি লক্ষ্য করেছি। তবে আমার ক্ষেত্রে এটি কেবলমাত্র ইনপুট ডেটার একটি খুব সামান্য শতাংশকে প্রভাবিত করবে, তাই গুণমানটি আমার পক্ষে যথেষ্ট ভাল।
ড্যানিলো বার্গেন

4

খাঁটি পিআইএল-এর একটি সমাধান এখানে।

def blend_value(under, over, a):
    return (over*a + under*(255-a)) / 255

def blend_rgba(under, over):
    return tuple([blend_value(under[i], over[i], over[3]) for i in (0,1,2)] + [255])

white = (255, 255, 255, 255)

im = Image.open(object.logo.path)
p = im.load()
for y in range(im.size[1]):
    for x in range(im.size[0]):
        p[x,y] = blend_rgba(white, p[x,y])
im.save('/tmp/output.png')

ধন্যবাদ, এটি ভাল কাজ করে। তবে স্তন্যপায়ী সমাধানটি আরও দ্রুত গতিতে দেখা যাচ্ছে: পেস্টবিন. com/rv4zcpAV (নপি: 8.92 মিমি, পাইল: 79.7 মিমি)
ড্যানিলো বার্গেন

খাঁটি পিআইএল সহ আরও একটি দ্রুত সংস্করণ রয়েছে বলে মনে হয়। নতুন উত্তর দেখুন।
ড্যানিলো বার্গেন

4
@ ড্যানিলোবার্গেন, ধন্যবাদ - আরও ভাল উত্তরটি দেখে আমি প্রশংসা করি এবং আপনি যদি তা আমার নজরে না আনেন তবে আমার পক্ষে না হত।
মার্ক রান্সম

1

এটি ভাঙা হয়নি। এটি আপনি যা বলেছেন ঠিক তা করছে; সেই পিক্সেলগুলি সম্পূর্ণ স্বচ্ছতার সাথে কালো। আপনাকে সমস্ত পিক্সেল জুড়ে পুনরাবৃত্তি করতে হবে এবং পূর্ণ স্বচ্ছতার সাথে সাদাতে রূপান্তর করতে হবে।


ধন্যবাদ তবে নীল বৃত্তের চারপাশে নীল অঞ্চল রয়েছে। সেগুলি কি আধা স্বচ্ছ অঞ্চল? আমি সেগুলিও ঠিক করতে পারি এমন কোন উপায় আছে?
ড্যানিলো বার্গেন

0
import numpy as np
import PIL

def convert_image(image_file):
    image = Image.open(image_file) # this could be a 4D array PNG (RGBA)
    original_width, original_height = image.size

    np_image = np.array(image)
    new_image = np.zeros((np_image.shape[0], np_image.shape[1], 3)) 
    # create 3D array

    for each_channel in range(3):
        new_image[:,:,each_channel] = np_image[:,:,each_channel]  
        # only copy first 3 channels.

    # flushing
    np_image = []
    return new_image

-1

চিত্র আমদানি করুন

Def fig2img (ডুমুর): "" "সংক্ষিপ্তভাবে একটি ম্যাটপ্ল্লোলিব চিত্রকে আরজিবিএ ফর্ম্যাটে একটি পিএল চিত্রে রূপান্তর করুন এবং এটি @ পরিমাপ ফিগার একটি ম্যাটপ্ল্লোব চিত্র ফিরিয়ে দিন @ পাইথন ইমেজিং লাইব্রেরি (পিআইএল) চিত্র" "" # ফিগার পিক্সম্যাপটিতে রাখুন একটি নপি অ্যারে বুফ = ফিগার 2 ডাতা (ডুমুর) ডাব্লু, এইচ, ডি = বুফ। শেপ রিটার্ন ইমেজ.ফ্রম্বাইটস ("আরজিবিএ", (ডাব্লু, এইচ), বুফ.স্টোস্টিং ())

ডিফ ফিগাডেটা (ডুমুর): "" "সংক্ষিপ্তভাবে একটি ম্যাটপ্ল্লোলিব চিত্রকে আরজিবিএ চ্যানেলগুলির সাথে একটি 4D নপি অ্যারে রূপান্তর করুন এবং এটি @ পরিসংখ্যানে একটি ম্যাটপ্ল্লোব চিত্র ফিরিয়ে দিন @ আরজিবিএ মানগুলির একটি অলস 3 ডি অ্যারে পুনরুদ্ধার করুন" "# রেন্ডার ফিগার আঁকুন" "। ক্যানভাস.ড্রে ()

# Get the RGBA buffer from the figure
w,h = fig.canvas.get_width_height()
buf = np.fromstring ( fig.canvas.tostring_argb(), dtype=np.uint8 )
buf.shape = ( w, h, 4 )

# canvas.tostring_argb give pixmap in ARGB mode. Roll the ALPHA channel to have it in RGBA mode
buf = np.roll ( buf, 3, axis = 2 )
return buf

Def rgba2rgb (img, c = (0, 0, 0), path = 'foo.jpg', is_already_saved = মিথ্যা, if_load = সত্য): যদি না_আলডি_সেভ করা হয়: ব্যাকগ্রাউন্ড = চিত্র.নিউ ("আরজিবি", img.size, গ) ব্যাকগ্রাউন্ড.পাস্ট (img, মাস্ক = img.split () [3]) # 3 হ'ল আলফা চ্যানেল

    background.save(path, 'JPEG', quality=100)   
    is_already_saved = True
if if_load:
    if is_already_saved:
        im = Image.open(path)
        return np.array(im)
    else:
        raise ValueError('No image to load.')
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.