2013年10月21日月曜日

PyQtでcheckboxのリストを作成

PyQtでチェックボックスのリストを作成した。
いままでだとVBoxLayoutなんかでWidgetを追加していたけど、今回はQListViewQStandardItem, QStandardItemModelというのを使って行った。StackOverflowを参考にした。少しスマートにできた気がした。


from PyQt4 import QtGui, QtCore
import sys


class MyItemModel(QtGui.QStandardItemModel):
 def __init__(self, parent=None):
  super(QtGui.QStandardItemModel, self).__init__(parent)
  for i in xrange(10):
   item = QtGui.QStandardItem("item%d" % i)
   item.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled)
     item.setData(QtCore.QVariant(QtCore.Qt.Checked), QtCore.Qt.CheckStateRole)
     self.appendRow(item)

    self.itemChanged.connect(self.printState)

   def printState(self):
    states = []
    for i in xrange(self.rowCount()):
     states.append(self.item(i).checkState())
    print states


      
class MainWindow(QtGui.QMainWindow):
 def __init__(self, parent=None):
  super(MainWindow, self).__init__(parent)
  self.model = MyItemModel(self)
    view = QtGui.QListView(self)
    view.setModel(self.model)
    self.setCentralWidget(view)  

def main(args):
    app = QtGui.QApplication(sys.argv)
    form = MainWindow()
    form.show()
    
    sys.exit(app.exec_())

    
    
if __name__ == "__main__":
    main(sys.argv)


Changing the properties of Excel plots using win32com module in Python

Like yesterday, I will put some simple example of changing plot properties.

Names, indices, etc of all the plots are accessed in for loop.
Take a look at the below website for other examples of plot control.

import win32com.client
from win32com.client import constants as consts

def main():
    xl = win32com.client.gencache.EnsureDispatch("Excel.Application")
    xl.Visible = True
    
    
    ws = xl.ActiveSheet    
    
    rng = xl.Range("C2:J20")

    nch = ws.ChartObjects().Count
    for i in range(1,nch+1):
        cobj = ws.ChartObjects(i)
        cobj.Left, cobj.Top, cobj.Width, cobj.Height = (rng.Left, rng.Top+(i-1)*rng.Height, rng.Width, rng.Height)
        print cobj.Index, cobj.Name, cobj.Left, cobj.Top, cobj.Width, cobj.Height
        
        ax = cobj.Chart.Axes(consts.xlValue, consts.xlPrimary)
        ax.MaximumScale = 150
        ax.MinimumScale = -50
        
        
if __name__ == "__main__":
    main()


2013年10月19日土曜日

simple Excel bar plot example using python's win32com module

Here is a simple example of Python interface with Excel using win32com module.
You can put other charts by setting the arguments in AddChart().
See the website below for the name of charts.


import win32com.client
from win32com.client import constants as c
import numpy as np


def main():
    xl = win32com.client.gencache.EnsureDispatch("Excel.Application")
    xl.Visible = True
    wb = xl.Workbooks.Add()
    #wb = xl.Workbooks.Open(r"C:\Users\test.xls")
    ws = xl.ActiveSheet

    x = np.arange(15)
    y = 0.1*x**2
    z = -y
    
    row = range(1,1+len(x))
    col = 1
    for xi, yi, zi, r in zip(x, y, z, row):
        ws.Cells(r,col).Value =  int(xi)
        ws.Cells(r,col+1).Value = float(yi)
        ws.Cells(r,col+2).Value = float(zi)

    chart = ws.Shapes.AddChart(c.xlColumnClustered).Select()
    xl.ActiveChart.SetSourceData(Source=ws.Range(ws.Cells(row[0], col+1), ws.Cells(row[-1], col+2)))
    xl.ActiveChart.SeriesCollection(1).XValues = ws.Range(ws.Cells(row[0], col), ws.Cells(row[-1], col))

if __name__ == "__main__":
    main()


2013年10月16日水曜日

PILで画像に円を描く

PILで画像に図形を描画するときはImageDraw.Drawオブジェクトに図形を加えていく。
円のときはarc.  中を塗りつぶした楕円ならellipseを使う。boxは描画領域の始まりと終わりを記述するようだ。

import Image, ImageDraw

img = Image.open("nebuta.jpg").convert('L')
draw = ImageDraw.Draw(img)
box = (100,100, 200,200)
draw.arc(box, 0, 360, fill=255)
img.show()



2013年10月15日火曜日

CythonのTutorialで高速化しなかった

Cythonを触ってみようと思ってチュートリアルを走らせた。
Pure Pythonにくらべ最終的には150倍早くなるとのことだったが、ならなかった。
理由はよくわからないがx**2をx*xに書き直すとうまく高速化できた。
MacbookAirだとx**2でもうまくいったので、コンパイラの違いでなったのか??
(Windowsのほうもgccを使っとるはずなんやけどなー)

2013年10月14日月曜日

SIFTで特徴量抽出のエッセンスを勉強してみる。

特徴量抽出のブームなんてDeep Learningみたいな話題のせいで、とっくに過ぎ去った感はあるけど、SIFT(Scale-Invariant Feature Transform)がどうして物体の大きさや回転に不変なのか不思議でたまらなかった。なにか規格化のようなものをやってるだろうと思うけど、想像ができなかった。今回初めて画像の特徴量抽出の勉強をするけど、この手法の考え方って画像以外の別のものにも応用できるエッセンスが詰まっているんじゃなかろうか、と思うようになった。(カメラの光学系認識なんかにつかえると面白いんやけどなー)

ちまたにはわかりやすい資料も結構落ちている。更にOpenCVなんかを使えば一発で実行できる。でもそれじゃ勉強にならないので、ここではSIFTの原理を紹介しつつPythonで実装していきたい。
参考文献は以下の2つ。

前者は開発者Loweさんが書いた論文。後者は日本語でそのまとめ+αな感じ。.

C++で実装されたプログラムについては
http://www.robots.ox.ac.uk/~vedaldi/code/siftpp.html
が大変参考になった。

有名な話かもしれませんが、SIFTは特許が取られていますので、商用利用する場合はちゃんと権利確認をしてください。

さて、では蛇でもわかるように説明しながらやっていきましょう。
[1]の論文ではSIFTは4つの過程を踏むことになっている。

  1. Scale-space extrema detection: 
    • スケールスペースを探索して特徴点となる候補点を見つける。(→スケール変換に対してロバストになる)
  2. Keypoint localization: 
    • ノイズ耐性のない点やエッジ上の点を除外して候補点の絞り込みを行う。
  3. Orientation assignment: 
    • 特徴点周辺の強度と向きを計算し、方向ヒストグラムを作成し、特徴点の向きを決定する。(回転に対してロバストになる)
  4. Keypoint descriptor: 
    • 輝度勾配と方向からなる特徴量ベクトルを作成。(→規格化することで照明変化にロバストになる)

このうち、要点となるのは"Scale-space"と"Orientation Histogram(勾配ヒストグラム)"だと思う。後者はHoG(Histogram of Oriented Gradient)の考えに非常に近い(HoGは具体的に勉強してないのでホントはわかりません)。SIFTではこの2つの重要な考え方を組み合わせて、1,2で重要な注目すべき点を見つけて、3,4でその周辺の形状をパラメータ化するという過程を踏むその他ちょっとしたテクニックもあるけど、要点はそうだ。


1. Scale-space extrema detection

まずスケールスペースというのを導入する。要するに画像は普通は縦と横の2次元(x,y)で考えるけど、これに大きさの次元も加えて考えましょうということ。それで、大きさ方向パラメータを振ったときに極値があれば、そこを特徴点の候補としましょう、ということ。この極値がどんな大きさの画像でも同じパラメータで表せられれば良い。そんなうまいScale-spaceの取り方が唯一存在していて、それがガウシアン画像(ガウスカーネルでフィルタされた画像)だという。標準偏差σをパラメータとしてこれを変化させていく。別々のσ間での差分画像をDoG画像(Difference of Gaussian)と言い、SIFTではこのDoG画像の極値を探していく。下の図は論文[1]より。
このとき、DoGの注目画素の隣接26箇所(9+8+9)を調べて一番大きいまたは小さいときに極値としてそのときのσの値をその候補点のスケールとして登録する。

ではPythonでDoG画像がどんなものか再現してみる。Pythonで画像にガウスフィルタを適用するのにScipyのモジュールを使わせて頂く。PythonとNumpyで画像を扱う場合はこちらを参考に。
from scipy.ndimage.filters import gaussian_filter
import numpy as np
import Image
 
org = Image.open("nebuta.jpg").convert('L')
org.show()
 
sigma = 1.6*3                      #first scale
img = np.array(org, np.float64)
g1img = gaussian_filter(img, sigma)    #first scale image
 
k= 2**(1/3.)
g2img = gaussian_filter(img, k*sigma)  #second scale image

dog = (g2img - g1img)
pmin = np.min(dog)
pmax = np.max(dog) 
dog -= pmin
dog *= 255 / (pmax - pmin)
Image.fromarray(dog).show()    #show DoG image


k=2**(1/3.)は1オクターブに3枚の画像をとることを想定している。つまり3枚とればσが2倍になる。ねぶた祭りの写真で効果を見てみる。



1枚目は原画像、2枚めはσ=1.6の時のDoG画像、3枚目は2オクターブ上がってσ=4.8の時のDoG画像。DoGのピクセル値は負の値もとるので適当なオフセットを加えて保存。DoG≒Laplacian Filterなので微分画像になってエッジが強調されているのがわかる。論文[1]によると、1オクターブに3つくらいのスケールサンプルを取得して、その時のσは1.6というふうに実験から決定している。では何オクターブ分サンプルすればよいのか?? 論文に記載はなかったけど、VLFeat(特徴量抽出ライブラリ)の説明によるとできるだけたくさん(だいたいlog2(min(width, height)オクターブくらい)が良いらしい。

2オクターブ目のガウシアンフィルタは計算量を抑えるために画像を半分にリサイズして1σのフィルタを掛けるとよい。ではこの時点でどのくらいの特徴候補点があるか調べてみたい。速さが気になるけど、Pure Pythonで組んでみよう。結果は下のようになった。検出された候補点を白丸で表す。丸の大きさはDoG画像の画素値を表していて、今回は1から50ピクセルに規格化してある。


候補点は全部で1500くらい検出されたので少し見にくいが、暗くコントラストの低い部分は点が小さく、顔の部分など構造をもった部分は点が大きいように思える。


2. Keypoint Localization

ご覧の通り無駄な点が多すぎるのでここで候補点を絞りたい。 

 まず、コントラストの低いところ(上の図の暗いところなど)は削りたい。これは検出されたDoG画像の画素値にスレッショルドを設けることで排除できる。論文[1]では画素レンジを[0,1]としたときに0.03としている。

 次にエッジ上の点を消去して、コーナーの点だけを残したい。エッジ上の点は強く反応するけど、変化に対して場所が変わり易いからだ。確かに、コーナーだと1点に決まるけど、エッジ上の点は無限に点が反応してしまう気がする。
さて、コーナーか、エッジかを見分ける方法はどうするか??SIFTでは極値での主曲面(Principal Curvature)を使うらしい。エッジなら片方に長細い曲面になっているはず、ということだ。これを調べるのに、極値でのDoG画像のヘッセ行列(2階微分した行列)の固有値を使う。この固有値の比があるスレッショルド以上ならエッジとみなすというわけである。論文では10としてある。

 これらをやるついでと言ってはなんやけど、より正確な極値をサブピクセルの精度で求めることができる。具体的にには上でも求めた極値において、DoG関数の2次のテーラー展開を行い、2次式なら極値は解析的に求まるので、
となる(論文[1], 式(3))。こうしたほうが精度が上がるそうだ。たぶん理由はピラミッドとかを作ったときに精度が落ちたんやろう。SIFTが提案された初期にはこの補間はやってなかったようだ。どうやらLowe先生のお弟子さんが考えたらしい。
これを実装すると以下のようになる。一番上は何もしきい値を設けてない場合。2番めはローコントラストの部分を取り除いた画像。3番目はエッジ部分を取り除いた画像。



続く…


























2013年10月11日金曜日

IPythonを使ってフォルダ内のファイルをすべて削除する。

NikonのCaptureNXのバッチ機能を使ってRaw現像したら同じ写真のjpgが2つできて片方にはファイル名の末尾に_01がくっついている。IPythonを使用してサクッとファイルを消去してしまおうとおもったら意外とコマンドがわからなかった。
よってメモしておく。

import os
path = os.getcwd()          #get current working dir
fnames = os.listdir(path)   #get a list of file
for name in fnames:         
    if "_1.jpg" in name:
        os.remove(name)     #remove file

注意しないといけないのはos.removeで消去したものはゴミ箱にはいらないという点だ。
まちがえたー

2013年10月9日水曜日

PyInstallerで簡単exeファイルの作成

py2exeからPyInstallerに乗り換えるとすこぶる簡単だったというはなし。

PyQtで作ったGUIアプリを職場のみんなに使ってもらうにはexeファイルを作成しなければならない状況にあって、以前はpy2exeでmatplotlibやPyQt4のアプリをexeファイル化していたが、py2exeを実行すると
The following modules appear to be missing
と言うエラーメッセージが 出てうまくいかない。どうもオプションでbundle=1と設定するとうまくいかないようだ。(bundle=1はDLLなどを1つexeに詰め込む設定。bundle=3だとうまく動いた。)
しかも何が足りないって、IronPythonとか使った記憶がないモジュールばかりなので、ちょっとわけがわからなくなった。

StackOverflowなんかを見てみるとpy2exeは止めてPyInstallerを使えって回答が多かった。
なんとなくPyInstallerはインストーラーを作るイメージがあって使ってなかったけど、exeファイルもつくれるようだ。食わず嫌いでした。


ほんで、実際にPyInstallerを使ってみたらすこぶる簡単だった。今までの時間は何だったのか。
インストールの仕方など調べてみると少し古いのもあって混乱したので、ここに簡単な使い方を紹介しておく。


1. インストール

PyInstallerのドキュメントにインストール方法が書いてある。Installing Using pipに従うと、
>pip install pyinstaller
とするだけ。
その下にPyWin32が必要とか書いてあるけど、今回は特に何もしなかった。多分Python(x,y)をインストールしたときに色々一緒にいれたので、そのときに入っていたのかもしれない。


2. exeファイル化

Pythonのスクリプトファイルがある場所に移動して、
>pyinstaller hoge.py

とするだけ。自動で必要なファイルやらなんやらを取得してくれるらしい。
buildとdistというフォルダが生成されてdistの中にあるexeファイルを実行ればpythonで作成したアプリが動作する。

今回はexeにすべて詰め込みたかった+実行時コマンドプロンプトを表示させたくなかったので
>pyinstaller hoge.py --onefile --noconsole 
というオプションを加えた。オプションについてはここを参照。

今回はPyQt4を使ったものをexe化したけど、matplotlibやOpenGLでもこんなに簡単やったらいいなぁ。

2013年10月8日火曜日

アメリカの高校の授業その1 About Me

アメリカの高校は2学期制。
後半のクラスでAbout Meという授業をとった。分類としてはEnglishに分類される。
内容は自分について深く掘り下げようという授業で、よく就活でやる自己分析みないなのをグループでディスカッションしたりする。そして、学期も終わりに差し掛かったあたりで一人ひとり自分のこれまでの行き方についてスピーチを行う。

そのスピーチにはひとつ決まり事があって、自分を表すものを持ってこなければならないということ。それが自分とどう関係するかを説明する。思い出の品を持ってきてもいいし、スクラップブックを作ってもよい。なんでもよい。でも一番手っ取り早いのは親友として人をつれてくること。結構この手の手段を使う人は多かった。(親友はもちろん別の授業に出とるときもあるけど、先生にいえば抜ける許可は簡単に下りる)

スピーチ時間は特に決まってなかった。今思うと不思議だが、その時は30分くらいスピーチした。意外と自分について喋れるものだ。細かい内容は忘れたけど、理科が好きで将来は科学者とかエンジニアになりたいみたいなことを言っと思う。

スピーチの後には聴衆から一言カードがもらえる。自分がもらったやつには、「頭いいからがんばれよ」みたいな意見がいっぱいあったのを覚えている。同じ内容の意見ばかりだったので、あまりおもしろくないスピーチだったのだろう。ちょっと残念だった。

この記事を書いていると、あの時とそんなに変わっていない自分がおることに気がつく。

2013年10月4日金曜日

C++ コンストラクタの:(コロン)について

サンプルコードを見ていると変なコンストラクタを見た。
どうやら、Initialization listと呼ばれるものらしい。
http://stackoverflow.com/questions/2785612/c-what-does-the-colon-after-a-constructor-mean

サイトによると
1.親クラスの初期化
2.コンストラクタが呼び出される前にメンバを初期化する。

らしい。更に
http://ameblo.jp/nana-2007-july/entry-10037680575.html
によると初期化の実行速度も違うらしい。