end0tknr's kipple - web写経開発

太宰府天満宮の狛犬って、妙にカワイイ

PIL / Pillow , numpy による画像処理入門 その3 - 平板化(1次元化)と主成分分析(principal component analysis; PCA)

www.oreilly.co.jp

更に↑こちらで提供されているサンプルコードのまんま

実行はできましたが、算出結果の正しさは確認していません

#!/usr/bin/python
# -*- coding: utf-8 -*-

from PIL import Image
import numpy
import os


def main():
    # 指定dir以下のjpg file名一覧を取得
    imlist = get_imlist('a_thumbs')

    im = numpy.array(Image.open(imlist[0]))
    m,n = im.shape[0:2] # jpg size

    imnbr = len(imlist) # files size


    # 平板化(1次元化)し行列へ格納
    immatrix = numpy.array([numpy.array(Image.open(im)).flatten()
                            for im in imlist],'f')

    # 主成分分析 - 返り値:写像行列(次元の重要度順), 分散, 平均
    V,S,immean = my_pca(immatrix)
    print V


def get_imlist(path):
  """ pathに指定されたフォルダのすべてのjpgファイル名のリストを返す """
  return [os.path.join(path,f) for f in os.listdir(path) if f.endswith('.jpg')]


def my_pca(X):
  """ 主成分分析
   入力:X, 訓練データを平板化した配列を行として格納した行列
   出力:写像行列(次元の重要度順), 分散, 平均 """

  # 次元数を取得
  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 = numpy.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 = numpy.linalg.svd(X) 
    V = V[:num_data] # 最初のnum_dataの分だけが有用

  # 写像行列と、分散、平均を返す
  return V,S,mean_X


if __name__ == '__main__':
    main()