4
3

More than 1 year has passed since last update.

【matplotlib】0を含んだ画像をlogスケールで白塗りにならずに表示する方法

Last updated at Posted at 2023-01-22

はじめに

matplotlibで0が含まれ画像を対数(log)スケールで表示するとき、以下の図の左側のように0の値が白塗りされてしまう事態に遭遇したことはないだろうか。0値にカラーをつけるなら、右側のような色になってほしいですよね。

image.png

そこで、本記事では、白塗りにならないで正しく表示する方法を紹介します。

実装

Google Colabで作成した本記事のコードは、こちらにあります。

各種インポート

各種インポート
import cv2
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import multivariate_normal
from scipy.signal import convolve

実行時の各種バージョン

Name Version
numpy 1.21.6
matplotlib 3.2.2
scipy 1.7.3

サンプル画像

def sample_img(px=25, sigma=1):
    half_px = px // 2
    x, y = np.mgrid[-half_px:half_px+1:, -half_px:half_px+1:]
    pos = np.dstack((x, y))
    mean = np.array([0, 0])
    cov = np.array([[sigma**2, 0], [0, sigma**2]])
    rv = multivariate_normal(mean, cov)
    img = rv.pdf(pos)
    img[img < 1e-10] = 0  # 本記事用に小さい値を0に置換しておく
    return img

ガウシアンを使います。ただし、本記事では0値がほしいので適当に1e-10より小さい値を0に置換しています。

まずはそのままで見てみよう

何も加工しない場合
img = sample_img()

fig, ax = plt.subplots()
cbar = ax.imshow(img, norm=colors.LogNorm())
fig.colorbar(cbar)
plt.show()

image.png

0値が白塗りされているのがわかります。

方法

白塗りになる原因は、単純にlogスケールで0を表現できないためです。そのため、0値をカラーバーの最小値に置換すれば解決できます。ここでは、カラーバーの最小値を設定しない場合と設定した場合の両方のケースで白塗りにならない表示方法を紹介します。

カラーバーの範囲がオートの場合

カラーバーの範囲がオートの場合
img = sample_img()

# 1番小さい値(0)を2番目に小さい値に置換
second_min = np.unique(img)[1]
mask_img = np.copy(img)
mask_img[img < second_min] = second_min

fig, ax = plt.subplots()
cbar = ax.imshow(mask_img, norm=colors.LogNorm())
fig.colorbar(cbar)
plt.show()

image.png

説明

  • np.unique()を使うことで、画像の値を重複を除き昇順でソートされます。
  • その中には、0値が最小値として含まれていて、その一つ大きい値(np.unique(img)[1])は0以外なので、その値をsecond_minに代入します。
  • mask_img[img < second_min] = second_minで、second_minより小さい値をsecond_minに置換します。
  • 後は、colors.LogNorm())とすることで、オートでmask_imgの最小値・最大値でカラーをつけてくれます。

カラーバーの範囲を任意で指定する場合

カラーバーの範囲を任意で指定する場合
img = sample_img()

# color_minに任意の範囲を指定
color_min = 1e-6
mask_img = np.copy(img)
mask_img[img < color_min] = color_min

fig, ax = plt.subplots()
cbar = ax.imshow(mask_img, norm=colors.LogNorm(vmin=color_min, vmax=None))
fig.colorbar(cbar)
plt.show()

image.png

説明

  • color_minにカラーバーの最小値を指定します。
  • mask_img[img < color_min] = color_minで、color_minより小さい値をcolor_minに置換します。
  • 後は、colors.LogNorm(vmin=color_min, vmax=None)とすることで、最小値の範囲を指定しカラーをつけてくれます。(vmaxには、Noneでなく、適当な値を入れることもできます。)

まとめ

matplotlibで、0値をlogスケールにしたいけど、白塗りになってしまうという問題を解決する方法を紹介しました。
np.unique()は、0が暗黙に含まれて、カラーバーをオートでつけるときに役に立つのでぜひ使ってみてください。
また、単純にカラーの最小値を指定する場合は、やはり、普通にその最小値になるように置換するのが良いかなと思います。

matplotlibで0が含まれた画像の対数表示は、少し慎重に置換しながら解決していきましょう。

参考資料

4
3
2

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
4
3