午後わてんのブログ

ベランダ菜園とWindows用アプリ作成(WPFとC#)

いろいろな局所範囲しきい値で画像の2値化を試してみた

局所範囲(注目ピクセルの近傍ピクセル)からしきい値を計算して2値化、この前は平均値をしきい値にしたものだった。今回はそれ以外の計算方法をググって、いくつか試してみた

使ったアプリは
20200422_局所しきい値で2値化.zip

github.com

f:id:gogowaten:20200529125100p:plain

  • 画像ファイルドロップか、Pasteボタンでクリップボードから画像貼り付けで画像表示
  • Copyボタンで表示している画像をクリップボードにコピー
  • 数値変更は数値の右をクリックか、ホイール
  • 画像クリックで変換前の画像表示


局所範囲の最大値、最小値を使って求める

Contrast
最大値 - 最小値
これであっているのかわからん


Bernsen
条件

  • contrastMin = 15
  • bgThreshold = 128

のとき

(最大値 - 最小値 < contrastMin) ? bgThreshold : (最大値 + 最小値) / 2.0;


Bernsen2
条件

  • MidGray = (最大値 + 最小値) / 2.0
  • contrastMin = 15
  • bgThreshold = 128
  • pv = 注目ピクセルの値)

のとき

if(最大値 - 最小値 < contrastMin)
(MidGray >= bgThreshold) ? 255: 0;
else
(pv >= MidGray) ? 255: 0;

Bernsenとある計算はこの2つが見つかったけど、これであっていのかわからん

MidGray
(最大値 + 最小値) / 2.0
最大値と最小値の中間をしきい値にするっては直感的にもわかる



局所範囲の並べ替えが必要
Median
中央値、計算量が多いので時間がかかる



平均値と標準偏差を使って求める

Niblack
条件

  • k = -0.2

のとき

平均値 + k * 標準偏差

平均値にばらつき具合を表す標準偏差を足し算。標準偏差が大きいほど極端なしきい値になる。kの符号を変えると白と黒が逆になる


Sauvola
条件

  • k = 0.5
  • r = 128

のとき

平均値 * (1 + k * (標準偏差 / r - 1))

平均値に加工した標準偏差を掛け算、kとrの値で細かい調整ができる

Phansalkar
条件

  • k = 0.25
  • r = 0.5
  • p = 2(基本的に固定?)
  • q = 10(基本的に固定?)

のとき

平均値 * (1 + p * exp(-q * 平均値) + k * (標準偏差 / r -1))、これだと真っ黒になる
or
平均値 + (1 + p * exp(-q * 平均値) + k * (標準偏差 / r -1))、これだと期待通りになる

ググって出てくるのは平均値に掛け算する上の式で、これだとしきい値が大きくなりすぎて真っ黒な画像になってしまうので、掛け算じゃなくて足し算にしてみたら、それっぽい結果になったのが下の式、今回はこちらを使っている

平均値制限法
条件

  • k = 1~10
  • γ = 0~0.5

のとき

γ * (k - 1) + (1 - 2 * γ) * 平均値

kに設定する値がわからん、γ(ガンマ)の値で結果が大きく変わる


大津の方法
大津の2値化を局所範囲に適用、計算量がものすごく多くて他の方法の100倍くらい時間がかかる。実行前に確認ウィンドウを出すようにしたくらい


計算方法は
Auto Local Threshold - ImageJ
https://imagej.net/Auto_Local_Threshold#Phansalkar
殆どの計算式はここから

opencvsharp/Binarizer.cs at master · shimat/opencvsharp
https://github.com/shimat/opencvsharp/blob/master/src/OpenCvSharp.Extensions/Binarizer.cs
Bernsenはここから

imagej-ops/LocalPhansalkarThreshold.java at master · imagej/imagej-ops
https://github.com/imagej/imagej-ops/blob/master/src/main/java/net/imagej/ops/threshold/localPhansalkar/LocalPhansalkarThreshold.java
Phansalkarはここから

Scikit-imageで画像処理を行う(2)- filtersモジュールのうち、平滑化、二値化を使うー
http://ishidate.my.coocan.jp/vpy_6/vpy_6.htm

https://ocw.kyoto-u.ac.jp/ja/09-faculty-of-engineering-jp/image-processing/pdf/dip_04.pdf
平均値制限法はここから



2値化してみる
f:id:gogowaten:20200425125836p:plain
設定する値は初期値のまま、範囲7は7 * 2 + 1 = 15で15 * 15 = 225ピクセル

f:id:gogowaten:20200425125945p:plain
元の画像サイズは296x288ピクセル

結果
f:id:gogowaten:20200425130008p:plain
どれもそれなりにいい感じ、意外だったのは(最大値 - 最小値)をしきい値にしたContrast、ノイズだらけのような画像になると思ってたけど普通に見れる画像になっている。Bernsenも計算がわからんけどそれっぽい結果になった。平均値制限法は軽い計算なのにとてもいい結果

SauvolaとPhansalkaはちょっと違う感じなので調整して
f:id:gogowaten:20200425132403p:plain
良くなった

局所範囲3x3
f:id:gogowaten:20200425133350p:plain
範囲を1にして1 * 2 + 1 = 3で、3 * 3 = 9ピクセルに設定

f:id:gogowaten:20200425133448p:plain
エッジ抽出みたいになるのがある

範囲を20は20 * 2 + 1 = 41、41 * 41 = 1681ピクセル
f:id:gogowaten:20200425152944p:plain
元の画像に依るのかもしれないけど、範囲を広げればいいってわけでもないみたいねえ。あとは方式での違いが少なくなった感じで、似たりよったりになった

範囲20のときの処理時間

製作と計測環境

0.057 Bernsen
0.055 Bernsen2
0.056 Contrast
9.366 大津
0.083 MidGray
0.737 Median
0.044 Average
0.063 Niblack
0.062 Sauvola
0.067 Phansalkar
0.052 平均値制限法

大津の方法だけ飛び抜けて時間がかかるし、処理途中でのキャンセル処理は書いていないので
f:id:gogowaten:20200425154826p:plain
実行前に確認するようにした

予想時間の計算は大雑把で
(局所ピクセル画像の横ピクセル画像の縦ピクセル数) / 1千万

範囲20、296x288ピクセルの画像の時
((20 * 2 + 1) ^ 2 * 296 * 288) / 10000000 = 14.330189秒
4コアCPUだと実際には10秒くらいだから、8コアCPUだと5秒とかになるかも?



f:id:gogowaten:20200529120340p:plain
元の画像
これを範囲2で処理すると手のシワとか指紋が強調されて面白い

f:id:gogowaten:20200529120756p:plain
Bernsen

f:id:gogowaten:20200529120607p:plain
Bernsen2

f:id:gogowaten:20200529120846p:plain
Contrast

f:id:gogowaten:20200529120901p:plain
大津

f:id:gogowaten:20200529120918p:plain
MidGray

f:id:gogowaten:20200529120943p:plain
Median

f:id:gogowaten:20200529121020p:plain
Average(c = 1)

f:id:gogowaten:20200529121050p:plain
Niblack(k = -2)

f:id:gogowaten:20200529121112p:plain
Sauvola(k = 0.01, r = 128)

f:id:gogowaten:20200529121141p:plain
Phansalker(k = -0.25, r = 0.5)

f:id:gogowaten:20200529121213p:plain
LimitedAverage(k = 0, g = 0.01)

このときのエッジ抽出に似ているけど、また違った感じ
gogowaten.hatenablog.com

f:id:gogowaten:20200529133122p:plain
ラプラシアン5x5(24近傍)


関連記事
次のWPF記事は20日

gogowaten.hatenablog.com

前回は1ヶ月前

gogowaten.hatenablog.com

大津の方法

gogowaten.hatenablog.com