11
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

行列によるグレースケール化編 ~Python画像処理の再発明家~

画像処理ライブラリに頼らず、行列演算だけで画像処理・グレースケール化をするお話。Pythonistaでも可能

基礎編はこちらから

「再発明家」とは

Open CVとかPillowに頼らず、numpyとmatplotlibを使って、様々な画像処理を実際に書いてみる。iOSアプリのPythonistaでも使える組み合わせだ。

import numpy as np
import matplotlib.pyplot as plt

また、画像表示には以下の関数が便利である。(詳しくは基礎編

def img_show(img : np.ndarray, cmap = 'gray', vmin = 0, vmax = 255, interpolation = 'none') -> None:
    '''np.arrayを引数とし、画像を表示する。'''

    #dtypeをuint8にする
    img = np.clip(img,,vmin,vmax).astype(np.uint8)

    #画像を表示
    plt.imshow(img, cmap = cmap, vmin = vmin, vmax = vmax, interpolation = interpolation)
    plt.show()
    plt.close()

グレースケール化

グレースケール化、とは各ピクセルに充てられたRGBの値を白黒の値Yを計算する手法である。
ここでは、基礎編で扱わなかった様々なグレースケールの手法も試してみる。
詳しい説明はリンクを参照。同じ順序で扱っている。

使用画像は'tiger.jpeg'
tiger.jpeg

img = plt.imread('tiger.jpeg')
R, G, B = img[...,0], img[...,1], img[...,2]

カラーと白黒を比較して並べるための関数をここで定義しておく。

def align_show(img_gray):
    #img_grayをN*M*3に変換
    img_pseudogray = np.einsum('ij,k->ijk',img_gray,[1,1,1])

    #横に並べて表示
    img_show(np.concatenate((img,img_pseudogray), axis = 1))

中間値法

$\rm Y=\frac{\max(R,G,B) + \min(R,G,B)}{2}$とする。手法である。要するに、最大値と最小値の平均。
なお実際の計算ではオーバーフローを避けるために上式とは一部、計算の順序を変えてある。

img_mid_v = np.max(img, axis = 2)/2 +np.min(img, axis = 2)/2
img_show(img,img_mid_v)

mid_v.png

パッと見問題ないが、迷路の真ん中のボタン(?)が見えにくい。

NTSC 係数による加重平均法

$\rm Y = ( 0.298912 R + 0.586611 G + 0.114478 B )$とする手法である。これらの係数は、各RGBが人間の目に与える影響(心理的加重)を考慮に入れた結果である。

img_ntsc = (0.298912 * R + 0.586611 * G + 0.114478 * B)
align_show(img_ntsc)

ntsc.png

良さげ

HDTV 係数による加重平均と補正

$\rm Y = ((0.222015 R)^X + (0.706655 G)^X + (0.071330 B)^X )^{1/X}$とする手法である。これも心理的加重を取り入れている。

X = 2.2
img_hdtv = ((0.222015*R)**X + (0.706655*G)**X + (0.071330*B)**X)**(1/X)
align_show(img_hdtv)

hdtv.png

私にはNTSC法との違いがわからないくらいの違いである。

単純平均法

$\rm Y = \frac{R + G + B}{3}$という平均をとる方法である。一番直感的なやり方だろう。加重平均をとる前のNTSC法ともいえるかも。

img_mean = np.mean(img)
align_show(img_mean)

mean.png

Gチャンネル法

$\rm Y = G$というGチャンネルのみを取り出す方法。一番速そう。

img_g_channel = G
align_show(img_g_channel)

g_channel.png

赤色部分がちょっと濃すぎるかな…

中央値法

$\rm Y = median(R, G, B)$という中央値を取り出す方法。中間値法と似た発想な気がする。

img_median = np.median(img, axis = 2)
align_show(img_median)

median.png

中間値法と同じく、緑が濃すぎる。

まとめ

中間値 NTSC HDTV
元画像
単純平均 Gチャンネル 中央値

sumup.png

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
11
Help us understand the problem. What are the problem?