web-dev-qa-db-ja.com

PILのImage.point()メソッドを使用してピクセルデータを操作する

Python Imaging Library を使用して、色の関係を定義するルックアップテーブルで白黒画像を色付けしています。ルックアップテーブルは、RGBタプルの256要素のリストです。

_>>> len(colors)
256
>>> colors[0]
(255, 237, 237)
>>> colors[127]
(50, 196, 33)
>>> 
_

私の最初のバージョンでは、getpixel()メソッドとputpixel()メソッドを使用しました。

_    for x in range(w):
        for y in range(h):
            pix = img.getpixel((x,y))
            img.putpixel((x,y), colors[pix[0]])
_

これはひどく遅かった。 profileレポートは、putpixelメソッドとgetpixelメソッドを原因として指摘しています。少し調べて(つまり、ドキュメントを読んで)、「この方法は比較的遅いことに注意してください。」re:putpixel。 (実際のランタイム:1024x1024イメージの場合はputpixelで53秒およびgetpixelで50秒)

ドキュメントの提案に基づいて、代わりにim.load()と直接ピクセルアクセスを使用しました。

_    pixels = img.load()
    for x in range(w):
        for y in range(h):
            pix = pixels[x, y]
            pixels[x, y] = colors[pix[0]]                
_

処理は桁違いに高速化されますが、1024x1024の画像を処理するには、それでも遅い:約3.5秒です。

PILドキュメントのより徹底的な調査は、Image.point()正確にこの目的を目的としていることを示しているようです。

im.point(table) =>画像

im.point(function) =>画像

指定されたテーブルを介して各ピクセルがマッピングされた画像のコピーを返します。テーブルには、画像のバンドごとに256個の値が含まれている必要があります。代わりに関数を使用する場合は、単一の引数を取る必要があります。この関数は、可能なピクセル値ごとに1回呼び出され、結果のテーブルが画像のすべてのバンドに適用されます。

私はインターフェースをハッキングするのにしばらく時間を費やしましたが、それを正しく理解することができないようです。私の無知を許してください、しかし、PILのドキュメントは素っ気なくて、私は多くの画像処理経験を持っていません。私は少しググっていくつかの例を見つけましたが、使用法を「クリック」させるものは何もありませんでした。したがって、最後に、私の質問:

  • Image.point()はこの仕事に適したツールですか?
  • Image.point()はどのフォーマット/構造をテーブルに期待しますか?
  • 誰かが実装例を大まかに説明できますか?私がこれまでに試したすべての反復は、真っ黒な画像になってしまいました。
20
J.J.

Image.point()はこの仕事に適したツールですか?

はい、確かに、Image.point()はこの仕事に最適です

Image.point()はどのフォーマット/構造をテーブルに期待しますか?

[(12, 140, 10), (10, 100, 200), ...]の代わりに次のようにリストをフラット化する必要があります:

[12, 140, 10, 10, 100, 200, ...]

これが私が試した簡単な例です:

im = im.point(range(256, 0, -1) * 3)

alt textalt text

ちなみに、色をより細かく制御する必要があり、Image.pointが適切でないと思われる場合は、Image.getdataImage.putdataを使用して、両方のloadよりもすばやく色を変更することもできます。およびputpixel。ただし、Image.pointよりも低速です。

Image.getdataは、すべてのピクセルのリストを提供し、それらを変更して、Image.putdataを使用して書き戻します。とても簡単です。ただし、最初にImage.pointを使用して実行してみてください。


[〜#〜]編集[〜#〜]

私は最初の説明を間違えました、私は今正しく説明します:

カラーテーブルは実はこんな感じ

[0, 1, 2, 3, 4, 5, ...255, 0, 1, 2, 3, ....255, 0, 1, 2, 3, ...255]

各バンドの範囲は隣り合っています。色(0、0、0)を(10、100、10)に変更するには、次のようにする必要があります。

[10, 1, 2, 3, 4, 5, ...255, 100, 1, 2, 3, ....255, 10, 1, 2, 3, ...255]

カラーリストを正しい形式に変換するには、次のことを試してください。

table = sum(Zip(*colors), ())

私の最初の例はあなたのためにギ酸塩を示すべきだと思います。

15
Nadia Alramli

私はそれがそのようにバンドごとにpointするのがより典型的かもしれないと思います(PILから直接持ち上げられます チュートリアル ):

# split the image into individual bands
source = im.split()

R, G, B = 0, 1, 2

# select regions where red is less than 100
mask = source[R].point(lambda i: i < 100 and 255)

# process the green band
out = source[G].point(lambda i: i * 0.7)

# paste the processed band back, but only where red was < 100
source[G].paste(out, None, mask)

# build a new multiband image
im = Image.merge(im.mode, source)
3
Paul