画像処理を行う上で、二値化は非常に重要な処理の一つです。OpenCVでも二値化に必要な関数は複数用意されているため、目的や入力画像の特性に応じてうまく使い分けることができるよう、基本的な内容を紹介させていただきます。
二値化とは
カラー画像やモノクロ(グレースケール)画像など、複数の色や明るさで表現された画像を、黒と白の2色だけの画像に変換することを二値化と言います。カラー画像の場合は一旦、グレースケール画像に変換(グレースケール変換)してから二値化を処理を行う場合と、一定のルールに基づいて一気に二値化を行う方法がありますが、OpenCVを用いる場合は、一旦グレースケール変換を行ったあとに二値化を行う、前者の方法となります。
この二値化の処理では、一般的に「しきい値」という値を用いて、それより明るい点を白(255)、暗い色を黒(0)に置換します。二値化した画像の利用目的に応じ、この「しきい値」を適切な値に設定することが大切になります。また、しきい値より明るい点を黒(0)に、暗い点を白(255)に置換するといった反転処理を行う場合があります。実際に二値化を行った様子をご覧ください。
注)デジタル画像の場合、1画素を8bitの階調で表現しているため0と255の2値を使用しますが、二値画像データの場合は0と1の値を用います。
しきい値の違いによる二値化変換への影響と反転処理の例






使用した関数
- cv2.threshold(gray_src,64,255,cv2.THRESH_BINARY)[1]
- cv2.threshold(gray_src,128,255,cv2.THRESH_BINARY)[1]
- cv2.threshold(gray_src,192,255,cv2.THRESH_BINARY)[1]
- cv2.threshold(gray_src,128,255,cv2.THRESH_BINARY_INV)[1]
※gray_srcは、グレースケールイメージの入力配列
二値化の目的
OpenCVを用いることで、二値化が簡単に行えることを見てきました。それでは、このような二値化は、どのような場面で役に立つのか、代表的な例を紹介させていただきます。
1)輪郭の強調
対象物の形状を知りたい場合などに、二値化フィルターによる輪郭強調が利用できます。背景との境界がハッキリすることで、ラベリングや画像検出処理を行う上で処理しやすい画像を生成することができます。
二値化フィルターによる輪郭強調の例


使用した関数
1)cv2.adaptiveThreshold(gray_src, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 9, 5)
※gray_srcは、グレースケール画像の入力配列
簡単な前処理を行うことで、さらに輪郭抽出の精度を向上させることができます。例として、ノイズ抑制の効果がある平準化フィルターを使用した場合を紹介いたします。しきい値を大きくすることで、ノイズ除去の効果が増える一方、画質が劣化してしまうため注意が必要です。
平準化後の画像に対し輪郭強調処理を行った結果とそうでない場合とでは、同じしきい値で輪郭強調を行っても、かなり異なった結果になります。前処理で行うしきい値設定と輪郭強調のために行う二値化用しきい値をうまく調整し、ラベリングや画像検出処理で扱いやすい画像になるよう工夫をする必要があります。
前処理と組み合わせた輪郭強調の例




使用した関数
前処理)cv2.GaussianBlur(gray_src, (5, 5), 2)
※gray_srcは、グレースケール画像の入力配列
2)cv2.adaptiveThreshold(blur_src, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 5, 2)
3)cv2.adaptiveThreshold(blur_src, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 9, 5)
4)cv2.adaptiveThreshold(blur_src, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 9, 12)
※blur_srcは、平準化フィルター適用後グレースケール画像の入力配列
2)背景の分離
今回使用したサンプル写真は、白い壁に白いエアコン、そして白黒の図形で構成されています。このような特徴的な画像の場合、二値化フィルターにより容易に背景の除去が行うことができます。次の例では、最初にノイズ抑制のための平準化を行ったあとで、単純な二値化処理を行った結果です。天井と壁の境目のラインを除いて、ほぼカットされています。ノイズ抑制のためのガウスフィルターとの組み合わせ以外にも、元画像の特徴によってはコントラストや明るさを調整後に二値化を行う方が良い場合もあります。コントラストや明るさを調整する場合にも、OpenCVを利用することができます。
背景の分離の例
(しきい値=48)

(しきい値=48)

使用した関数
前処理)cv2.GaussianBlur(gray_src, (5, 5), 1)
※gray_srcは、グレースケール画像の入力配列
5)cv2.threshold(gray_image, 48, 255, cv2.THRESH_BINARY)[1]
6)cv2.threshold(gray_image, 48, 255, cv2.THRESH_BINARY_INV)[1]
※blur_srcは、平準化フィルター適用後グレースケール画像の入力配列
二値化の種類
二値化の目的や入力画像の特性などから、最適な手法を選択することが大切です。OpenCVで利用できる、代表的な手法を紹介させていただきます。
1)グローバルしきい値法
1-1)静的二値化
しきい値は、ヒストグラムを参考にするなどして人の感覚で決定していかなければならず、感覚や経験の違いで結果が左右されてしまう欠点があります。
OpenCVで使える静的二値化関数
(しきい値=128)

(しきい値=128)

(しきい値=128)

(しきい値=128)

(しきい値=128)

使用した関数
1)cv2.threshold(gray_src, 128, 255, cv2.THRESH_BINARY)[1]
2)cv2.threshold(gray_src, 128, 255, cv2.THRESH_BINARY_INV)[1]
3)cv2.threshold(gray_src, 128, 255, cv2.THRESH_TRUNC)[1]
4)cv2.threshold(gray_src, 128, 255, cv2.THRESH_TOZERO)[1]
5)cv2.threshold(gray_src, 128, 255, cv2.THRESH_TOZERO_INV)[1]
※gray_srcは、グレースケール画像の入力配列
1-2)動的二値化
しきい値をヒストグラムから自動的決定する方法です。複数のアルゴリズムがありますが、OpenCVでは2種類の手法が利用できます。
OpenCVで使える動的二値化関数
(大津の方法)

(トライアングル法)

使用した関数
6)cv2.threshold(gray_src, 0, 255, cv2.THRESH_OTSU)[1]
7)cv2.threshold(gray_src, 0, 255, cv2.THRESH_TRIANGLE)[1]
※gray_srcは、グレースケール画像の入力配列
※しきい値は設定しても無視されるため、0を使用する
2)ローカルしきい値法
画像全体でしきい値を固定せずに、画像内の少領域中で注目画素と周囲にある画素からアルゴリズムに基づいたしきい値を領域ごとに求める手法です。OpenCVでは2種類の手法が利用でき、それぞれに反転での出力も選択できます。しきい値とブロックサイズを指定します。
OpenCVで使える動的二値化関数




使用した関数
8)cv2.adaptiveThreshold(gray_src, 0, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 5, 3)
9)cv2.adaptiveThreshold(gray_src, 0, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 7, 2)
10)cv2.adaptiveThreshold(gray_src, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 5, 3)
11)cv2.adaptiveThreshold(gray_src, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 5, 3)
※gray_srcは、グレースケール画像の入力配列
サンプルコード
必要に応じ、入力画像のファイル名や使用する関数を差し替えてください。
サンプルプログラムの動作確認環境
1)OS: ubuntu16.04LTS(64bit)
2)Python: 3.4.1
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import random
import sys
if __name__ == '__main__':
# 対象画像を指定
input_image_path = '<file path>/<file name>'
# 画像をグレースケールで読み込み
gray_src = cv2.imread(input_image_path, 0)
# 前処理(平準化フィルターを適用した場合)
# 前処理が不要な場合は下記行をコメントアウト
blur_src = cv2.GaussianBlur(gray_src, (5, 5), 2)
# 二値変換
# 前処理を使用しなかった場合は、blur_srcではなくgray_srcに書き換えるする
mono_src = cv2.adaptiveThreshold(blur_src, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 9, 5)
# 結果の表示
cv2.imshow("mono_src", mono_src)
cv2.waitKey(0)
cv2.destroyAllWindows()