1.13. 簡単な画像処理

 

 class, function, 属性など基本的なpythonの使い方を習得したので、これまでの復習を兼ねて簡単な画像処理をしてみよう。matplotlibには画像データを読み込む関数image.imreadも用意されている。下記の画像はリンクフリーのサイトからダウンロードした。「白地図 japan05.jpg」で検索すると出てくる。

 
 

これをimage.imreadを使って、ndarrayの行列として読み出してみる。

In [1]:
from matplotlib import image
import matplotlib.pyplot as plt
import numpy as np

img = image.imread('japan05.jpg')
print(type(img))
print(img.shape)
print(img.dtype)
 
<class 'numpy.ndarray'>
(1279, 814, 3)
uint8
 

 上に表示されているように、imgは縦横$1279\times 814$のサイズで、RGBの三つのフレーム(色の強度)からなる$3$次元のnp.ndarrayの形式になっている。要素は.dtypeというndarrayの属性で取得でき、uint8つまりunsigned 8 bit int(符号なし8ビット整数型)であることが分かる。plt.imshowを使って、$3$枚のフレームを表示してみる。

In [2]:
cmaps = ['Reds', 'Greens', 'Blues'] #listでcmapsを定義
plt.figure(figsize=(8, 4))
for n, cmap in enumerate(cmaps):
    plt.subplot(1, 3, n+1)
    plt.imshow(img[:,:,n], cmap=cmap)
    #plt.tick_params(labelleft=False)
    #plt.tick_params(labelbottom=False)
 
 

 forループで紹介したenumerateを使い、listの要素番号nとそれに対応する要素cmapを取得し、plt.subplotplt.imshow内の変数として使っているところがポイントである。なお、plt.subplotを使って横に3枚並べているが、左端のパネルを$0$番目ではなく$1$番目と数えるので、cの部分は$4$行目のようにnでなくn+1としなければならないのはすでに紹介した通りである(ややこしい)。

 

 このデータを使って陸地の部分の要素を$0$、海の部分の要素を$1$にもつ行列を作りたい。このうちのBlueのフレームを図示してみる。

In [3]:
plt.imshow(img[:,:,2], cmap='bone')
plt.colorbar();
 
 

のような感じなので、要素の値が$230$より小さい部分を陸地、それ以外を海とみなすことにする。(この$230$は目でみて適当に選んだ数字)

In [4]:
M = img[:,:,2] < 230
print(M.dtype)
 
bool
 

 if文のところで勉強したように、条件を満たす要素の抽出を行っているので、このMTrueFalseを要素に持つ$1279 \times 814 $の行列である。True/Falseだと扱いにくいので、.astypeという属性を使って、True1False0というunsigned 8 bit int(uint8)に変換する。なおuint8はNumPyの属性なので、.astypeの引数は、np.unit8とする。

In [6]:
M = M.astype(np.uint8)
 

これでMを$1279 \times 814$の0と1からなる行列として抽出できた。

In [7]:
plt.imshow(M, cmap='bone')
plt.colorbar();
 
 

 このデータは偏微分方程式の数値計算のときに使うので、もう少し画像処理をしておく。$y=400$あたり(岩手県付近?)で横切ったときの値をプロットしてみると、

In [10]:
plt.plot(M[400, :])
print(M[400, 810:814])
 
[0 0 1 1]
 
 

のように、画像の枠の部分の2ピクセル分、つまりM[400,0:2], M[400,812:814]が$1$になっていて、陸地とみなされてしまっている。これに注意しつつ、海の部分をもう少し広げて$2000 \times 1500$のサイズの行列にしておく。

In [11]:
map0 = np.zeros([2000, 1500])
a, b = M.shape
a0, b0 = 400, 300
map0[a0:a0+a-4, b0:b0+b-4] = M[2:a-2, 2:b-2]
In [12]:
plt.imshow(map0,cmap='bone');
 
 

 これで2ピクセル分を枠を消して海の領域を広くした形で、日本地図を二値化した行列map0を作ることができた。

 

データの保存

 データはnp.save('ファイル名','配列名)ndarryの形式のまま保存できる。

In [12]:
np.save('map0', map0)
 

 

練習問題

(1.13.1.) リンクフリーの画像などを二値化したり色を変えたりして保存してみよ。

 


当サイトのテキスト・画像の無断転載・複製を固く禁じます。
Unauthorized copying and replication of the contents of this site, text and images are strictly prohibited.
© 2019 Go Yusa