Zenn
👋

System.Drawing.Bitmapからの移行先をくっそまじめに検討した

に公開

はじめに

.NET Frameworkと.NET 8.0-windowsで、System.Drawing.Bitmapに依存した実装に十年以上も縛られ続けてきました。

いい加減、真面目に非Windows環境での動作に対応しようという事で、各種画像ライブラリーについて真面目に評価してみました。ただし、あくまで画像ファイルからのデコードと二値化処理に特化した評価になっていますので、かなりニッチな評価だとは思います。

参考になるようであれば、ぜひご利用ください。

評価内容

JPEGと二値のTIFF、WebPの3種類の画像ファイルをデコードし、画像解析用の二値のバイト列へデコードする。

評価結果

先に結論だけ記載すると、つぎのようになりました。

ImageSharpのJPEGデコードアルゴリズムが、System.Drawing.Bitmapと微妙に異なっていました。

目視では分からないレベルだとは思いますが、システム処理している場合に移行する際は注意が必要そうです。

評価ライブラリ

# ライブラリ ライセンス 補足
1 Aspose 有償
2 ImageSharp 有償 非商用・小規模商用利用は無償
3 LibTiff.Net New BSD License TIFF専用
4 Magick.NET Apache License 2.0
5 SkiaSharp MIT License
6 System.Drawing.Bitmap -

※ ImageSharpはv3から大規模商用の場合は有償になりました

※ ImageSharpはJPEGのYCbCrからRGBへの色空間変換アルゴリズムがSystem.Drawing.Bitmapと異なります

上記の2点から、私の用途ではImageSharpはそもそも除外することになりました。

評価環境

# OS CPU CPU Core Clock GPU メモリ
1 Windows 11 AMD Ryzen 9 7950X 16 最大 5.7 GHz NVIDIA GeForce RTX 4060 Ti 96GB
2 Windows 11 Intel Core i9-13900H 8 最大 5.4 GHz NVIDIA GeForce RTX 4070 Laptop 32GB
3 Windows 11 XEON PLATINUM 8573C 8 最大 3.5 GHz Intel Xe 32GB
4 Windows Server 2022 XEON PLATINUM 8573C 8 最大 3.5 GHz Intel Xe 32GB

評価ランタイム

  1. .NET Framework 4.8.1
  2. .NET 8.0

評価OS

  1. Windows Server 2022
  2. Windows 11

脱WindowsといってるのにWindowsだけですみません。

処理内容

  1. 画像のデコード
  2. 大津の二値化による二値化

具体的には下記のベンチマークなどを参照してください。

分析詳細

JPEG

処理速度

まず評価環境#4のWindows Server 2022でベンチマークを取得して比較します。

# ライブラリ 処理時間[ms] 性能比 Allocated[Bytes]
1 ImageSharp 53.087 100% 8,721,641
2 System.Drawing.Bitmap 65.191 81% 1,348
3 SkiaSharp 70.241 76% 1,546
4 MagickNet 101.435 52% 34,790,147
5 Aspose 167.711 32% 137,316,035

性能的にはImageSharpが良いのですが、System.Drawing.Bitmapとの互換性や、ライセンス的に今回は除外する方向で検討したいです(この時点では未決定)。

そのため、移行先の第一候補はSkiaSharpとして後続を検討します。

メモリーのアロケートはSystem.Drawing.BitmapとSkiaSharpが極端に小さいですが、これは.NETの管理外メモリーが利用されているからで、実際にメモリー消費が小さいかどうかはここでは判断できません。

ランタイムとOS

SkiaSharpに限定し、XEONの環境に固定し、ランタイムとOSを変更した場合のベンチマークを分析します。

# Runtime OS 処理時間[ms] Allocated[Bytes]
1 .NET 8.0 Windows Server 2022 70.241 1,546
2 .NET 8.0 Windows 11 71.609 327
3 .NET Framework 4.8.1 Windows 11 72.904 2,341

.NET Frameworkや、OSがWindows 11の場合でも性能的に大きな差は見られませんでした。

Windows Server 2022上で、.NET Frameworkでなぜかベンチマークが正しく動作しなかったので評価は割愛しています。あまり影響ないでしょうし。

CPUとメモリとGPU

SkiaSharpに限定し、Windows 11 & .NET8.0で、CPUなどを変えた場合のベンチマークを分析します。

# CPU Passmark Single メモリ GPU 処理時間[ms] Allocated[Bytes] Passmark*処理時間
1 AMD Ryzen 9 7950X 4,272 96GB NVIDIA GeForce RTX 4060 Ti 53.233 1,536 227,411
2 Intel Core i9-13900H 3,798 32GB NVIDIA GeForce RTX 4070 Laptop 59.796 1,540 227,105
3 XEON PLATINUM 8573C 2,474 32GB Intel Xe 71.609 327 177,161

概ねCPUベンチマークの性能によって決定されることが分かります。XEONの性能が低いのはAzure上のVMのため仮想化の影響でしょうか?

マルチスレッド性能

念のためマルチスレッド性能も見ておきます。著名なライブラリでそうそうマルチスレッド性能が極端に低いということも考えられませんが、念のため。

# ライブラリ 処理時間[ms] 性能比 Allocated[KB]
1 ImageSharp 1,172 100% 851530.56
2 System.Drawing.Bitmap 1,447 81% 129.79
3 SkiaSharp 1,636 72% 148.54
4 MagickNet 2,142 55% 3397526.24
5 Aspose 3,868 30% 13410745.75

傾向は変わらずで、特段問題は見受けられませんね。

TIFF

処理速度

まず評価環境#4のWindows Server 2022でベンチマークを取得して比較します。

# ライブラリ 処理時間[ms] 性能比 Allocated[Bytes]
1 LibTiff 4.871 100% 255,875
2 System.Drawing.Bitmap 6.364 77% 259
3 ImageSharp 40.094 12% 10,493,862
4 Aspose 45.641 11% 72,120,703
5 MagickNet 67.949 7% 34,790,174

LibTiffとSystem.Drawing.Bitmapの性能がとびぬけて高いです。

ImageSharpはのちに出てくるWebPの性能も高いのに、TIFFだけ低めです。これはImageSharpが内部アーキテクチャが二値に直接対応しておらず、一旦RGBAの32bitカラーに展開されてしまうためです。そのためAllocatedも多くなっています。

性能的にはLibTiffが良い感じなので、移行先の第一候補はLibTiffとして後続を検討します。

ランタイムとOS

LibTiffに限定し、XEONの環境に固定し、ランタイムとOSを変更した場合のベンチマークを分析します。

# Runtime OS 処理時間[ms] Allocated[Bytes]
1 .NET 8.0 Windows 11 4.63 180
2 .NET 8.0 Windows Server 2022 4.87 255,875
3 .NET Framework 4.8.1 Windows 11 6.18 256,411

LibTiffはマネージドライブラリのためか、.NET Frameworkより.NETの性能が高い傾向があります。

#1のAllocatedが少ないのですが・・・

# CPU Runtime OS 処理時間[ms] Allocated[Bytes]
1 AMD Ryzen 9 7950X .NET 8.0 Windows 11 3.446 255,874
2 Intel Core i9-13900H .NET 8.0 Windows 11 3.735 255,874
3 XEON PLATINUM 8573C .NET 8.0 Windows 11 4.633 180

Windows 11 & .NET8.0でもXEONだけ小さいため、正しく取得できなかった可能性があります。#1, #2あたりが正しいと考えるのが良いかと思います。

CPUとメモリとGPU

LibTiffに限定し、Windows 11 & .NET8.0で、CPUなどを変えた場合のベンチマークを分析します。

# CPU Passmark Single メモリ GPU 処理時間[ms] Allocated[Bytes] Passmark*処理時間
1 AMD Ryzen 9 7950X 4,272 96GB NVIDIA GeForce RTX 4060 Ti 3.446 255,874 14,721
2 Intel Core i9-13900H 3,798 32GB NVIDIA GeForce RTX 4070 Laptop 3.735 255,874 14,186
3 XEON PLATINUM 8573C 2,474 32GB Intel Xe 4.633 180 11,462

概ねCPUベンチマークの性能によって決定されることが分かります。XEONの性能が低いのは、JPEGの場合と同じ傾向にあります。

やはりAzure上のCPU性能が、PassmarkのBenchmark結果より低い傾向にあるように思われます。

マルチスレッド性能

# ライブラリ 処理時間[ms] 性能比 Allocated[KB]
1 LibTiff 113 100% 24,991
2 System.Drawing.Bitmap 170 67% 27
3 ImageSharp 1,150 10% 1,024,733
4 Aspose 1,218 9% 7,043,840
5 MagickNet 1,523 7% 3,397,486

System.Drawing.BitmapのAllocatedがさすがに低すぎるのは計測ミスな気がしますが、まぁ気にしません。

特段問題ないでしょう。

WebP

処理速度

WebPに対応しているのは3つのみです。

まず評価環境#4のWindows Server 2022でベンチマークを取得して比較します。

# ライブラリ 処理時間[ms] 性能比 Allocated[Bytes]
1 SkiaSharp 67.962 100% 1,546
2 ImageSharp 105.665 64% 9,857,987
3 MagickNet 107.949 63% 34,790,130

性能も良いですし、JPEGと統一できるメリットは大きいので、移行先の第一候補はSkiaSharpとして後続を検討します。

ランタイムとOS

SkiaSharpに限定し、XEONの環境に固定し、ランタイムとOSを変更した場合のベンチマークを分析します。

# Runtime OS 処理時間[ms] Allocated[Bytes]
1 .NET 8.0 Windows Server 2022 67.962 1546
2 .NET 8.0 Windows 11 73.899 NA
3 .NET Framework 4.8.1 Windows 11 75.370 2341

またWindows 11 & .NET8.0でAllocatedが正しくとれていません。

# CPU Runtime OS 処理時間[ms] Allocated[Bytes]
1 AMD Ryzen 9 7950X .NET 8.0 Windows 11 48.404 1,532
2 Intel Core i9-13900H .NET 8.0 Windows 11 59.879 1,536
3 XEON PLATINUM 8573C .NET 8.0 Windows 11 73.899 NA

やはりWindows 11 & .NET8.0でもXEONだけ小さいため、正しく取得できなかった可能性があります。TIFFと同様に、#1, #2あたりが正しいと考えるのが良いかと思います。

CPUとメモリとGPU

SkiaSharpに限定し、Windows 11 & .NET8.0で、CPUなどを変えた場合のベンチマークを分析します。

# CPU Passmark Single メモリ GPU 処理時間[ms] Allocated[Bytes] Passmark*処理時間
1 AMD Ryzen 9 7950X 4,272 96GB NVIDIA GeForce RTX 4060 Ti 48.404 1,532 206,782
2 Intel Core i9-13900H 3,798 32GB NVIDIA GeForce RTX 4070 Laptop 59.879 1,536 227,420
3 XEON PLATINUM 8573C 2,474 32GB Intel Xe 73.899 NA 182,826

ちょっと他と違って#2が#1に比較して高目の数字になっています。

またAzure上のCPU性能が、PassmarkのBenchmark結果より低い傾向にあるのは他と同様です。

ただ特段問題ともいえない範囲に収まっていると思います。

マルチスレッド性能

# ライブラリ 処理時間[ms] 性能比 Allocated[KB]
1 SkiaSharp 1,508 100% 149
2 ImageSharp 2,170 70% 962,659
3 MagickNet 2,361 64% 3,397,522

SkiaSharpのAllocatedも計測ミスかも?シングル時はちゃんと取れていて、特段高くないのでスルーします。

特段問題ないでしょう。

総評

JPEGとWebPはSkiaSharp、TIFFはLibTiffを利用したいと思います。

性能だけみると、つぎのようになります。

  1. JPEG: ImageSharp
  2. TIFF: LibTiff
  3. WebP: SkiaSharp

ImageSharpであればすべてのフォーマットに対応しますが、TIFFの性能がちょっと微妙です。特にメモリ使用量が気になります。

またImageSharpはJPEGのデコードアルゴリズムが他と違いSystem.Drawing.Bitmapと異なります。目視では問題ないのだと思いますが、私の用途では画像解析に利用するため、System.Drawing.Bitmapと解析結果が変わるのは望ましくないため、選択が難しいです。

TIFFの性能はLibTiffの性能がとびぬけて高いですが、LibTiffを選ぶと必然的に他のフォーマットのために2つ以上のライブラリを使う必要があります。

ImageSharpとSkiaSharpの、JPEGとWebPの性能をもう少し見てみましょう。

# ライブラリ JPEG性能比 WebP性能比
1 ImageSharp 100% 64%
2 System.Drawing.Bitmap 81% 100%

JPEGのデコードアルゴリズムの相違が問題にならない場合、3つ使い分けるのが最速ではあります。ただどちらかに絞る場合は、扱いフォーマットの多い方の性能で選んでもいいかもしれません。

そういうわけで、つぎのようになりました。

Discussion

ログインするとコメントできます