0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

OpenCV で 16bit/pixel グレイスケール画像を 8bit/pixel にする

Last updated at Posted at 2022-11-11

OpenCVでの16bit画像、しかも値に偏りのある場合の、8bitノーマライズの仕方メモ
C++, Python でそれぞれについて
ここでは、1CH(グレースケール)の話

各画素の値分布がこんな感じのとき、普通にやると真っ暗な画像になってしまう。
また定数でやらないとノイズで動画がチラつく。

2022-11-11_22h46_36.jpg

その16bit画像が「0x0000が真っ黒/0xFFFFが真っ白」というわけではなく、こんなときにやるノーマライズ

  • 実際は12bitまでしか使っていない
  • 最低値が0じゃない
  • N以下/M以上はノイズ

その画像のシェイプを確かめる

C++ シェイプ確認

// 型: cv::Mat
cout << frame.rows << ", " << frame.cols << ", " << frame.channels() << endl;
// → HEIGHT, WIDTH, 1
cout << frame.type() << endl;
// → 2 (つまりCV_16U)

Python シェイプ確認

# 型: numpy.ndarray
print(frame.shape)
# → (HEIGHT, WIDTH, 1)
print(frame.dtype)
# → uint16

普通のノーマライズ

今回はこの仕様で困ったわけだが、何も考えずにcv2.imshow()すると、単純に256で割られたノーマライズで表示される。

If the image is 16-bit unsigned, the pixels are divided by 256. That is, the value range [0,255*256] is mapped to [0,255].

これは、次のやり方と同じ。
従ってこれらはcv2.imshow()するためにはやる必要のないことたち。

C++ 普通のノーマライズ

src.convertTo(dist, CV_8UC1, 1. / 256.);

Python 普通のノーマライズ

dist = (src/256).astype('uint8')

min/maxを指定したノーマライズ

ちなみに下記でmin/maxを入れ替えると白黒反転する。

C++ min/max指定ノーマライズ

const int MIN = 200;
const int MAX = 1200;

cv::Mat dist;
double alpha = 256. / ((double)MAX - MIN);
double beta = alpha * -1. * MIN;
frame.convertTo(dist, CV_8UC1, alpha, beta);

cv::imshow("normalised frame", dist);
cv::waitKey(1);

Python min/maxノーマライズ

MIN = 200;
MAX = 1200;

alpha = 256.0 / (MAX - MIN)
beta = alpha * MIN * -1
dist = cv2.convertScaleAbs(frame, alpha=alpha, beta=beta)

cv2.imshow("normalised frame", dist)
cv2.waitKey(1)

min/max 動的に決めるノーマライズ

その画像中のmin/maxを取得するのが自然っぽいが、ノイズの影響を受けまくる。
冒頭のような、ノイズが存在する画像の動画だと、チラつきが気になってしまう。

やるなら、動画中でmin/maxあまり振れすぎないようするか、平均/標準偏差(cv::meanStdDev)を取得してmin/max決定するのがよさげ。

ちなみに「画像中のmin/max」で正規化する、そのやり方

    double min, max;
    cv::minMaxLoc(frames[1], &min, &max);
    alpha = 256. / (max - min);
    beta = alpha * -1. * min;
    frames[1].convertTo(dist4, CV_8UC1, alpha, beta);

    cv::normalize(frames[1], dist1, 0., 255., cv::NORM_MINMAX, CV_8UC1);

が同じことをしているのでこれでいい。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?