<jupyter_start><jupyter_text>情報データ科学演習III第2週：画像の輝度変換第2週では，Pythonで読み込んだ画像に輝度値に対する処理方法を習得する．具体的には，輝度変換，ヒストグラム計算，しきい値による二値化である． まずいろいろなモジュールをインポートするために以下のセルを実行する．notebookを起動したときには，これらのモジュールをインポートしなければ，これらのモジュールの関数を使うことはできない．<jupyter_code>import numpy as np
import os

import matplotlib.pyplot as plt
%matplotlib inline
plt.gray();
from matplotlib.pyplot import imshow

from skimage.io import imread, imsave

import os<jupyter_output><empty_output><jupyter_text>使用する画像ここでは画像の輝度を変換するいくつかの例を見る．そのためにいくつかの画像を用いる． マンモグラフィ（胸部X線写真）のデジタル画像`breast_g.jpg`には，小さな病変部位が白く映っている．図：breast_g.jpg (public domain from wikimedia, "Mammogram Showing Dense And Fatty Breasts") 画像`spine_g.jpg`は，折れた上部胸椎の一部のMRI (Magnetic Resonance Imaging) 画像である．この画像のほとんどの部分が暗いため，輝度値の範囲を拡張することが必要である．図：spine_g.jpg    <NAME> - CC BY-SA 3.0 空港の空撮画像`aerial_g.jpg`はややコントラストが低い画像である．図：aerial_g.jpg(public domain from wikimedia, "Baltimore, Maryland, seen from an airplane") 画像`bone_g.jpg`は手のレントゲン写真であり，骨格構造が映し出されている．図：bone_g.jpg(from pixbay)  =================================== パート1：輝度変換以下では，白黒反転，対数変換，ガンマ変換，コントラスト強調という4つの輝度値変換を行う． 白黒反転輝度値の範囲が$[0, 255]$である画像を白黒反転するには，以下のように輝度値を変換する．$$y = 255 - x$$ここで$x$は入力画像の輝度値，$y$は変換後の輝度値である．これをプロットすると以下のようになる．つまり入力輝度値$x$が小さいほど，出力輝度値$y$は大きくなる．<jupyter_code>plt.figure(figsize=(5, 5))  # プロットのサイズ

x = np.arange(0, 256) # [0, 1, ..., 255]のリスト
y = 255 - x  # xの各要素に対して，この式を適用する

plt.plot(x, y)  # x,yのペアをプロット


# 以下はプロットの設定
plt.xlabel("input pixel value x")
plt.ylabel("output pixel value y")
plt.xlim(0, 255)
plt.ylim(0, 255)
plt.title("Negation transform")
plt.savefig('IP2-plot.pdf')  # プロットの保存．plt.show()の前に行う
plt.show()<jupyter_output><empty_output><jupyter_text>以下では画像に白黒反転の処理を適用する．<jupyter_code># 画像の読み込み
im = imread(os.path.join('images','breast_g.jpg'))
# im = imread(os.path.join('images','spine_g.jpg'))
# im = imread(os.path.join('images','aerial_g.jpg'))
# im = imread(os.path.join('images','bone_g.jpg'))


imshow(im, vmin=0, vmax=255)  # 必ずvmin, vmaxオプションをつけましょう（そうしないと輝度が自動調整されてしまう）
plt.colorbar()
plt.title('original')
plt.show()


x = im.astype(float)  # 分かりやすいように，入力画像をxとおく．また型をfloatにしておく（以降の処理では実数値で処理をするため）．
y = 255 - x  # 白黒反転

imshow(y, vmin=0, vmax=255)  # 結果画像yの表示
plt.colorbar()
plt.title('converted')
plt.show()

imsave('IP2-negation.jpg', y.astype(np.uint8))  # 処理画像の保存．保存するときにはuint8に戻す<jupyter_output><empty_output><jupyter_text>対数変換以下は対数変換の式である．$$y = c \log(1 + x)$$ここで$c$は定数で，$0 \le x$である．これをプロットした以下の図を見ると，入力輝度値$x$が小さいと出力輝度値$y$は大きくなり（つまり暗い部分が明るくなる），$x$が大きくなると$y$も大きくなる．<jupyter_code>plt.figure(figsize=(5, 5))

x = np.arange(0, 256) # [0, 1, ..., 255]

c = 45.0  # 定数cに適切な値を設定
y = c * np.log(1 + x)  # 対数変換


plt.plot(x, y)
plt.xlabel("input pixel value x")
plt.ylabel("output pixel value y")
plt.xlim(0, 255)
plt.ylim(0, 255)
plt.title("Log transform")
plt.savefig('IP2-plot.pdf')  # プロットの保存．plt.show()の前に行う
plt.show()<jupyter_output><empty_output><jupyter_text>以下では画像に対数変換の処理を適用する．<jupyter_code>im = imread(os.path.join('images','breast_g.jpg'))
# im = imread(os.path.join('images','spine_g.jpg'))
# im = imread(os.path.join('images','aerial_g.jpg'))
# im = imread(os.path.join('images','bone_g.jpg'))


imshow(im, vmin=0, vmax=255)
plt.colorbar()
plt.title('original')
plt.show()

x = im.astype(float)
c = 45.0  # 適切な定数を設定
y = c * np.log(1 + x)  # 対数変換

imshow(y, vmin=0, vmax=255)
plt.colorbar()
plt.title('converted')
plt.show()

imsave('IP2-log-trans.jpg', y.astype(np.uint8))  # 処理画像の保存<jupyter_output><empty_output><jupyter_text>ガンマ変換ガンマ変換は以下の式であらわされる．$$y = 255 \left(\frac{x}{255}\right)^\gamma$$ここで$\gamma$は正の定数である．$x=0$は$y=0$に変換され，$x=255$は$y=255$に変換される．$\gamma < 1$のときの指数曲線は，暗い輝度値のある狭い範囲を，広い範囲に拡大する．また逆に，明るい輝度値についても同様である．この効果は$\gamma > 1$の時は逆になる．$\gamma$の値を変えることで，コントラスト強調に使うことができる．<jupyter_code>plt.figure(figsize=(5, 5))

x = np.arange(0, 256) # [0, 1, ..., 255]

gamma = 2.0
y = 255 * ( (x / 255) ** gamma )

plt.plot(x, y)
plt.xlabel("input pixel value x")
plt.ylabel("output pixel value y")
plt.xlim(0, 255)
plt.ylim(0, 255)
plt.title("Gamma transform")
plt.savefig('IP2-plot.pdf')  # プロットの保存．plt.show()の前に行う
plt.show()<jupyter_output><empty_output><jupyter_text>以下では画像にガンマ変換の処理を適用する．<jupyter_code>im = imread(os.path.join('images','breast_g.jpg'))
# im = imread(os.path.join('images','spine_g.jpg'))
# im = imread(os.path.join('images','aerial_g.jpg'))
# im = imread(os.path.join('images','bone_g.jpg'))


imshow(im, vmin=0, vmax=255)
plt.colorbar()
plt.title('original')
plt.show()

x = im.astype(float)
gamma = 2.0  # gammaの値を設定
y = 255 * ( (x / 255) ** gamma )  # ガンマ変換

imshow(y, vmin=0, vmax=255)
plt.colorbar()
plt.title('converted')
plt.show()

imsave('IP2-gamma-trans.jpg', y.astype(np.uint8))  # 処理画像の保存<jupyter_output><empty_output><jupyter_text>コントラスト強調コントラスト強調は次の式で表される．$$y = T(x) = \frac{255}{1 + \Bigl(\frac{M}{x+\epsilon}\Bigr)^E}$$この変換は，M以下の輝度値を暗くし，M以上の輝度値を明るくするため，結果画像は元画像よりもコントラストが高くなる．つまり，M以下の輝度値はこの変換によってより狭い範囲の輝度値に変換され，暗くなる．M以上の輝度値についてはこの逆である．上式のEは，この関数の傾きを制御するパラメータである．なお$\epsilon$は0で割ることを防ぐための小さな値である（例えば0.0001程度）．<jupyter_code>plt.figure(figsize=(5, 5))

x = np.arange(0, 256) # [0, 1, ..., 255]

M = 128
E = 5.0
epsilon = 0.0001
y = 255 / (1 + (M / (x + epsilon)) ** E)
y *= 255 / y.max()

plt.plot(x, y)
plt.xlabel("input pixel value x")
plt.ylabel("output pixel value y")
plt.xlim(0, 255)
plt.ylim(0, 255)
plt.title("Constrast enhancement")
plt.savefig('IP2-plot.pdf')  # プロットの保存．plt.show()の前に行う
plt.show()<jupyter_output><empty_output><jupyter_text>以下では画像にコントラスト強調の処理を適用する．<jupyter_code>im = imread(os.path.join('images','breast_g.jpg'))
# im = imread(os.path.join('images','spine_g.jpg'))
# im = imread(os.path.join('images','aerial_g.jpg'))
# im = imread(os.path.join('images','bone_g.jpg'))


imshow(im, vmin=0, vmax=255)
plt.colorbar()
plt.title('original')
plt.show()

x = im.astype(float)

M = 128
E = 5.0
epsilon = 0.0001
y = 255 / (1 + (M / (x + epsilon)) ** E)  # コントラスト強調
y *= 255 / y.max()  # 最大値が255になるように正規化


imshow(y, vmin=0, vmax=255)
plt.colorbar()
plt.title('converted')
plt.show()

imsave('IP2-contrast-enhanced.jpg', y.astype(np.uint8))  # 処理画像の保存<jupyter_output><empty_output><jupyter_text>レポート課題1- 4つの画像（breast_g.jpg, spine_g.jpg, aerial_g.jpg, bone_g.jpg）のそれぞれに対して，白黒反転，対数変換，ガンマ変換，コントラスト強調を適用する．- それぞれの変換・それぞれの画像に対して，パラメータ（c, gamma, M, E）の値を変えて，どのような変化が出るのか，また最も画像が見やすくなる値はなにか，を考察する．  =================================== パート2：ヒストグラム画像のヒストグラムとは，輝度値の頻度分布を表すグラフである．ヒストグラムの横軸は輝度値，縦軸はその輝度値を持つ画素の個数である．暗い画像のヒストグラムの要素は低い（暗い）輝度値に集中している．逆に，明るい画像のヒストグラムの要素は高い（明るい）輝度値に偏っている．またこれら画像はコントラストが低く，輝度値の中央付近に集中したヒストグラムを持つ．コントラストが高い画像であれば，輝度値の範囲全体に分布するヒストグラムを持つ．ヒストグラムを計算・表示するには，関数`plt.hist`を用いる．<jupyter_code>im = imread(os.path.join('images','breast_g.jpg'))
# im = imread(os.path.join('images','spine_g.jpg'))
# im = imread(os.path.join('images','aerial_g.jpg'))
# im = imread(os.path.join('images','bone_g.jpg'))

imshow(im, vmin=0, vmax=255)
plt.title('original grayscale image')
plt.show()


plt.hist(im.flatten(), bins=16)  # ヒストグラムの計算とプロット

# プロットの設定
plt.xlabel("intensity")
plt.ylabel("frequency")
plt.title('histogram')
plt.savefig('IP2-histogram.pdf')  # ヒストグラムを保存．plt.show()の前に行う
plt.show()<jupyter_output><empty_output><jupyter_text>`plt.hist`の引数：- `im`は入力画像（ただし`flatten()`関数を使って画像を1次元化しておく必要がある）．- `bins`はヒストグラムの区間（ビン，bin）の数である．区間とは，輝度値の範囲を分割した部分範囲のことである．  レポート課題2- 4つの画像（breast_g.jpg, spine_g.jpg, aerial_g.jpg, bone_g.jpg）のそれぞれに対して，区間数binsを128, 64, 32, 16と変更して，それぞれヒストグラムを表示する．- ヒストグラムの形状から画像について分かることを予想し，また実際が画像がそうなっているかどうかを考察する．- どの区間数のときが，輝度分布の形を把握しやすいのかを考察する．  =================================== パート3：しきい値処理しきい値処理とは，画素値があるしきい値$T$以下なら黒に，それより大きければ白にする処理である．以下の3枚の画像に適用する． 図：coins_g.jpg (Vassia Atanassova - CC BY-SA 3.0)図：handwritten.jpg(public domain from wikimedia,    "Original Bacardi daiquiri recipe")図：fingerprint.jpg(public domain from wikimedia,    Picture of an arch fingerprint pattern") 以下ではコインの画像に対してしきい値を`T=152`に設定している．こうすると，ヒストグラムの2つの山を分離するようなしきい値処理となり，つまり画像中の白い部分と黒い部分を分けることができる．<jupyter_code>im = imread(os.path.join('images','coins_g.jpg'))
# im = imread(os.path.join('images','handwritten.jpg'))
# im = imread(os.path.join('images','fingerprint.jpg'))


imshow(im, vmin=0, vmax=255)
plt.show()


plt.hist(im.flatten(), bins=64)
plt.xlabel("intensity")
plt.ylabel("frequency")
plt.title('histogram')
plt.savefig('IP2-histogram.pdf')  # ヒストグラムを保存．plt.show()の前に行う
plt.show()


# しきい値処理
T = 152
im[im <= T] = 0  # imの中で輝度値がT以下の画素の画素値を0にする
im[im > T] = 255  # imの中で輝度値がTより大きい画素の画素値を255にする

imshow(im, vmin=0, vmax=255)  # 処理した画像imを表示
plt.show()

imsave('IP2-binalized.jpg', im)  # 処理画像の保存<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.18563717437221308, 'fraction_numerical': 0.03309082375029336, 'mean_word_length': 7.540080160320641, 'pattern_counts': {'":': 0, '<': 48, '<?xml version=': 0, '>': 48, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '214768', 'license': 'MIT', 'n_tokens_mistral': 5493, 'n_tokens_neox': 5175, 'n_words': 462, 'path': 'ImageProcessingLab/2020-IP2.ipynb', 'repo_name': 'shutoushu/lecture_code', 'size': '8530'}