Pillow 2.7-品質と生産性が大幅に向上

2015年1月1日に、 Pillow 2.7イメージライブラリの新しいバージョンが予定通りリリースされました。 Uploadcareチームによって多くの変更が加えられたため、このバージョンのリリースノートの拡張バージョンをご紹介します。



そもそも、それがどのように始まったかを思い出してください。 Pillowは、人気のあるPILライブラリであるPython Imaging Libraryの友好的な分岐点です(著者によると)。 PIL 1.1.7の最新バージョンは2009年にリリースされ、主にバグ修正が含まれていました。 当初、PillowはPILのアセンブリを整理するためのプロジェクトとして考えられていました。開発者は、アセンブリに関係のないすべてのバグを元のPILに送信することを推奨しました。 しかし、時間が経つにつれて、PILは急速に時代遅れになり、バグは減少せず、Python 3が近づいてきました。 そのため、Pillow 2.0ではすべてが変更されました。 「Pillow 2.0.0はPython 3のサポートを追加し、インターネット周辺の多くのバグ修正を含みます」とPyPI プロジェクトの説明を読みます。 そしてそれ以来、それは始まりました。 3か月ごとに、さまざまな開発者による膨大な数のバグ修正やその他の改善が加えられたバージョンがありました。 この期間の最も重要な革新は、おそらくWebPおよびJPEG2000形式のサポートでした。 これで、次の大きなステップの時間です。



画像サイズ変更フィルター



画像のサイズを変更する関数Image.resize()



およびImage.resize()



は、引数の1つとしてサイズ変更に使用されるフィルターを受け入れますImage.resize()



。 可能な値は、 BILINEAR



BICUBIC



BILINEAR



、およびANTIALIAS



です。 それらのほとんどすべての動作は、新しいバージョンで変更されました。



バイリニアフィルターとバイキュービックフィルターによる画像の縮小



PIL、そして枕の問題の1つは、バイリニアおよびバイキュービックフィルターを使用してサイズ変更するために、 アフィン変換の方法が使用され、元の画像の同じピクセル数を使用して最終の1つのピクセルを形成することです(双線形の2x2ピクセル、バイキュービック用の4x4)および固定フィルターサイズ。 これにより、画像縮小の結果が不十分になりましたが、実際には最近傍法と違いはありませんでした。



最も近いアフィン

最も近いアフィン



左側は最近傍法で、右側はアフィン変換のバイキュービックフィルターです。 最初のサンプルは5.8倍の減少であり、実質的に違いはありません。 2つ目は1.8倍で、差は最小限で、階段の短い飛行が鋭い対角線上に見えます。



同時に、高品質の畳み込みベースのアルゴリズムが ANTIALIAS



フィルター使用されました。これにより、削減と増加の両方で同等に良い結果が得られました。



Pillow 2.7.0以降、3つのフィルターすべてに高品質の畳み込みベースのアルゴリズムが使用されます。



アフィンたたみ込み

アフィンたたみ込み



左側はアフィン変換に基づくバイキュービックフィルター、右側は畳み込みです。 畳み込みが確実に勝ちます。



その前に、バイリニアまたはバイキュービックフィルターを使用するときに品質を改善するためにいくつかのトリックを使用した場合(たとえば、数ステップで画像を縮小したり、予備のぼかし)、それらは不要になりました。



アンチエイリアスがランチョスに改名



Image.LANCZOS



を置き換える新しいImage.LANCZOS



定数Image.LANCZOS



追加されました。



ANTIALIAS



メソッドが最初に導入されたとき、唯一の高品質の畳み込みベースのメソッドでした。 そして彼の名前はこの事実を反映していました。 すべての方法は畳み込みに基づいているため、すべてが「平滑化」されています。 また、この定数に以前に使用されたフィルターの実際の名前は、ランチョスフィルターです。



もちろん、古い定数は後方互換性のために残されており、新しい定数のエイリアスです。 言語学者のジョーク:アンチエイリアスはエイリアスになりました。



増加するランチョスフィルターの品質



奇妙なことに、和解の質も大丈夫ではありませんでした。 以前のバージョンでは、増加に伴うLanczosフィルターの品質がBILINEAR



フィルターの品質とほぼ同じであったため、バグがありました。 このバグは修正されました。



前に後

前に後



左側は以前のバージョンで4.3倍に増加した結果で、右側はPillow 2.7.0です。 左側の写真はよりぼやけており、ピクセル化されています。



増加するバイキュービックフィルターの品質



アフィン変換用に実装されたバイキュービックフィルタは、拡大するとシャープでわずかにピクセル化された画像を生成しました。 畳み込み用に実装されたバイキュービックフィルターはわずかにソフトです。



前に後

前に後



左側は以前のバージョンで4.3倍に増加した結果で、右側はPillow 2.7.0です。 左側の写真はよりピクセル化されています(より具体的なピクセルの境界線があります)。 同時に、最初の例の対角線はよりシャープで、ステップ効果の影響を受けにくくなっています。 それと別の両方- バイキュービック方程式のパラメータ「a」の影響。 両方の効果は、より良いLanczosフィルターでのみ回避できます。



パフォーマンスのサイズ変更



一般的な場合、 コンボリューションは、 アフィン変換とは異なり、元の画像のすべてのピクセルを考慮するため、削減するコストの高いアルゴリズムです。 このため、バイリニアフィルターとバイキュービックフィルターの正味のパフォーマンスは以前よりも低くなる可能性があります。 一方、バイリニアフィルターとバイキュービックフィルターの品質に以前満足していた場合は、ほぼ同じ結果が得られたNEAREST



フィルターの使用を検討する必要があります。 これにより、生産性が大幅に向上します。



同時に、Pillow 2.7.0の重要な改善点の1つは、削減のための畳み込みのパフォーマンスが以前のバージョンと比較してImageMagickと比較して平均で2倍になったことです。 BILINEAR



フィルターの畳み込み増加パフォーマンスはBILINEAR



倍速く、 BICUBIC



4倍、 LANCZOS



は同じレベルでした。



なぜなら ほとんどの場合、アプリケーションでLANCZOS



(旧ANTIALIAS



)以外を使用していなかった場合、パフォーマンスは平均で2倍低下するはずです。 他のフィルターの品質が低いためにLanczosを使用する必要がある場合は、バイリニアフィルターに切り替えることができます。 これにより、生産性が約2倍低下し、約30%増加します。



Image.thumbnail()



のデフォルトフィルター



Pillow 2.5では、 ANTIALIAS



Image.thumbnail()



デフォルトフィルターがANTIALIAS



からANTIALIAS



変更されANTIALIAS



。 このフィルターは、上記で繰り返し表明されている理由-残りのフィルターの低品質のために選択されました。 Pillow 2.7.0では、デフォルトのフィルターが再びBICUBIC



変更されます。これはもう少し高速だからです。 実際、ランチョスはImage.draft()



内でImage.draft()



メソッドを使用しても利点を与えません。これは、 libjpeg



ライブラリを使用して画像を縮小し、これに畳み込みではなくImage.thumbnail()



を使用します。



画像の転置



既存のFLIP_LEFT_RIGHT



FLIP_TOP_BOTTOM



ROTATE_90



ROTATE_180



ROTATE_270



加えて、新しいImage.TRANSPOSE



メソッドImage.TRANSPOSE



Image.transpose()



関数に追加されました。 TRANSPOSE



は代数転置、つまり 主対角線に対する画像の反射。



ROTATE_90



ROTATE_270



およびTRANSPOSE



メソッドのパフォーマンスは、プロセッサキャッシュに収まらない大きなイメージに対して大幅に向上しました。



これらの3つの方法は、ピクセルが行から取得され、列に配置されるという事実によって結合されます。 このようなメモリアクセスパターンは、1つのパスでデータをプロセッサキャッシュから強制的に削除し、次のパスでメモリからリロードする必要があるため、大きな画像では非常に非効率的です。



新しいバージョンでは、画像は128×128ピクセルの論理的な正方形に分割され、ピクセル操作は各正方形内で順番に実行されます。 これにより、プロセッサが各ラインで移動する距離を大幅に短縮できます。その結果、データをキャッシュから強制的に削除する時間がありません(1スクエアに必要なメモリは64Kbです)。



ガウスぼかしと輪郭のシャープネス



ImageFilter.GaussianBlur



の実装は、ボックスフィルターの一貫した使用に置き換えられました。 新しい実装は、Mathematical Image Analysis Groupの拡張ボックスフィルタリングによるガウス畳み込みの理論的基礎の記事に基づいていますImageFilter.UnsharpMask



の実装はガウスぼかしに基づいているため、このセクションで説明するすべてのものも適用されます。



ぼかし半径



Pillowの以前のバージョンには、ぼかし半径(ガウス標準偏差)が実際にその直径を設定するバグがありました。 したがって、たとえば、半径5で画像をぼかすには、10の値を指定する必要がありました。エラーが修正され、半径の値はソフトウェアの他の部分と同じ方法で解釈されます。



その前に特定の半径のガウスぼかしを使用した場合、その値を2で割る必要があります。



ぼかしのパフォーマンス



ボックスフィルターの計算時間は、その半径に対して一定であり、入力イメージのサイズのみに依存します。 なぜなら ガウスぼかしの新しい実装はボックスフィルターに基づいており、その計算はぼかし半径とは無関係です。



半径が1ピクセルの場合、新しい実装は5倍速くなり、半径は10〜18倍、半径は50〜85倍になります。 iOS 8スタイルのデザイナーは喜んでいるはずです。



ぼかし品質



理論的には、ガウスぼかしでは、特定の係数を持つソースのすべてのポイントが、最終画像の各ポイントの計算に関与する必要があります。 実際には、3×標準偏差よりも遠い点の係数は非常に小さいため、それらを考慮することは意味がありません。



以前の実装では、最終ピクセルごとに半径2×標準偏差内のピクセルのみが考慮されていました。 これでは十分ではなかったため、ガウスぼかしの他の実装と比較して品質が低下しました。



新しい実装は数学的な近似にすぎないという事実にもかかわらず、このようなバグは含まれていません。



前に後

前に後



左側では、前のバージョンで半径5でぼかした結果(半径を2倍にしたバグを考慮)、右側では新しいバージョンで。 オブジェクトの鋭いエッジが左側に表示されます。






これらの変更はすべて、すでにサーバーで機能しています。 それらのおかげで、オンザフライで画像を処理するためAPIの品質と速度が向上しました 。 また、より迅速なブルー操作も実装しました。 しかし、それだけではありません。 Pillowの次の大きなステップを準備していますが、これについては後ほどお知らせします。



All Articles