5

さて、これが状況です:

Python Image Libraryを使用して、次のような画像を「テーマ化」したいと思います。

テーマカラー:色合いの色を示す見本 "#33B5E5"

IN:http://mupload.nl/img/olpiyj9is.png OUT:http://mupload.nl/img/fiaoq6gk5.png

ImageMagickでこのコマンドを使用して結果を取得しました:

convert image.png -colorspace gray image.png
mogrify -fill "#33b5e5" -tint 100 image.png
説明:


画像は最初に白黒に変換され、次にテーマが設定されます。

PythonImageLibraryでも同じ結果が得られたいです。しかし、それ以来、私はそれを使用するのにいくつかの問題を抱えているようです:

  1. 透明度を扱えない
  2. 背景(メイン画像の透明度)もテーマになります。

私はこのスクリプトを使おうとしています:

import Image
import ImageEnhance

def image_overlay(src, color="#FFFFFF", alpha=0.5):
    overlay = Image.new(src.mode, src.size, color)
    bw_src = ImageEnhance.Color(src).enhance(0.0)
    return Image.blend(bw_src, overlay, alpha)

img = Image.open("image.png")
image_overlay(img, "#33b5e5", 0.5)

透明度でも機能しなかったため、最初にグレースケールに変換しなかったことがわかります。

1つの質問に多くの問題を投稿して申し訳ありませんが、他に何もできませんでした:$

皆さんが理解してくれることを願っています。

4

2 に答える 2

8

:この回答のPILバージョンのPython3/枕フォークがここにあります

更新4:私の答えに対する以前の更新は結局最後のものではなかったと思います。それを排他的に使用するように変換することは大きな改善でしたが、能力PILさえあれば、より良い、より厄介ではない方法があるべきであるように思われることがいくつかありました。PIL

さて、ドキュメントといくつかのソースコードをよく読んだ後、私がやりたいこと実際に可能であることに気づきました。トレードオフとして、手動で使用するルックアップテーブルを作成する必要があるため、コード全体が少し長くなります。ただし、その結果Image.point()、3回ではなく、比較的遅いメソッドを1回呼び出すだけで済みます。

from PIL import Image
from PIL.ImageColor import getcolor, getrgb
from PIL.ImageOps import grayscale

def image_tint(src, tint='#ffffff'):
    if Image.isStringType(src):  # file path?
        src = Image.open(src)
    if src.mode not in ['RGB', 'RGBA']:
        raise TypeError('Unsupported source image mode: {}'.format(src.mode))
    src.load()

    tr, tg, tb = getrgb(tint)
    tl = getcolor(tint, "L")  # tint color's overall luminosity
    if not tl: tl = 1  # avoid division by zero
    tl = float(tl)  # compute luminosity preserving tint factors
    sr, sg, sb = map(lambda tv: tv/tl, (tr, tg, tb))  # per component adjustments

    # create look-up tables to map luminosity to adjusted tint
    # (using floating-point math only to compute table)
    luts = (map(lambda lr: int(lr*sr + 0.5), range(256)) +
            map(lambda lg: int(lg*sg + 0.5), range(256)) +
            map(lambda lb: int(lb*sb + 0.5), range(256)))
    l = grayscale(src)  # 8-bit luminosity version of whole image
    if Image.getmodebands(src.mode) < 4:
        merge_args = (src.mode, (l, l, l))  # for RGB verion of grayscale
    else:  # include copy of src image's alpha layer
        a = Image.new("L", src.size)
        a.putdata(src.getdata(3))
        merge_args = (src.mode, (l, l, l, a))  # for RGBA verion of grayscale
        luts += range(256)  # for 1:1 mapping of copied alpha values

    return Image.merge(*merge_args).point(luts)

if __name__ == '__main__':
    import os

    input_image_path = 'image1.png'
    print 'tinting "{}"'.format(input_image_path)

    root, ext = os.path.splitext(input_image_path)
    result_image_path = root+'_result'+ext

    print 'creating "{}"'.format(result_image_path)
    result = image_tint(input_image_path, '#33b5e5')
    if os.path.exists(result_image_path):  # delete any previous result file
        os.remove(result_image_path)
    result.save(result_image_path)  # file name's extension determines format

    print 'done'

これは、左側に入力画像、右側に対応する出力を示すスクリーンショットです。上の行はアルファレイヤーのあるもので、下の行はアルファレイヤーのない同様の行です。

アルファありとアルファなしの画像の結果を示すサンプル入力および出力画像

于 2012-09-07T02:10:22.387 に答える
5

最初にグレースケールに変換する必要があります。私がしたこと:

  1. を使用して元のアルファレイヤーを取得しますImage.split()
  2. グレースケールに変換
  3. を使用して色付けImageOps.colorize
  4. 元のアルファレイヤーを元に戻す

結果のコード:

import Image
import ImageOps

def tint_image(src, color="#FFFFFF"):
    src.load()
    r, g, b, alpha = src.split()
    gray = ImageOps.grayscale(src)
    result = ImageOps.colorize(gray, (0, 0, 0, 0), color) 
    result.putalpha(alpha)
    return result

img = Image.open("image.png")
tinted = tint_image(img, "#33b5e5")
于 2012-09-06T10:13:08.607 に答える