Pynote

Python、機械学習、画像処理について

OpenCV - 画像の統計量を計算する

概要

画像から最小値、最大値、平均値、中央値、最頻値、分散、標準偏差といった各種統計量を計算する。

試した環境

f:id:nekobean:20180614001040j:plain

今回使用した画像

ipynb は こちら

# -*- coding: utf-8 -*-
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('flower.jpg', 0)

画像をグレースケール形式で読み込む。

統計量

最小値

画素値の中で最小のものを最小値 (minimum value) という。

関数

minMaxLoc(), minMaxIdx()

// src が2次元配列の場合、こちらで最小値、最大値及びその位置を取得できる。
// src のチャンネル数は1である必要がある。
void cv::minMaxLoc(InputArray src,
    double  minVal,
    double *maxVal = 0,
    Point *minLoc = 0,
    Point *maxLoc = 0,
    InputArray mask = noArray())
// src が n 次元配列の場合、位置を int 型の配列経由で受け取る。
void cv::minMaxIdx(InputArray src,
    double *minVal,
    double *maxVal = 0,
    int *minIdx = 0,
    int *maxIdx = 0,
    InputArray mask = noArray())
minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(src[, mask])
コード
// minMaxLoc()
double minVal, maxVal;
cv::Point minLoc, maxLoc;
cv::minMaxLoc(img, &minVal, &maxVal, &minLoc, &maxLoc);

std::cout << "minVal: " << minVal << ", minLoc: " << minLoc << std::endl;
std::cout << "maxVal: " << maxVal << ", maxLoc: " << maxLoc << std::endl;
// minVal: 0, minLoc: [193, 133]
// maxVal: 248, maxLoc: [211, 106]
// minMaxIdx()
double minVal, maxVal;
int minIdx[2], maxIdx[2];
cv::minMaxIdx(img, &minVal, &maxVal, minIdx, maxIdx);

std::cout << "minVal: " << minVal << ", minIdx: " << minIdx[0] << ", "
          << minIdx[1] << std::endl;
std::cout << "maxVal: " << maxVal << ", maxLoc: " << maxIdx[0] << ", "
          << maxIdx[1] << std::endl;
// minVal: 0, minIdx: 133, 193
// maxVal: 248, maxLoc: 106, 211

// minIdx[2] が 133, 193 となっているが、これは配列の133行193列目を意味する。 
// 位置は minMaxLoc では Point(x, y) であったが、minMaxIdx では配列のインデックス
// となる違いに注意する。
# OpenCV
minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(img)
print('min value: {}, min position: {}'.format(minVal, minLoc))
# min value: 0.0, min position: (193, 133)

# numpy
min = np.min(img)
print('min', min)  # min 0

最大値

画素値の中で最大のものを最大値 (maximum value) という。

# OpenCV
minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(img)
print('max value: {}, max position: {}'.format(maxVal, maxLoc))
# max value: 248.0, max position: (211, 106)

# numpy
max = np.max(img)
print('max', max)  # max 248

平均値

画像サイズが M \times N としたとき、その画像の平均値 (mean value) \mu は次の式で計算できる。

\displaystyle \mu = \frac{1}{MN} \sum_{i=0}^{N-1} \sum_{j=0}^{M-1} img(i, j)

ただし、 img(i, j) は画像の位置 (i, j) の画素値を表す。

関数

mean()

Scalar cv::mean(InputArray src, InputArray mask = noArray())
retval = cv2.mean(src[, mask])
コード
cv::Scalar mean = cv::mean(img);
std::cout << "mean: " << mean[0] << std::endl; // mean: 81.1051
# OpenCV
mean = cv2.mean(img)
print('mean', mean)  # mean (81.10509036144579, 0.0, 0.0, 0.0)

# numpy
mean = np.mean(img)
print('mean', mean)  # mean 81.1050903614

中央値

画像サイズが M \times N としたとき、その画像の中央値 (median) は次の式で計算できる。

  • MN が奇数の場合: 画素値を小さい順に並べたときに MN / 2 番目の値
  • MN が偶数の場合: 画素値を小さい順に並べたときに (MN + 1) / 2 番目の値
median = np.median(img)
print('median', median)  # median 64.0

最頻値

画素値の中で最も頻度が高い値を最頻値 (mode) という。

from scipy import stats
mode, count = stats.mode(img.flatten())
print('mode', mode[0])  # mode 41

分散

画像サイズが M \times N としたとき、その画像の分散 (variance) \sigma^2 は次の式で計算できる。

\displaystyle \sigma^2 = \frac{1}{MN} \sum_{i=0}^{N-1} \sum_{j=0}^{M-1} (img(i, j) - \mu)^2

ただし、 img(i, j) は画像の位置 (i, j) の画素値を表す。
分散の平方根 \sigma, (\sigma \le 0)標準偏差という。

関数

meanStdDev()

void cv::meanStdDev(InputArray src,
    OutputArray mean,
    OutputArray stddev,
    InputArray mask = noArray())
mean, stddev = cv2.meanStdDev(src[, mean[, stddev[, mask]]])
コード
cv::Scalar mean, stddev;
cv::meanStdDev(img, mean, stddev);
std::cout << "mean: " << mean[0] << std::endl;  // mean: 81.1051
std::cout << "var: " << stddev[0] * stddev[0]
          << std::endl;  // var: 2255.03
std::cout << "stddev: " << stddev[0] << std::endl;  // stddev: 47.4872
# OpenCV
mean, stddev = cv2.meanStdDev(img)
print(mean, stddev)  # [[ 81.10509036]] [[ 47.48715753]]

# numpy
var = np.var(img)
print('var', var)  # var 2255.03013071

std = np.std(img)
print('std', std)  # std 47.4871575346

参考

  • ディジタル画像処理 P60