C# プログラム 画像処理

【C#】画像の輝度値の取得設定速度の比較

スポンサーリンク

C#で画像の輝度値を取得/設定を行う場合は、GetPixel、SetPixelメソッドを使うと遅いのでLockBits~UnlockBitsでポインタをむき出して輝度値の取得/設定を行うのが定番となっていますが、自分自身でGetPixel、SetPixelメソッドを使った事が無かったので、いくつかの方法で処理時間を比較してみました。

 

【評価環境】

OSWindows10 64bit ver.1809
CPUIntel Core i7-7700K 4.2GHz
メモリ32GB
.NET Framework4.5.2
プラットフォームAny CPU(32ビットを優先)
評価画像jpeg 6000×4000画素 24bitカラー

です。

 

評価プログラムとしては、カラー画像の輝度値をR,G,Bそれぞれ取得し、値を明暗反転して輝度値を入れなおすプログラムを作成しています。

 

処理結果は、以下のようにポジ→ネガ→ポジ→ネガと繰り返すようになっています。

C# 画像の輝度値の取得設定時間C# 画像の輝度値の取得設定時間

 

処理時間は処理を5回行い平均した時間となります。

 

 

GetPixel、SetPixelを使った方法

平均処理時間は27439msec

本当に遅かった。。

しかもGetPixel、SetPixelではモノクロ画像(Format8bppIndexed)に対応していないので、モノクロ画像も多く扱う画像処理には不向きとなります。

 

LockBits~UnlockBitsでポインタ(Scan0)を取得し、データを配列にコピーしてから処理を行い、結果を元にコピーしなおす方法

平均処理時間は101msec

さすがにGetPixel、SetPixelよりはぜんぜん速いです。

 

MarshalクラスのReadByte、WriteByteメソッドでポインタ(Scan0)に直接、値を読み書きする方法

平均処理時間は273.6msec

この方法に少し期待していたのですが、配列にコピーした方が速かった。。

 

unsafeを使ったポインタ(Scan0)を直接読み書きする方法

平均処理時間は25.4msec

やっぱりunsafeはできれば使いたくないのですが、ここまで速いと使うのもあり??

ポインタを使うなら、C言語のライブラリにしておきたい気もしますが、C#だけで完結できるのもちょっと惹かれます。

 

ポインタで読み書きし、Parallel.Forをつかって処理を並列化する方法

平均処理時間は11.4msec

もう、unsafeは使うしかないでしょ!というレベルですが、やっぱり抵抗がある。。

 

処理を呼び出す側のプログラム

 

まとめ

それぞれの処理時間をまとめると以下の通りでした。

 

方法処理時間(msec)
GetPixel、SetPixel27439
LockBits、UnlockBitsで配列を介して処理101
MarshalクラスのReadByte、WriteByte273.6
unsafeのポインタで参照25.4
unsafeのポインタの並列処理11.4

 

結局GetPixel、SetPixelは論外でした。

あとは好みというか、ポリシーというか、意見の分かれるところだと思いますが、ポインタで処理するのは、やはり魅力です。

 

(2019.11.8追記)

.NET Framework4.5.232ビットを優先で評価を行っていたので、この部分を変えると処理速度に差が出るか?確認しました。

 

.NET Framework 4.7.2  32ビットを優先

方法処理時間(msec)
GetPixel、SetPixel27293.4
LockBits、UnlockBitsで配列を介して処理101.8
MarshalクラスのReadByte、WriteByte290.8
unsafeのポインタで参照24.4
unsafeのポインタの並列処理9.8

 

.NET Framework 4.7.2  32ビットを優先なし

方法処理時間(msec)
GetPixel、SetPixel21281.2
LockBits、UnlockBitsで配列を介して処理85.4
MarshalクラスのReadByte、WriteByte213.6
unsafeのポインタで参照27.2
unsafeのポインタの並列処理9.2

 

となりました。

ということで、.NET Frameworkの4.5.2と4.7.2の差はほとんどありませんでしたが、「32ビットを優先」のあるなしでは優先しない(64bitで動作)方が少し速い結果となりました。

 

関連記事

【C#】Bitmap画像データのメモリ構造
Bitmap画像の輝度値を参照するには、こちらのページ↓ で、Bitmap画像のメモリの値を参照す...

 

画像処理のためのC#テクニックへ戻る

コメント

タイトルとURLをコピーしました