Pythonで大津の二値化を試す

Pocket

画像を白と黒で表すことを二値化と言います。
まずグレーで表して、それを白と黒に分けるのですが、その境目、閾値をうまく指定する必要があります。
グレーだと色は256段階で表されます。
最も単純なのは真ん中の128を閾値とする方法です。しかしこれだと偏りがあるとキレイに見えません。
次に考えられるのは平均です。これだとまあまあキレイに見えます。

そして「大津の二値化」という良い手法があります。
次のページの説明がわかりやすかったです。ありがとうございました。
大津の二値化ってなんだ…ってなった. - Qiita

ある閾値を決めてすべての画素を黒側のグループと白側のグループに分けます。
次のように計算します。
r0:黒側の画素の割合
r1:白側の画素の割合
m0:黒側の画素の数値の平均
m1:白側の画素の数値の平均
として
r0*r1*(m0-m1)**2
が最大になる閾値を求めます。

実際にコードを書いてみました。

def otsu(pixels):
  # 大津の二値化を使い閾値を求める。
  # pixels:二次元の各点の色(0−255)
  # r0*r1*(m0-m1)**2
  # r0,r1:画素の割合 m0,m1:平均

  max_v = 0
  max_f = 0
  for f in range(255):
    gaso0 = []
    gaso1 = []
    for color in pixels:
      for val in color:
        if val < f:
          gaso0.append(val)
        else:
          gaso1.append(val)
    all = len(gaso0) + len(gaso1)
    r0 = len(gaso0) / all
    r1 = len(gaso1) / all
    if len(gaso0) == 0:
      m0 = 0
    else:
      m0 = sum(gaso0) / len(gaso0)
    if len(gaso1) == 0:
      m1 = 0
    else:
      m1 = sum(gaso1) / len(gaso1)
    v = r0 * r1 * (m0 - m1) ** 2
    if v > max_v:
      max_v = v
      max_f = f
  return max_f

実験してみます。

モナリザ

平均

大津の二値化

大津の二値化のほうがキレイな感じです。

真珠の耳飾りの少女

平均

大津の二値化

こちらの方が違いが顕著だと思います。

[ 2021年8月12日 | カテゴリー: Python | タグ: , ]

« | »

コメントを残す

メールアドレスが公開されることはありません。

送信してください。


タグ

カテゴリー

最近の投稿

最近のコメント

固定ページ

アーカイブ

stabucky

写真

メタ情報