【Python・OpenCV】ピクセルの最大値・最小値と、その座標を取得する方法(cv2.minMaxLoc)

※当サイトではアフィリエイト広告を利用しています

Python プログラミング 画像処理

【Python・OpenCV】ピクセルの最大値・最小値と、その座標を取得する方法(cv2.minMaxLoc)

はじめに

画像の中で、最も明るい・最も暗い場所は重要な特徴点となる場合が多くあります。
そんな時に活躍するのが、ピクセル値の範囲を調査するcv2.minMaxLoc関数です。

この記事では、cv2.minMaxLoc関数の詳細な使用方法、引数や戻り値についての解説、サンプルコードを交えた実践的な例、さらにはNumpyを使用して同様の操作を行う方法についても解説します。

ピクセルの最大値・最小値

cv2.minMaxLoc関数で取得できる、ピクセルの最大値・最小値が利用される一般的なケースを紹介します。

  1. 画像のコントラスト調整:
    • 画像のコントラストを向上させるために使用されます。最小値と最大値を取得し、これらを適切な範囲にスケーリングすることで、画像のダイナミックレンジを調整できます。
  2. 特定領域の強調:
    • 画像内で特定の領域の明るさやコントラストが他と異なる場合、その領域を強調するのに利用されます。例えば、最大値や最小値の位置を特定して、それを目印にすることができます。
  3. 特徴点の検出:
    • 画像内での最大値や最小値の位置は、特徴点や意味のある領域の位置を示すのに役立ちます。これは特に、エッジやコーナーなどの特徴を見つけるために使用されます。
      また、OpenCVのテンプレートマッチングにいおては cv2.minMaxLoc関数を使って,類似度が最大となる画素の位置を調べます。
  4. 画像の前処理:
    • 画像処理の前に、画像内の最小値や最大値を調査することがあります。これにより、異常値の除去や画像の正規化などが行われます。
  5. 機械学習の特徴量抽出:
    • 機械学習において、最小値や最大値は画像データから抽出する特徴量として使用されます。例えば、画像内の最小値や最大値を利用して特徴ベクトルを構築することがあります。

これらの用途からわかるように、cv2.minMaxLoc関数により取得される値は画像の意味のある情報として使用されたり、調整する上で重要な役割を果たしています。

cv2.minMaxLoc関数

cv2.minMaxLoc関数の引数と戻り値は下の通りです。

cv2.minMaxLoc(入力画像[, mask])

引数

名称説明
入力画像(必須)処理対象の画像(グレースケール画像)。カラー画像を処理する場合は、事前にグレースケール変換が必要です。
mask(オプション)適用するマスク。特定の領域だけを対象にする場合に使用します。

戻り値

cv2.minMaxLoc関数の戻り値は4つの要素からなるタプルです。

名称説明
minVal最小値
maxVal最大値
minValLoc最小値の位置(x, y)
maxValLoc最大値の位置(x, y)

位置は(x座標, y座標)の並びで格納されています。

使い方

以下にサンプルコードを示します。

import cv2

# 画像をグレースケールで読み込む
image = cv2.imread("image.jpg", cv2.IMREAD_GRAYSCALE)

# cv2.minMaxLocを使用して最小値と最大値の位置を取得
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(image)

# 結果の表示
print(f"最小値: {min_val}, 位置: {min_loc}")
print(f"最大値: {max_val}, 位置: {max_loc}")

cv2.minMaxLoc関数を使うにあたって、以下の注意点があります。

入力画像に関して

cv2.minMaxLoc関数はマルチチャネルでは機能しません。
つまり、入力画像はカラー画像の様なマルチチャンネル画像では動作しないため、シングルチャンネル(グレースケール)画像に変換して入力します。

カラー画像からグレースケールに変換する方法は、サンプルコードの方法を含めいくつかの手法があります。
詳細はこちらの記事で紹介しています。

(広告) OpenCV関連書籍をAmazonで探す

最大値・最小値の値が複数個存在する場合

cv2.minMaxLoc関数は最大値・最小値が複数の座標にある場合、最初に見つかった座標をそれぞれをmax_loc, min_locとして返します。他の座標の最大値・最小値の座標は無視されます。

最大値・最小値の値が複数個ある場合に全ての座標をcv2.minMaxLoc関数で取得することができません。
全ての座標を取得する場合は以下のサンプルコードのプロセスで実現します。
最小値と最大値の値はcv2.minMaxLoc関数で把握できるので、その値をNumpyのnumpy.where関数で条件を満たす全ての位置を取得します。

import cv2
import numpy as np

# 既知の3x3の配列を画像データの代わりに使用します。
# 座標(0, 1)と(2, 1)が"2"なので最大値となり、これら以外は"1"で最小値です。
image = np.array([[1, 2, 1],
                  [1, 1, 1],
                  [1, 2, 1]], dtype=np.uint8)

# cv2.minMaxLocを使用して最小値と最大値の位置を取得
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(image)

min_positions = np.where(image == np.min(image))
max_positions = np.where(image == np.max(image))

print(f"最小値の座標: {min_positions}")
print(f"最大値の座標: {max_positions}")

サンプルコードの出力は次の様になります。
期待した様に、全ての座標を取得できましたが、x座標とy座標が個別のlistとなって出力されます。

最小値の座標: (array([0, 0, 1, 1, 1, 2, 2]), array([0, 2, 0, 1, 2, 0, 2]))
最大値の座標: (array([0, 2]), array([1, 1]))

場合によっては、この様な形式は扱いづらい場合も想定されます。
"(x座標, y座標)"という形式で出力したい場合は、zip関数でそれぞれの要素をまとめて"(x座標, y座標)"の形に変換することができます。

import cv2
import numpy as np

# 既知の3x3の配列を画像データの代わりに使用します。
# 座標(0, 1)と(2, 1)が"2"なので最大値となり、これら以外は"1"で最小値です。
image = np.array([[1, 2, 1],
                  [1, 1, 1],
                  [1, 2, 1]], dtype=np.uint8)

# cv2.minMaxLocを使用して最小値と最大値の位置を取得
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(image)

# np.where関数を使用して、条件を満たすすべての位置を取得
min_positions = np.where(image == np.min(image))
max_positions = np.where(image == np.max(image))

# zip関数で要素をまとめ、listに変換
min_positions = list(zip(min_positions[0], min_positions[1]))
max_positions = list(zip(max_positions[0], max_positions[1]))

# 結果の表示
print(f"最小値の座標: {min_positions}")
print(f"最大値の座標: {max_positions}")

結果は下の様になります。
見やすい形で結果を得ることができました。

最小値の座標: [(0, 0), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 2)]
最大値の座標: [(0, 1), (2, 1)]

Numpyで最大値・最小値を取得する

OpenCVを使わずに、Numpyで最大値・最小値を取得することもできます。
Numpyのnumpy.min関数で最小値、numpy.max関数で最大値を取得することができます。

cv2.minMaxLoc関数の代わりにこれらを使ったサンプルコードは下になります。

import cv2
import numpy as np

# 画像をグレースケールで読み込む
image = cv2.imread("image.jpg", cv2.IMREAD_GRAYSCALE)

# np.min関数、np.max関数で最大値・最小値を検出し、np.where関数を使用して、条件を満たすすべての位置を取得
min_positions = np.where(image == np.min(image))
max_positions = np.where(image == np.max(image))

# zip関数で要素をまとめ、listに変換
min_positions = list(zip(min_positions[0], min_positions[1]))
max_positions = list(zip(max_positions[0], max_positions[1]))

print(f"最小値の座標: {min_positions}")
print(f"最大値の座標: {max_positions}")

cv2.minMaxLoc関数を使用した場合と同じ結果が得られます。

おわりに

最大値・最小値はさまざまな場面で利用されます。
また、画像データ以外でも必要となる機会があると思います。Numpyを使用する方法も覚えておいて損はないかもしれません。

ご質問や取り上げて欲しい内容などがありましたら、コメントをお願いします。
最後までご覧いただきありがとうございました。

参考リンク

■(広告)OpenCVの参考書としてどうぞ!■

-Python, プログラミング, 画像処理
-,