転置ガイドライン

2015-0414
コンピュータビジョン
Solem, J. (2012)
白井英俊
Programming Computer Vision with Python
(相川訳「実践 コンピュータビジョン」オライリー・ジャパン, 2013)
訳者のまえがき
読みこなす上でのポイント
1.数学、特にベクトルと行列の計算に慣れていること
2.Python ―
習得しやすく生産性が高い。数学ライブラリがあり高速で正確
著者まえがき
ガイドライン
・解説を読んだらすぐにサンプルコードを試す
・細部にこだわらず広い視点をもつ。理論よりも創発性を重視
前提条件
・基本的なプログラミング、エディタの使い方、データ型、実行方法など
・基本的な数学。行列やベクトル演算、標準的な数学関数、微分係数や勾配の知識
本書で学べること
・Python を用いた画像処理の実践
・各種のコンピュータビジョン技術
・基礎的なアルギリズムの実装法や応用
サンプルコード:物体認識や類似画像検索、文字認識、オプティカルフロー、追跡
(トラッキング)
、3 次元復元、ステレオ画像、拡張現実感(AR:Augmented Reality)、ジェ
スチャー認識、パノラマ画像合成、画像のセグメンテーション(領域分割)、ノイズ除去、画像
分類など
コンピュータビジョンとは
画像から情報を自動抽出すること
「情報」: 3D モデル、カメラ位置、物体検出や認識、画像内容のグループ化や検索など、さらに
画像のワーピングやノイズ除去、拡張現実感なども
使用する Python: バージョン 2.7
ベクトルや行列: NumPy というモジュールの配列 array 型で表す
処理結果の可視化:Matplotlib
数式: インライン表記 f (x) = w Tx + b
もしくは
𝑓𝑓 (𝐱𝐱) = ∑𝑖𝑖 𝑤𝑤𝑖𝑖 𝑥𝑥𝑖𝑖 + 𝑏𝑏
スカラーを小文字(s、r、λ、θ、...)、行列を大文字(A、V、H、...)、ベクトルを太字の小
文字(t、c、...)
画像を配列で表す場合は I 、2D 上の点は x = [x,y]、3D 上の点は X = [X,Y,Z ]
2015-0414
コンピュータビジョン
白井英俊
1章 基本的な画像処理
画像の扱い方や処理方法, Python の主要なパッケージ、画像の読み込み・変換、拡大縮
小、微分、表示、結果の保存などのための基本的なツールの紹介
1.1 PIL(Python Imaging Library)
一般的な画像の取り扱いのほか、サイズ変更、切り抜き、回転、色変換といった画像の基
本操作
画像ファイル形式の読み込み、保存 (表示はできない?)
Image モジュール:最も重要なモジュール ――― 読み込みの例
from PIL import Image
pil_im = Image.open('empire.jpg')
# 戻り値は PIL 画像オブジェクト
色変換: convert() メソッド
pil_im = Image.open('empire.jpg').convert('L') #読み込んでグレースケール変換
サンプルコード; http://www.pythonware.com/library/pil/handbook/index.htm (図 1.1)
1.1.1 画像のファイル形式変換
画像の保存:save( ) メソッド
サンプルコード:
from PIL import Image
# PIL モジュールから Image を使えるようにする
import os
# os モジュールを使えるようにする
filelist = ['foo.jpg', 'bar.bmp', 'zot.png']
# 画像ファイルのリスト
for infile in filelist:
# それぞれのファイルに対して
outfile = os.path.splitext(infile)[0] + ".jpg"
# 出力ファイルを指定
if infile != outfile:
# 入力ファイルが jpg ファイルでなければ
try:
# エラーが起きた時の対処
Image.open(infile).save(outfile)
# 画像ファイルを開いて保存
except IOError:
# ファイルが開けない場合のエラー
print "cannot convert", infile
この本のサンプルコード imtools.py に。ディレクトリの中のすべての JPEG 画像ファイ
ル名のリストを取得する関数が定義されている:
import os
def get_imlist(path):
""" path に指定されたディレクトリのすべての jpg ファイル名のリストを返す """
return [os.path.join(path,f) for f in os.listdir(path) if f.endswith('.jpg')]
使用例
filelist = imtools.get_imlist('.') # 現在のディレクトリ(‘.’)の JPEG ファイルリストを返す
2015-0414
コンピュータビジョン
1.1.2 サムネイルの作成
pil_im.thumbnail((128,128))
白井英俊
#幅と高さの最大値が 128 ピクセルのサムネイル生成
1.1.3 領域のコピーと貼りつけ
PIL は左上隅を(0,0)とする座標系を採用
box = (100,100,400,400)
region = pil_im.crop(box)
# crop で画像の切り抜き(引数は(左,上,右,下)の座標値)
貼り付け:
region = region.transpose(Image.ROTATE_180)
# 180 度回転
pil_im.paste(region,box)
# box で指定された範囲に画像 region を貼り付け
1.1.4 拡大縮小と回転
画像のサイズ変更:
out = pil_im.resize((128,128))
画像の回転:
out = pil_im.rotate(45)
# resize 関数、引数は幅と高さのサイズ
# rotage 関数。引数は時計回りの角度
例:図 1-1-左から、原画像、グレースケール化したもの、一部を切り抜き回転して貼
りつけたもの、サムネイル画像
1.2 Matplotlib
グラフを描いたり画像に点や直線、曲線を描画するためのモジュール(PIL よりも強力)
PyLab インタフェース: グラフ描画用の関数群
1.2.1 画像と点と線を描画する
画像と点と線を描画する例
from PIL import Image
from pylab import *
# 配列に画像を読み込む
# import * には注意せよ(あまり使わない方が良い)
# import pylab as pl などとするほうがよい
im = array(Image.open('empire.jpg'))
# pylab.array
# 画像を表示するための準備(show で表示)
imshow(im)
# 点の座標
# pylab.imshow
x = [100,100,400,400]
y = [200,500,200,500]
# 赤い星マークで点を描画する
plot(x,y,'r*')
# pylab.plot
2015-0414
コンピュータビジョン
白井英俊
# 最初の 2 点間に線を描画する
plot(x[:2],y[:2])
# pylab.plot
# タイトルを追加し、描画結果を表示する
title('Plotting: "empire.jpg"')
# pylab.title
show()
# pylab.show()
#通常、1 つのスクリプトにつき 1 回だけ、スクリプトの末尾で呼び出す
#スクリプトの実行をブロックし、ウィンドウが閉じられるまでスクリプトを停止
座標軸の非表示: axis('off')
Plot 関数の引数の例:
線: ‘-‘ 実線、’- -‘ 破線、’:’ 点線
色: b 青,g 緑,r 赤,c シアン、m マゼンタ、y 黄、k 黒、w 白)
マーカ: . 点、o 丸、s 四角、* 星、+ 十字、x ✕
plot(x,y)
# デフォルトの青の実線
plot(x,y,'r*')
# 赤の星マーク plot(x,y,'go-')
# 緑の線で、丸マーク付き
plot(x,y,'ks:')
# 黒の点線で、四角マーク付き
1.2.2 画像の等高線とヒストグラム
等高線はすべての座標[x,y]について 1 つの値を要求→グレースケールの画像が必要
from PIL import Image
from pylab import *
# 画像を配列に読み込む
im = array(Image.open('empire.jpg').convert('L')) # pylab.array
# 新しい図を作成する
figure()
# pylab.figure
# 色を使わない
gray()
# pylab.gray()
# 左上隅を原点とする等高線を表示する
contour(im, origin='image')
axis('equal')
# pylab.axis
axis('off')
# pylab.axis
# pylab.contour
ヒストグラム: ピクセル値の分布を描画(ビンの数を指定)
figure()
# pylab.figure
hist(im.flatten(),128) # 引数は「1 次元の array」と「ビンの数」 pylab.hist
show()
# pylab.show
flatten()メソッドは、多次元配列の行方向に値をとって 1 次元の配列に変換
2015-0414
コンピュータビジョン
白井英俊
1.2.3 インタラクティブな注釈
ginput()関数: 簡単に点を入力できる
例:画像を表示した後、ユーザーがウィンドウ上で画像領域を 3 回クリックするのを待ち、
クリックされた座標[x,y]をリスト x に保存
from PIL import Image
from pylab import *
im = array(Image.open('empire.jpg')) # pylab.array
imshow(im)
# pylab.imshow
print '3 点クリックしてください'
x = ginput(3)
#pylab.ginput
print 'クリックした座標:',x
show()
# pylab.show
1.3 NumPy :科学技術計算パッケージ
NumPy には、ベクトルや行列、画像などを表現するための配列オブジェクトや線形代数
の関数など、便利な機能がある
配列オブジェクトにより、行列の積や転置行列の作成、方程式の解法、ベクトルの積、正
規化などが可能---用途: 画像変換、ワーピング、変形モデリング、画像認識、グループ分け
1.3.1 配列による画像表現
NumPy の配列は多次元: ベクトルや行列、画像を表現可能
配列は「すべての要素が同じ型でなければならない」制約があるリストとみなせる
配列: shape の例 (800, 569, 3) --- 各次元の大きさ(行数,列数,色数)
dtype の例
uint8 --- 配列の要素のデータ型を表す文字列
通常、画像は符号なし 8 ビット整数(uint8)、浮動小数点数(float32)にするには
im = array(Image.open('empire.jpg').convert('L'),'f') のように’f ’指定が必要
配列の要素には添字を使ってアクセス: 例 value = im[i,j,k]
配列のスライスを使って複数の要素にアクセス
例:
im[i,:] = im[j,:] # j 行の値を i 行に代入する
im[:,i] = 100 # i 列のすべての値を 100 にする
# 座標(i,j)、色 k の値
im[:100,:50].sum() # 最初の 100 行と 50 列の値の合計
im[50:100,50:100] # 50~100 行と、50~100 列(100 番目は含まれない)
im[i].mean() # i 行の平均
im[:,-1] # 最後の列
im[-2,:] (or im[-2]) # 最後から 2 番目の行
2015-0414
コンピュータビジョン
白井英俊
添字が 1 つだけのときは、行の添字として解釈
マイナスの添字は末尾から逆方向に数える
1.3.2 グレーレベルの変換
画像を Numpy 配列に読み込むことで、数値演算が可能
例としてグレーレベルの変換
from PIL import Image
from numpy import *
# import numpy as np とすることが多い
im = array(Image.open('empire.jpg').convert('L')) # np.array
im2 = 255 - im
# 画像を反転する
im3 = (100.0/255) * im + 100
# 100~200 の値に縮める
im4 = 255.0 * (im/255.0)**2
# 2 乗する:暗いピクセルをより暗く
print int(im.min()), int(im.max()) # np.int ピクセル値の最大値と最小値
配列から画像に戻す
pil_im = Image.fromarray(im) # 配列から PIL 画像に戻す
pil_im = Image.fromarray(uint8(im)) #、「uint8」以外のデータ型に変換した場合
参考: 画像表示には pylab の imshow と show を用いる
1.3.3 画像のサイズ変更
、配列のサイズを変えるのは容易ではないため、サイズ変更関数を用意:
def imresize(im,sz):
# imtools.py で定義
""" PIL を使って画像配列のサイズを変更する """
pil_im = Image.fromarray(uint8(im))
1.3.4 ヒストグラム平坦化
グレースケールの画像とヒストグラムのビン数を渡すと、ヒストグラム平坦化された画像
と、ピクセル値の変換に用いられた累積分布関数を返す関数
def histeq(im,nbr_bins=256):
# imtools.py で定義
""" グレースケール画像のヒストグラム平坦化 """
# 画像のヒストグラムを得る
imhist,bins = histogram(im.flatten(),nbr_bins,normed=True)
cdf = imhist.cumsum()
# 累積分布関数
cdf = 255 * cdf / cdf[-1]
# 正規化
# cdf を線形補間し、新しいピクセル値とする
im2 = interp(im.flatten(),bins[:-1],cdf)
return im2.reshape(im.shape), cdf
2015-0414
コンピュータビジョン
白井英俊
使用例: コントラストが増して暗い領域が明確になる
from PIL import Image
from numpy import *
im = array(Image.open('AquaTermi_lowcontrast.jpg').convert('L'))
im2,cdf = imtools.histeq(im)
1.3.5 平均画像
画像列から平均画像を求める:画像はすべて同じサイズと仮定し、総和を画像数で割る
def compute_average(imlist):
# imtools.py で定義
""" 画像列の平均を求める """
# 最初の画像を開き、浮動小数点数の配列に変換する
averageim = array(Image.open(imlist[0]), 'f')
for imname in imlist[1:]:
try:
averageim += array(Image.open(imname))
except:
print imname + '...skipped'
averageim /= len(imlist)
# 平均を uint8 に変換する
return array(averageim, 'uint8')
1.3.6 画像の主成分分析
主成分分析(Principal Component Analysis:PCA)
:次元を削減するのに便利な方法
訓練データの多様性をできるだけ少ない次元数で表現するのに最適
PCA で出力された写像行列は、重要度順に並んだ座標軸に座標値を変換するものとみな
せる
画像に PCA を適用するには、NumPy の flatten()メソッドなどにより、画像を 1 次元の
ベクトルに変換する
主成分を計算する前に、各行を平均画像からの相対値に変換(平均画像が原点になるよう
にセンタリング), その後で特異値分解(Singular Value Decomposition:SVD)
pca.py の内容
-------------------------------------------------------------------------------------------------------------------from PIL import Image
from numpy import *
def pca(X):
""" 主成分分析
入力:X, 訓練データを平板化した配列を行として格納した行列
出力:写像行列(次元の重要度順), 分散, 平均 """
# 次元数を取得
2015-0414
コンピュータビジョン
白井英俊
num_data,dim = X.shape
# データをセンタリング
mean_X = X.mean(axis=0)
X = X - mean_X
# 平均を引くことでセンタリング
if dim>num_data:
# PCA - 高次元のときはコンパクトな裏技を用いる
M = dot(X,X.T) # 共分散行列
e,EV = linalg.eigh(M) # 固有値と固有ベクトル
tmp = dot(X.T,EV).T
# ここがコンパクトな裏技
V = tmp[::-1] # 末尾の固有ベクトルほど重要なので、反転する
S = sqrt(e)[::-1] # 固有値の並びも反転する
for i in range(V.shape[1]):
V[:,i] /= S
else: # PCA - 低次元なら特異値分解を用いる
U,S,V = linalg.svd(X)
V = V[:num_data] # 最初の num_data の分だけが有用
# 写像行列と、分散、平均を返す
return V,S,mean_X
-------------------------------------------------------------------------------------------------------------------pca.py を用いて主成分分析を行う:
fontimages.zip を使用
from PIL import Image
from numpy import *
from pylab import *
import pca
im = array(Image.open(imlist[0])) # サイズを得るため画像を 1 つ開く
m,n = im.shape[0:2] # 画像のサイズを得る
imnbr = len(imlist) # 画像数を得る
# すべての平板化画像を格納する行列を作る
immatrix = array([array(Image.open(im)).flatten()
for im in imlist],'f')
# 主成分分析を実行する
V,S,immean = pca.pca(immatrix)
# 画像を表示する(平均と、最初の 7 つの主成分)
figure()
gray()
subplot(2,4,1)
imshow(immean.reshape(m,n))
2015-0414
コンピュータビジョン
for i in range(7):
subplot(2,4,i+2)
imshow(V[i].reshape(m,n))
# 1 次元表現から画像に戻す
show()
1.3.7 pickle モジュール
pickle: Python オブジェクトを文字列表現に変換、その逆は unpickle
import pickle
# 平均と主成分を保存する
f = open('font_pca_modes.pkl', 'wb')
pickle.dump(immean,f)
pickle.dump(V,f)
# immean, V の順で記憶
f.close()
保存したデータからの読み出し: load()メソッド
import pickle
# 平均と主成分を読み出す
f = open('font_pca_modes.pkl', 'rb')
immean = pickle.load(f)
V = pickle.load(f)
# immean, V の順で取り出し
f.close()
オブジェクトの順番を同じにすることに注意
ファイルの読み書きのための with ステートメント
# ファイルを開いて保存する
import pickle
with open('font_pca_modes.pkl', 'wb') as f:
pickle.dump(immean,f)
pickle.dump(V,f)
# ファイルを開いて読み込む
import pickle
with open('font_pca_modes.pkl', 'rb') as f:
immean = pickle.load(f)
V = pickle.load(f)
白井英俊
2015-0414
コンピュータビジョン
白井英俊
1.4 SciPy : NumPy 上に構築されたオープンソースの数学パッケージ
1.4.1 画像をぼかす: 画像の畳み込みの例
Iσ= I *Gσ ガウシアンカーネルを用いた(グレースケール)画像 I の畳み込み
Gσ =
1
2𝜋𝜋𝜋𝜋
𝑒𝑒 −(𝑥𝑥
2 +𝑦𝑦2 )
/2𝜎𝜎 2
scipy.ndimage.filters: 高速な 1 次元分割により、畳み込みを計算 from PIL import Image
from numpy import *
from scipy.ndimage import filters
im = array(Image.open('empire.jpg').convert('L'))
im2 = filters.gaussian_filter(im,5)
# 標準偏差を 5 とした
カラー画像をぼかすには、色チャンネルごとにガウシアンぼかし
im = array(Image.open('empire.jpg'))
im2 = zeros(im.shape)
for i in range(3):
im2[:,:,i] = filters.gaussian_filter(im[:,:,i],5)
im2 = uint8(im2)
1.4.2 画像の微分
画像の勾配は、∇I = [I x, I y]T
画像の微分を計算するには離散近似
Ix= I *Dx
Iy= I *Dy
代表的なものは Prewitt フィルタと Sobel フィルタ
scipy.ndimage.filters モジュール標準の畳み込みを使って、簡単に実装できる
from PIL import Image
from numpy import *
from scipy.ndimage import filters
im = array(Image.open('empire.jpg').convert('L'))
# Sobel 微分係数フィルタ
imx = zeros(im.shape)
filters.sobel(im,1,imx)
imy = zeros(im.shape)
filters.sobel(im,0,imy)
magnitude = sqrt(imx**2+imy**2)
sobel()関数の第 2 引数により x か y の微分の方向を選択し、第 3 引数に出力を格納
正の微分係数は明るいピクセル、負の微分係数は暗いピクセル、灰色の領域は 0 に近い値
2015-0414
コンピュータビジョン
白井英俊
この方式の欠点:微分係数が画像の解像度に依存
ガウシアン微分フィルタ:ノイズにロバスト、いろいろな解像度に対応
Ix= I *Gσx
Iy= I * Gσy
Gx と Gy : x 方向と y 方向の標準 のガウス関数 G
filters.gaussian_filter()関数は、次のように引数を追加によりガウシアン微分を計算可能
sigma = 5 # 標準偏差
imx = zeros(im.shape)
#第 3 引数に微分の方向を指定し、第 2 引数に標準偏差
filters.gaussian_filter(im, (sigma,sigma), (0,1), imx) imy = zeros(im.shape)
filters.gaussian_filter(im, (sigma,sigma), (1,0), imy)
1.4.3 モルフォロジー: 物体を数える
通常、モルフォロジーは 2 値画像だが、グレースケールにも適用可能
scipy.ndimage モジュールの morphology
scipy.ndimage モジュールの measurements :2 値画像の計数や測定関数
物体を数える:
from scipy.ndimage import measurements,morphology
# 画像を読み込み、閾値処理で 2 値化する
im = array(Image.open('houses.png').convert('L'))
im = 1*(im<128)
# 2 値の配列に変換
labels, nbr_objects = measurements.label(im)
print "Number of objects:", nbr_objects
# モルフォロジー 物体を分離する
# binary_opening()の第 2 引数は構造要素:y 方向に 9 ピクセル(上下に 4 ずつ)、x 方向に
5 ピクセル
im_open = morphology.binary_opening(im,ones((9,5)),iterations=2)
labels_open, nbr_objects_open = measurements.label(im_open)
print "Number of objects:", nbr_objects_open
非 0 の要素が隣接ピクセルとして扱われる
1.4.4 便利な SciPy モジュール
io, misc : 入出力のためのモジュール
scipy.io.loadmat : Matlab の .mat 形式のデータ読み込み
scipy.io.savemat : Matlab の .mat 形式のデータ保存
2015-0414
コンピュータビジョン
白井英俊
scipy.misc モジュールの imsave()関数 : 配列を画像ファイルに保存
scipy.misc.lena() : Lena(512×512 のグレースケール画像)
1.5 高度な例:画像のノイズ除去
画像のノイズ除去: 詳細や構造を保存しながら画像のノイズを除去する処理
Rudin-Osher-Fatemi(ROF)のノイズ除去モデルを用いた例
グレースケール画像 I の Total Variation(TV)を勾配のノルムの和として定義
J(I) = ∫|∇𝐼𝐼 |𝑑𝑑𝒙𝒙
ノイズ除去した画像 U は以下の値を最小化
min‖𝐼𝐼 − 𝑈𝑈‖2 + 2λ𝐽𝐽(𝑈𝑈)
𝑈𝑈
rof.py の中の denoise() 関数
応用例:
from PIL import Image
from pylab import *
import rof
im = array(Image.open('empire.jpg').convert('L'))
U,T = rof.denoise(im,im)
figure()
gray()
imshow(U)
axis('equal')
axis('off')
show()
演習問題をやってみよう