11
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

8-bit grayscale画像へのダウンスケーリングと画像コントラスト

Last updated at Posted at 2019-11-07

前提

ここでいうダウンスケーリングは、画像の標本化でいうところのダウンスケールを意味します。

画像のダウンスケーリング

ここでは、グレースケール画像を対象に話をします。
一般的に、グレースケール画像は8-bit, 16-bit, 32-bit等、「1チャンネル」の画素の集まりで構成されています。
(RGBなどのカラー画像は、R、G、Bそれぞれのチャンネルがあり、これらを統合して画像にしています。この点は重要です。言い換えれば、RGB画像は、8-bit grayscale画像が3枚分あると言えます。厳密にはα成分(透明度を指定する成分)がある場合もありますが、α成分も8-bit grayscale画像が一枚分増えたようなものです。)

よく医用画像で使われるのが、16-bit画像です。
16-bit画像は、0-65535の間の数値をピクセル値として保持できます。
一方で、8-bit画像は、0-255までの数値しか保持できません。
(符号付き、符号なしについてはここでは敢えて触れません。)

画像処理や機械学習などでは、計算を簡便にするため、あるいは処理を高速にするために、高いビットの画像を8-bit画像にダウンスケールして変換する処理を行います。
このダウンスケールの際にお作法を間違えると、画像がおかしなことになるので注意が必要です。

サンプル画像

JIRAの胸部レントゲンをお借りします。
LEEとついているものは非圧縮画像という意味です。これを使います。
サンプル画像

ダウンスケール例(16-bitから8-bit)

まずは、画像をロードしてnumpyのndarrayとして扱うために、pydicomを使って行きます。

!pip install pydicom

データをロードします。

import pydicom
import numpy as np
ds = pydicom.dcmread('CR_LEE_IR87a.dcm')#パスを指定する

#ピクセルを取り出す(ndarrayとして扱っています)
pixels = ds.pixel_array

# 左右反転しているので戻す
pixels = np.fliplr(pixels)

#画像として表示
import matplotlib.pyplot as plt
plt.imshow(pixels,cmap="gray")#2つとも必要
plt.show() 

ダウンロード (2).png

念のため、この画像が8-bitでないことを確認します。
DICOMタグからもわかりますが、直接ピクセルをみてもわかります。

# この画像の画素を見てみる
print (pixels[512,512]) # 3186

画素(x,y)(512,512)にあるピクセル値は3186であることが確認できます。
つまり、0-255の間にない、かつ、実数ではないので16-bitであることがわかります。

これで準備が出来ました。

numpy

単純に8bitに変換してみます。

# numpyで8 bit変換してみる
np_img = pixels.astype('uint8')
plt.imshow(np_img,cmap="gray")
plt.show() 

ダウンロード (3).png

違うなあ。

Pillow

# pillowを使う
from PIL import Image, ImageOps
pil_img = Image.fromarray(pixels)
pil_img = pil_img.convert('L')#L:grayscale
plt.imshow(pil_img,cmap="gray")#2つとも必要
plt.show() 
print(np.asarray(pil_img)[512,512]) #255, 完全にアウトオブレンジな感じです。

ダウンロード (4).png

これも違うなあ。

OpenCV

# opencvを使う
# 変換可能
# pixels は16 bit配列の変数とする。
import cv2
cv_img8 = np.zeros(pixels.shape)  # dummy変数
cv_img8 = cv2.convertScaleAbs(pixels-np.min(pixels), cv_img8, 255/(np.max(pixels)-np.min(pixels)), beta=0) #  2021/6/22修正
cv_img8 = cv_img8.astype(np.uint8)
plt.imshow(cv_img8, cmap="gray")
plt.show() 
print(cv_img8[512,512])

Scikit-image

# skimageを使う
import skimage
sk_img = skimage.img_as_ubyte(pixels)
plt.imshow(sk_img,cmap="gray")#2つとも必要
plt.show() 

お!と思うが、これはまやかしで、よくみると画素が潰れている。

ダウンロード (5).png

ImageJのアルゴリズムを用いたダウンスケール

ImageJのダウンスケールを実装してみました。
最大値、最小値と、スケーリングファクタで正規化します。

# ImageJから拝借したノーマリゼーション
pixels_ = np.copy(pixels)
amin=np.amin(pixels_)
amax=np.amax(pixels_)
pixelsByte = ((pixels_-amin)/(amax-amin))*255
# pixelsByte = ((pixels_-amin)/(amax-amin+1))*256
pixelsByte = np.clip(pixelsByte,0,255)
pixelsByte = np.uint8(pixelsByte) # 符号なしバイトに変換

print(np.asarray(pixelsByte)[512,512])
plt.imshow(pixelsByte,cmap="gray")
plt.show() 

ダウンロード (6).png

これこれ。求めてた画像です。

Visionary Imaging Services, Inc.

11
13
3

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
11
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?