💭

Magick.NETとImageSharpとSystem.Drawingの性能評価してみた

2023/12/01に公開

はじめに

WebPのデコード処理と、画像加工に特化したベンチマークを取得してみました。

使い方としてかなり特殊で、特にSystem.Drawingを利用した実装はunsafeコードもゴリゴリ利用しているので、それぞれのライブラリの性能差というよりは、ゴリゴリ実装しないライブラリ任せで充分な性能が出るかどうかを見る意図だと考えてください。

また特にSystem.DrawingはWindows以外で利用しにくいので、クラウド環境であれば最初からImageMagickやImageSharpを利用する想定にしておいた方がいいと思います。

環境

  • BenchmarkDotNet v0.13.10, Windows 11 (10.0.22621.2715/22H2/2022Update/SunValley2)
  • 13th Gen Intel Core i9-13900H, 1 CPU, 20 logical and 14 physical cores
  • .NET Framework 4.8.1
    • System.Drawing
    • Magick.NET-Q16-OpenMP-x64 13.4.0
    • SixLabors.ImageSharp 2.1.6(3系は.NET Framework非対応)
  • .NET 8
    • System.Drawing.Common 8.0.0
    • Magick.NET-Q16-OpenMP-x64 13.4.0
    • SixLabors.ImageSharp 3.0.2

実施テスト

評価内容 .NET Framework 4.8.1 .NET 8
WebPデコード
サムネイル作成
クロップ
二値化

今回はもともと.NET Framework上で利用する想定だったため、基本は.NET Frameworkでのテストです。

ただImageSharpの3系が.NET8じゃないと使えないことから、性能差がどの程度あるのか気になったため、軽くテストはしてみました。

またImageSharpは.NET Frameworkでは2系しか使えず、将来性に不安があったのでWebPデコードのテストだけしています。

実際のコードはこちら。結構雑なコードですがご容赦ください。

評価結果

WebP -> BitmapSourceデコード

ここだけ、System.DrawingがWebPに対応していないので、WPFのパッケージに含まれているSystem.Windows.Media.BitmapImageを利用しています。ちなみにSystem.Drawing.Commonも.NET 7と8ではWebPに対応してるかのようなAPIドキュメントにありますが、実際は動きませんでした。

Method .NET Framework 4.8.1 .NET 8
System.Windows.Media 103.2 ms 83.44 ms
Magick.NET 134.1 ms 141.69 ms
ImageSharp 460.4 ms 149.99 ms

ImageSharpの.NET Framework環境の動作速度が極端に遅いです。これは2系のためで、3系である.NET8上の速度は充分に出ていると思います。

WebP -> Bitmapデコード

WebP以外のJpeg、Tiffも含まれています。

WebPはSystem.Drawingだと直接デコードできないので、UseWpfをtrueにしてBitmapSourceからBitmapに変換しています。

.NET8環境で、Windows OSに限定しない実装をしたいなら、ImageSharpが速度的に有利ですが、ややメモリのアロケートがMagick.NETの方が少ない傾向ですね。

サムネイル作成

  • WebPの場合
    • DPIをアジャストしない
      • BitmapSourceからScaleTransformを使うのが速度・メモリともに効率がいい。
    • アジャストする
      • 速度はSystem.Drawing
      • メモリーはBitmapSourceからScaleTransform
  • WebP以外の場合
    • System.Drawing

DPIアジャストしないならBitmapSourceからScaleTransformに統一するのが、複雑になりすぎなくて好みかな。

クロップ

WebP以外はSystem.Drawingが、それ以外は大きな差がありません。

ただ小さな領域のCrop処理の場合、ほとんどの処理はデコード時間です。私の用途では元画像がBitmapSourceなので、ロードしなおさずにCroppedBitmapを利用するのが良さそうです。

固定しきい値による二値化

Bitmapから二値化してBitmapSourceを作る処理になっています。

Magick.NETは元々関数で提供されているので実装が非常に容易です。

ただゴリゴリに手で実装したほうが速いしメモリー消費も少ないですね。浮動小数点演算を近似的に整数演算で処理したりしているので(人の目で見わけはできない)その辺の差もありそうです。

大津の二値化

二値化時のしきい値を、大津さん考案の(画像処理業界では超一般的)アルゴリズムで自動計算して二値化した感じ。

Magick.NETはこれも関数で用意されていて、実装が非常に楽です。

処理速度の傾向は固定値の二値化と同じ感じ。

考察

とりあえず分かったことは

  • 個別に特化したチューニングしているとクライアントPC上ではSystem.DrawingやSystem.Windows.Media.Imagingのほうが速くは作れる
  • 実装自体は圧倒的にMagick.NETが楽
  • ImageSharpは3系統は速度的にもMagick.NETと同等で.NETネイティブとしては素晴らしい速度が出ているが、.NET Frameworkでは3系統がサポートされておらず厳しい。

以上です。

Discussion