Pythonで画像をくっきり二値化!OpenCV, NumPyでしきい値処理を極める


画像処理において、画像を「黒」と「白」の2色に変換する二値化(Binarization)は、最も基本的かつ重要な前処理の一つです。これにより、画像の背景と前景を明確に分離したり、特定のオブジェクトを抽出しやすくしたりすることができます。Pythonで画像を二値化するには、主にOpenCVNumPyという強力なライブラリが使われます。この記事では、これらのライブラリを活用して画像を二値化する方法について、具体的なサンプルコードを交えながら詳しく解説します。

二値化(しきい値処理)とは?

二値化は、画像データに含まれる画素値(通常0〜255)を、あらかじめ定めた**しきい値(threshold)**と比較し、そのしきい値よりも大きいか小さいかによって、画素値を0(黒)または255(白)のどちらかに変換する処理です。

  • しきい値より小さい画素: 0(黒)に変換

  • しきい値より大きい画素: 255(白)に変換

この処理によって、画像は白黒のコントラストがはっきりとした状態になり、その後の解析が容易になります。


1. OpenCVでの二値化:cv2.threshold()

OpenCVは、コンピュータビジョン分野で広く使われるライブラリで、多様な画像処理機能を提供しています。二値化に関しても、cv2.threshold()という専用の関数があり、非常に柔軟な設定が可能です。

cv2.threshold()の書式

Python
 
retval, dst = cv2.threshold(src, thresh, maxval, type)
  • src: 入力画像(通常はグレースケール画像)。NumPy配列である必要があります。

  • thresh: しきい値。この値と比較して二値化が行われます。

  • maxval: しきい値を超えた画素に割り当てる最大値(通常255)。

  • type: 二値化の種類を指定します。主要なものとして以下があります。

    • cv2.THRESH_BINARY: しきい値より大きければmaxval、そうでなければ0。

    • cv2.THRESH_BINARY_INV: しきい値より大きければ0、そうでなければmaxval(反転)。

    • cv2.THRESH_OTSU: 大津の二値化(自動でしきい値を決定)。

    • cv2.THRESH_TRIANGLE: 三角形アルゴリズム(自動でしきい値を決定)。

サンプルコード

Python
 
import cv2
import numpy as np

# ダミー画像を生成 (グレースケール)
# 400x300の黒い画像に、中央に白い四角を描画
img_gray = np.zeros((300, 400), dtype=np.uint8)
img_gray[50:250, 100:300] = 150 # 中央を灰色にする

# OpenCVで二値化(固定しきい値)
# しきい値100で二値化し、255を最大値とする
ret, binary_img_cv = cv2.threshold(img_gray, 100, 255, cv2.THRESH_BINARY)
print(f"OpenCV (固定しきい値) での二値化結果の形状: {binary_img_cv.shape}")

# 大津の二値化(自動しきい値)
# しきい値部分に0、タイプにcv2.THRESH_OTSUを追加
ret_otsu, binary_img_otsu = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
print(f"OpenCV (大津の二値化) での二値化結果の形状: {binary_img_otsu.shape}, 自動しきい値: {ret_otsu}")

# 結果はファイルとして保存 (例: cv2.imwrite('binary_cv.jpg', binary_img_cv))

2. NumPyでの二値化:論理演算とブロードキャスト

NumPyは、数値配列に対する高速な演算を可能にするライブラリです。画像の二値化も、NumPyの比較演算子ブロードキャスト機能を使えば、非常に簡潔に実装できます。

原理

NumPy配列に対して直接比較演算(例: >)を行うと、結果は真偽値(True/False)のブール配列になります。このブール配列を数値型に変換(例: astype(np.uint8) * 255)することで、0と255からなる二値画像を得られます。

サンプルコード

Python
 
# 上記で生成した img_gray を使用

# NumPyで二値化(固定しきい値)
# しきい値100より大きい画素はTrue, それ以外はFalse
# Trueは1、Falseは0として扱われるので、255を掛ける
binary_img_np = ((img_gray > 100) * 255).astype(np.uint8)
print(f"NumPyでの二値化結果の形状: {binary_img_np.shape}")

# 結果はファイルとして保存 (Pillowと連携)
from PIL import Image
binary_img_pil = Image.fromarray(binary_img_np, mode='L') # グレースケールモードで保存
# binary_img_pil.save('binary_np.jpg')

OpenCVとNumPyの使い分けと連携

  • OpenCV (cv2.threshold):

    • 利点: 大津の二値化や三角形アルゴリズムのような自動しきい値決定機能が組み込まれているため、手動でしきい値を設定する手間が省け、より汎用的な二値化が可能です。コードも専用関数で直感的です。

    • 欠点: 複雑な条件分岐や複数の配列を組み合わせた高度なロジックを直接実装するには、NumPyの方が柔軟な場合があります。

  • NumPy (> などの比較演算子):

    • 利点: 非常にシンプルで直接的なコードで二値化を実現でき、NumPyの他の配列操作とシームレスに連携できます。カスタムのしきい値ロジックや、複数の条件を組み合わせたい場合に柔軟性が高いです。

    • 欠点: 大津の二値化のような高度な自動しきい値決定アルゴリズムは、自分で実装するかOpenCVと連携する必要があります。

連携の例

実際には、OpenCVで画像を読み込み、必要に応じてグレースケール変換などの前処理を行い、そのNumPy配列に対してOpenCVのcv2.threshold()またはNumPyの比較演算を適用するという流れが一般的です。

Python
 
# OpenCVで画像を読み込む (BGR形式のNumPy配列)
# img_bgr = cv2.imread('your_color_image.jpg')

# グレースケールに変換 (NumPy配列になる)
# gray_image = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)

# その後の二値化はどちらでも可能
# ret, binary_ocv = cv2.threshold(gray_image, 128, 255, cv2.THRESH_BINARY)
# binary_np = ((gray_image > 128) * 255).astype(np.uint8)

まとめ

Pythonで画像を二値化する際、OpenCVのcv2.threshold()とNumPyの比較演算はどちらも強力な選択肢です。

  • cv2.threshold(): 自動しきい値決定機能や多様な二値化タイプが必要な場合に便利です。

  • NumPyの比較演算: 固定しきい値でのシンプルな二値化や、カスタムロジックを実装する際に高い柔軟性を提供します。

これらの手法を理解し、画像の特性や目的(例えば、単純な白黒化、背景分離、ノイズ除去など)に応じて最適な二値化方法を選択することで、画像処理の精度と効率を大幅に向上させることができるでしょう。ぜひ、あなたの画像処理プロジェクトで活用してください!🚀

「らくらくPython塾」が切り開く「呪文コーディング」とは?

■初心者歓迎「AI駆動開発/生成AIエンジニアコース」はじめました!

テックジム東京本校で先行開始。

■テックジム東京本校

格安のプログラミングスクールといえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
対面型でより早くスキル獲得、月額2万円のプログラミングスクールです。

<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。

<オンライン無料>ゼロから始めるPython爆速講座