【Python】二値化して白黒画像を作成してみよう

こんにちは、じょーじです!

今回はPythonを使ってカラー画像を二値化して白黒画像を作成していきますヾ(⌒▽⌒)ゞ

これね〜、結構面白いんですよ笑 ←自分で言うな

と言うわけで早速やりたいと思います!
(前半は分かりにくい解説なので、もう実行したいという方は下まで行っちゃってください笑)

手法

用いる手法は「判別分析法(大津の二値化)」です!

なんだそれって思うので簡単に説明します。

色黒の世界だと、0~255の値で色が決定します。

その0〜255の中で、2つのグループに分けて片方を全て0(黒)、他方を全て255(白)とします。

2つのグループに分けれるだけ分けて(0~1|2~255、0~2|3~255| …)、それぞれの分離度を求めます。

そして分離度が最大となる部分を閾値として、それ以下を0(黒)、それ以上を255(白)とすることで、白黒画像を作ります。 ←要は白、黒にした時に画像として一番ハッキリする所を探している

ざっくり言うとこんな感じです。。。よく分かんないかもですね笑

下のコードを実行してもらえれば、誰でも簡単に二値化できるので試してみてください!

 

ソースコード

OpenCVだけで二値化は出来るのですが、勉強がてら手動で二値化しています。

なので、OpenCVは画像を読み込み書き出しのみに使用しています。

OpenCVのインストール方法はこちら↓

【OpenCV】Pythonでインストールしてみよう

実行環境はPython3系です。

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
import numpy as np
import matplotlib.pyplot as plt
import cv2

#グレイスケール関数
def make_gray(img):
     r, g, b = img[:,:,0], img[:,:,1], img[:,:,2]
     return 0.2989 * r + 0.5870 * g + 0.1140 * b

#データ格納変数
data = {}

#画像読み取り
img = cv2.imread(sys.argv[1])

#グレイスケール化
img = make_gray(img)
cv2.imwrite("gray_" + sys.argv[1], img)

#初期化
for i in range(0, 241, 2):
    data[i] = 0

#dataに格納
for i, line in enumerate(img):
    for k, p in enumerate(line):
        if p > 241:
            data[240] += 1
        elif p < 0:
            data[0] += 1
        elif int(p) % 2 == 0:
            data[int(p)] += 1
        else:
            data[int(p) - 1] += 1

#閾値算出
b = 0
st = 0
for t in range(0, 241, 2):
    n1 = 0
    u1 = 0
    u2 = 0
    n2 = 0
    for t1 in range(0, t+1, 2):
        n1 += data[t1]
        u1 += t1 * data[t1]
    if n1 == 0 or u1 == 0:
        continue
    else:
        u1 = u1 / n1

    for t2 in range(t+2, 241, 2):
        n2 += data[t2]
        u2 += t2 * data[t2]
    if n2 == 0 or u2 == 0:
        continue
    else:
        u2 = u2 / n2

    tmp = n1 * n2 * pow(u1-u2,2)
    if b < tmp:
        b = tmp
        st = t
print("閾値:%d" % st)

#グラフ表示
plt.bar(list(data.keys()),list(data.values()))
plt.plot([st, st],[0, max(data.values())], "red", alpha=0.8, linestyle=":")
plt.show()

#二値化
for i, line in enumerate(img):
    for k, p in enumerate(line):
        if p < st:
            img[i][k] = 0
        else:
            img[i][k] = 255

#書き出し
cv2.imwrite("threshold_" + sys.argv[1], img)

実行結果

今回は画像処理でも有名なレナさんに協力いただきました〜!笑

実行例
python img_threshold.py lena.jpg

結果はこんな感じです!

上手く白黒画像にできましたね!可愛いっ!

画像のピクセルを棒グラフで表示し、閾値を表示する図を出力するようになっています。

これを見ると、閾値は大体80あたりにありますね!

こんな感じで実行するだけで出来てしまうんです。

不思議です!

今回はここまでっ。

記事読んでくれてありがとです!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です