長野エンジニアライフ

東京から長野に移住したエンジニアのブログです。🦒🗻⛰

Python + OpenCV4プログラミングの学習(5)〜色の処理など〜

本記事はOpenCVによる色の処理などを行ったときの備忘録である。

事前準備

以下の記事で仮想環境opencvEnvを構築していることを前提とする。 kawakeee.hatenablog.com

また、任意の画像を用意しておく。今回はLenna.jpgを用意した。

Lenna

グレイスケール

以下のコードを写経しgrayscale.pyのファイルを作成。

import cv2

try:
  # どのような画像であってもグレイスケールで読み込む
  img = cv2.imread('img/Lenna.jpg', cv2.IMREAD_GRAYSCALE)
  if img is None:
    print('ファイルを読み込めません')
    import sys
    sys.exit()
  
  cv2.imwrite('img/grayscale.jpg', img)

  cv2.imshow('img', img)
  cv2.waitKey(0)
  cv2.destroyAllWindows()
except:
  import sys
  print("Error:", sys.exc_info()[0])
  print(sys.exc_info()[1])
  import traceback
  print(traceback.format_tb(sys.exc_info()[2]))

対象画像が白黒画像で生成される。cv2.IMREAD_GRAYSCALEを用いない方法もあるので以下に添付する。

# 対象画像をグレイスケールに変換 (対象画像, 白黒2値)
dst = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
  • cv2.IMREAD_GRAYSCALE:cv2.imreadの引数に指定して画像をグレイスケールで読み込む。
  • cv2.cvtColor:対象画像を引数で指定した色調に変更する。
    使用例:cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    引数は、順に(対象画像, 色調設定)を表す。上記では対象画像がグレイスケールに変換される。

実行結果

(opencvEnv)$ python grayscale.py

指定フォルダ配下にグレイスケールされた画像が生成されていることを確認。
OpenCVによるグレイスケール処理

輝度平滑化

以下のコードを写経しequalize.pyのファイルを作成。

import cv2

try:
  # OpenCVの輝度平滑化関数はグレイスケール画像が対象のため、グレイスケール化
  img = cv2.imread('img/Lenna.jpg', cv2.IMREAD_GRAYSCALE)
  if img is None:
    print('ファイルを読み込めません')
    import sys
    sys.exit()
  
  # 対象画像を輝度平滑化する。(輝度の統一)
  dst = cv2.equalizeHist(img)
  cv2.imwrite('img/equalizeHist.jpg', dst)
  cv2.imshow('img', dst)
  cv2.waitKey(0)
  cv2.destroyAllWindows()
except:
  import sys
  print("Error:", sys.exc_info()[0])
  print(sys.exc_info()[1])
  import traceback
  print(traceback.format_tb(sys.exc_info()[2]))

OpenCVの輝度平滑化の関数はグレイスケール画像であることを前提にしているため、画像読み込み時にcv2.IMREAD_GRAYSCALEを指定する。

  • cv2.equalizeHist(...):対象画像を輝度平滑化する
    使用例:cv2.equalizeHist(img) 引数は、順に(対象画像)を表す。

実行結果

(opencvEnv)$ python threshold.py

指定フォルダ配下に輝度平滑化された画像が生成されていることを確認。
OpenCVによる輝度平滑化処理 グレイスケールで生成した画像と比べ輝度が統一されたように感じる。

スレッショルド処理

以下のコードを写経しthreshold.pyのファイルを作成。

import cv2

try:
  # 輝度に対してスレッショルド処理を行うため、グレイスケール化
  img = cv2.imread('img/Lenna.jpg', cv2.IMREAD_GRAYSCALE)
  if img is None:
    print('ファイルを読み込めません')
    import sys
    sys.exit()
  
  # スレッショルド変換 (対象画像, 閾値, 最大値, スレッショルド変換設定)
  # THRESH_BINARY の場合
  # 輝度が閾値より大きい箇所は 最大値(200)に変換
  # 輝度が閾値以下の箇所は 0に変換
  ret, dst = cv2.threshold(img, 100, 200, cv2.THRESH_BINARY)
  cv2.imwrite('img/threshold_THRESH_BINARY.jpg', dst)
  cv2.imshow('dst1', dst)

  # THRESH_BINARY_INV の場合
  # 輝度が閾値より大きい箇所は 0に変換
  # 輝度が閾値以下の箇所は 最大値(200)に変換
  ret, dst = cv2.threshold(img, 100, 200, cv2.THRESH_BINARY_INV)
  cv2.imwrite('img/threshold_THRESH_BINARY_INV.jpg', dst)
  cv2.imshow('dst2', dst)

  # THRESH_TRUNC の場合
  # 輝度が閾値より大きい箇所は 閾値に変換
  # 輝度が閾値以下の箇所は 0に変換
  ret, dst = cv2.threshold(img, 100, 200, cv2.THRESH_TRUNC)
  cv2.imwrite('img/threshold_THRESH_TRUNC.jpg', dst)
  cv2.imshow('dst3', dst)

  # THRESH_TOZERO の場合
  # 輝度が閾値より大きい箇所は 変換しない
  # 輝度が閾値以下の箇所は 0に変換
  ret, dst = cv2.threshold(img, 100, 200, cv2.THRESH_TOZERO)
  cv2.imwrite('img/threshold_THRESH_TRUNC.jpg', dst)
  cv2.imshow('dst4', dst)

  # THRESH_TOZERO_INV の場合
  # 輝度が閾値より大きい箇所は 0に変換
  # 輝度が閾値以下の箇所は 変換しない
  ret, dst = cv2.threshold(img, 100, 200, cv2.THRESH_TOZERO_INV)
  cv2.imwrite('img/threshold_THRESH_TRUNC.jpg', dst)
  cv2.imshow('dst5', dst)

  cv2.waitKey(0)
  cv2.destroyAllWindows()
except:
  import sys
  print("Error:", sys.exc_info()[0])
  print(sys.exc_info()[1])
  import traceback
  print(traceback.format_tb(sys.exc_info()[2]))

ここでは以下の5パターンのスレッショルド処理を実行。

スレッショルド処理 処理内容
THRESH_BINARY 輝度が閾値より大きい箇所は 最大値に変換
輝度が閾値以下の箇所は 0に変換
THRESH_BINARY_INV 輝度が閾値より大きい箇所は 0に変換
輝度が閾値以下の箇所は 最大値に変換
THRESH_TRUNC 輝度が閾値より大きい箇所は 閾値に変換
輝度が閾値以下の箇所は 0に変換
THRESH_TOZERO 輝度が閾値より大きい箇所は 変換しない
輝度が閾値以下の箇所は 0に変換
THRESH_TOZERO_INV 輝度が閾値より大きい箇所は 0に変換
輝度が閾値以下の箇所は 変換しない

実行結果

(opencvEnv)$ python threshold.py

指定フォルダ配下にスレッショルド処理された画像を確認。
OpenCVによるスレッショルド処理

アダプティブスレッショルド処理

以下のコードを写経しadaptive_threshold.pyのファイルを作成。

import cv2

try:
  img = cv2.imread('img/Lenna.jpg', cv2.IMREAD_GRAYSCALE)
  if img is None:
    print('ファイルを読み込めません')
    import sys
    sys.exit()
  
  print(img)
  # アダプティブスレッショルド変換
  # 周りのピクセルと比べ輝度が大きい箇所は 最大値(200)に変換
  # 周りのピクセルと比べ輝度が小さい箇所は 0に変換
  dst = cv2.adaptiveThreshold(img, 200, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
    cv2.THRESH_BINARY, 7, 8)
  cv2.imwrite('img/adaptiveThreshold.jpg', dst)
  cv2.imshow('dst', dst)
  print(dst[:3])
  cv2.waitKey(0)
  cv2.destroyAllWindows()
except:
  import sys
  print("Error:", sys.exc_info()[0])
  print(sys.exc_info()[1])
  import traceback
  print(traceback.format_tb(sys.exc_info()[2]))

(調査中)ググってみたが概要しかつかめていない...
adaptiveThresholdの処理内容について詳しい方いたらご教授お願いします

ざっくりだが、周辺のピクセルに比べ輝度が大きい箇所は最大値(この場合200)に変換され、小さい箇所は0に変換されているよう。

実行結果

(opencvEnv)$ python adaptive_threshold.py

指定フォルダ配下にアダプティブスレッショルドされた画像が生成されていることを確認。
OpenCVによるアダプティブスレッショルド処理

カラー画像の各成分を分離

以下のコードを写経しsplit.pyのファイルを作成。

import cv2

try:
  img = cv2.imread('img/Lenna.jpg')
  if img is None:
    print('ファイルを読み込めません')
    import sys
    sys.exit()
  
  # 対象画像のカラー画像を分離
  rgb = cv2.split(img)
  
  blue = rgb[0]
  green = rgb[1]
  red = rgb[2]

  cv2.imwrite('img/b.jpg', blue)
  cv2.imwrite('img/g.jpg', green)
  cv2.imwrite('img/r.jpg', red)
  cv2.imshow('blue', blue)
  cv2.imshow('green', green)
  cv2.imshow('red', red)

  cv2.waitKey(0)
  cv2.destroyAllWindows()
except:
  import sys
  print("Error:", sys.exc_info()[0])
  print(sys.exc_info()[1])
  import traceback
  print(traceback.format_tb(sys.exc_info()[2]))
  • cv2.split(...):カラー画像の色成分を分離
    使用例:cv2.split(img)
    引数の(対象カラー画像)を色成分に分離した結果を返す。

今回、生成されたb.jpg、g.jpg、r.jpgは各色成分の強さを表している。画像が白に近いほど、当該成分の色が強い。逆に、画像が黒に近いほど、当該成分の色が弱い。

実行結果

(opencvEnv)$ python split.py

色成分が分離された画像が生成されていることを確認。
OpenCVによる色分離処理

他と比べr.jpgが白っぽい画像であることから、元の画像は全体的に赤成分が強い画像であるとわかる。

Lenna

まとめ

  • cv2.IMREAD_GRAYSCALE:cv2.imreadの引数に指定して画像をグレイスケールで読み込む。
  • cv2.cvtColor:対象画像を引数で指定した色調に変更する。
  • cv2.equalizeHist(...):対象画像を輝度平滑化する
  • cv2.threshold(...):スレッショルド処理した画像を生成
  • cv2.split(...):カラー画像の色成分を分離

ソースコード

github.com