Pillow の二値化処理がドキュメントに書かれている内容と異なる結果になる

はじめに

後述しますが、 この記事で書いた問題は既に他の方がGitHub のissue に報告し対応されておりますので、 次のバージョン以降ではこの問題は解消されると思います。 (2019/5/1追記)追記時の最新バージョンでは解消されていることを確認しました。 記事は残しておきますが、 バージョンをよく確かめてお読みください。

環境

問題

Pillow のImage.convert メソッドは色情報を変換するメソッドで、変換できる形式のひとつに二値化もあります。 ドキュメントには以下のように書かれています。

https://pillow.readthedocs.io/en/5.3.x/reference/Image.html#PIL.Image.Image.convert

The default method of converting a greyscale (“L”) or “RGB” image into a bilevel (mode “1”) image uses Floyd-Steinberg dither to approximate the original image luminosity levels. If dither is NONE, all non-zero values are set to 255 (white). To use other thresholds, use the point() method.

つまり、以下のような処理を行えば、非ゼロのピクセルが255(白)に変換された二値画像が出力されるはずです。

from PIL import Image

img_file = 'test_pattern.png'
img = Image.open(img_file).convert('1', dither=Image.NONE)
img.show()

余談ですが、最初はdither=NONEとかdither='NONE'とかやってエラーしてました。
上記の処理を以下のテスト画像を用意して実行したのですが、結果は期待していたものと異なりました。 明らかに非ゼロのピクセルでも0(黒)に変換されているところがあります。

f:id:kakashibata:20181007172231p:plain
テスト画像
f:id:kakashibata:20181007172228p:plain
処理結果画像

この問題は既に修正対応されている

同じ問題にぶつかっている人がいないかググったところ、Pillow のissue を発見しました。 しかもこのissue がopenしたのが(この記事の投稿日の)4日前と、割とタイムリーです。

github.com

この報告を受けて、2018年10月5日にドキュメントが修正されたようです。 latest 版のドキュメントでは修正後の文章が確認できます。

https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.convert f:id:kakashibata:20181007172107p:plain

おわりに

私がこの問題に遭遇したタイミングとissue で取り上げられたタイミングが近いことに驚きました。 この問題はずっと前から存在していたはずなので、ただの偶然でしょうけど私には不思議な気分でした。 もっとも、他の人から見れば、issue に取り上げられたことを私がブログに書いただけのようにも見えるのですが。

(2018/10/14追記)非ゼロのピクセルを白に変換する方法について書きました。 kakashibata.hatenablog.jp