オタク日記

(Mac と Linux, 2014Q3)

目次

2014-09-17 (Wed): お願いしますよ、Apple さん
2014-09-07 (Sun): Server Maintenance (3)—Git/Git-daemon
2014-09-03 (Wed): Server Maintenance (2)—Django/Git-daemon
2014-08-30 (Sat): Server Maintenance (1)—Sitemap/RSS
2014-08-20 (Wed): Win8.1 on Fusion
2014-08-09 (Sat): 流石は JavaScript ……
2014-08-06 (Wed): やっぱり JavaScript は……
2014-07-28 (Mon): 画像処理再入門 (その 2)—Homography 変換によるカメラ較正
2014-07-26 (Sat): JavaScript に走る—MathJax, prettyprint
2014-07-16 (Wed): MathType, MathML, Chrome
2014-07-02 (Wed): 画像処理再入門 (その 1)—SIFT

古い日記:
2014Q2   2014Q1   2013Q4   2013Q3   2013Q2   2013Q1  
2012 年   2011 年   2010 年   2009 年   2008 年   2007 年  
2006 年   2005 年   2004 年   2003 年   2002 年   2001 年


2014-09-17 (Wed): お願いしますよ、Apple さん

愛機 Quadra (MacPro 1,1, Lion) のマザーボードがおかしくなって、Riser card が一枚しか認識されなくなったのが今年の 5 月で、 その当座は「いつ完全に壊れてもおかしくない」とピリピリしていたのだが、 さすがに 4 ヶ月も経つと緊張が緩んできた。

それにつれて新旧の「壊れるまでは行かない不具合」が段々気になり始めた……

まあ、サポートされなくなった OS に「ありがちな運命」を辿っているだけ、 とも言えるが、 「さすがにもう Lion ではツライかな」という感じも……特に Xcode が古くなったのは痛い。

iTunes Installation Error
「デバイスドライバがおかしいよ」というエラーメッセージ?
そんな所に、目覚ましのような一撃…… 何時の頃からか、Firefox でファイルをダウンロードしようとすると、 こんなエラーメッセージが出るようになった。「うわっ、USB 関連のデバイスドライバにインストールミスか?」となって、 一瞬嫌〜な予感がした。

しかし調べてみると、どうやら iTunes-11.4 のインストール時に、古い symbolic link を消すのに失敗してるだけ、のようだ。実際、

fukuda@quadra:/System/Library/Extensions/AppleUSBEthernetHost.kext/Contents% ls -l
total 20
lrwxr-xr-x 1 root wheel   28 Sep 22  2013 CodeDirectory -> _CodeSignature/CodeDirectory
lrwxr-xr-x 1 root wheel   31 Sep 22  2013 CodeRequirements -> _CodeSignature/CodeRequirements
lrwxr-xr-x 1 root wheel   28 Sep 22  2013 CodeSignature -> _CodeSignature/CodeSignature
-rw-r--r-- 1 root wheel 3202 Jul 30 05:48 Info.plist
drwxr-xr-x 3 root wheel  102 Sep 17 14:34 MacOS/
drwxr-xr-x 3 root wheel  102 Sep 17 14:34 _CodeSignature/
-rw-r--r-- 1 root wheel  473 Jul 30 05:48 version.plist
fukuda@quadra:/System/Library/Extensions/AppleUSBEthernetHost.kext/Contents% sudo unlink CodeDirectory
fukuda@quadra:/System/Library/Extensions/AppleUSBEthernetHost.kext/Contents% sudo unlink CodeRequirements
fukuda@quadra:/System/Library/Extensions/AppleUSBEthernetHost.kext/Contents% sudo unlink CodeSignature    
とやってから、iTunes-11.4 を再インストールすれば、問題は解消した。 (再インストールしても、symbolic link は無いまま。)

たったこれだけの事だが、iTunes の再インストールだけではどうにもならない事、また Mavericks では問題が出なかった事、等を見ると、 Apple さん、Lion 以前の OS に対しては、パッケージのテストに手を抜いているのでは?という疑いが……


2014-09-07 (Sun): Server Maintenance (3) — Git/Git-daemon

2015-05-17 (Sun):
一旦は「うまく使えるようになった」と思った Git だが、Django サイトの開発のためにはもう一捻り必要だった。 つまり(試験)運用したらそれに応じてデータベースが更新されたり、 新にファイルが作られるサイトに対しては、 track するべきファイル(ソースコード)を明確に指定してやる必要がある。

想定している使い方とは、概略下の通り。

Django application development
Git で Django アプリのステージングをスマートに……
Server (Lark) で、実際に稼働しながら(Working Repository を http で公開する)、desktop に clone を作ってアップデートしていこうと。

これは、極大雑把に言えば、電子ファイルやハードコピーの文書に、 電子的な Index をつけようというシステムなので、稼働していれば、 文書(電子ファイル)や、その Index (data base) (つまり Working Repository の中身)はどんどん増えていく。 その状態で、Staging Repository で試験をすると、すぐに Working Directory と push/pull で同期させる事ができなくなる。

特に悩ましいのは、sqlite3 DB の実体である db.* ファイル (ここでは、db.sqlite3 としている) で、これの表の構成を手で弄ったり、models.py と同期させたり、という事もあるので、全く無視する事もできない。 大分悩んだが、結局スマートな解決方は思いつかず、他の「自動生成ファイル」 同様 git の track から外し、必要な時は、Lark の上で、手で db.sqlite3 を弄る事にした。 そもそも、Django のお勧めは、Staging Repository で、db.sqlite3 を改変する SQL ディレクティブのスクリプトを作って動作確認した上で、 同スクリプトを Working Repository で適用する、 だから、Git による管理には向いていないとも言える。

という事で、大元(現在の最新版)の tree (Work Depository) に、その旨を書き表わした.gitignore を置く。

fukuda@lark:~/wrm_dms% cat .gitignore
__pycache__/
*~
*pyc
db*
files/
    
## added on 2015-05-17 (Sun): 
fukuda@lark:~/wrm_dms% git add .gitignore #1)
fukuda@lark:~/wrm_dms% git rm --cached -rf */*pyc #2)
fukuda@lark:~/wrm_dms% git rm --cached -rf */files #3)
.... 
## end of add
fukuda@lark:~/wrm_dms% git commit -a -m "just for test 3" 
.gitignore も Shared Repository へコピーされる。
2015-05-17 (Sun): 記述が抜けていた……。

ここで、Quadra 側で git clone して、db.sqlite3 を手でコピー。 実際に Django の runserver を立ち上げて、db.sqlite3 を変化させてみる。

fukuda@quadra:~/Git/wrm_dms% git clone git://otacky.jp/wrm_dms.git       
fukuda@quadra:~/Git/wrm_dms% scp lark:wrm_dms/mysite/db.sqlite3 mysite/
fukuda@quadra:~/Git/wrm_dms% python3.4 manage.py runserver 0.0.0.0:8000
Validating models...

0 errors found
September 08, 2014 - 11:53:22
Django version 1.6.6, using settings 'mysite.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.
[08/Sep/2014 11:53:30] "POST /index/list/ HTTP/1.1" 200 6318
[08/Sep/2014 11:53:30] "GET /static/default.css HTTP/1.1" 200 4284
[08/Sep/2014 11:53:37] "POST /index/list/ HTTP/1.1" 200 12066
[08/Sep/2014 11:53:41] "POST /index/form/ HTTP/1.1" 200 8811
[08/Sep/2014 11:53:54] "POST /index/list/ HTTP/1.1" 200 12066
[08/Sep/2014 11:54:04] "POST /index/form/ HTTP/1.1" 200 8811
    ....
^C%
fukuda@quadra:~/Git/wrm_dms% git status
# On branch master
nothing to commit (working directory clean) 
という具合に、しっかり ignore されている。今度は、track されている筈の index_new.html にコメントを挿入してみる。
fukuda@quadra:~/Git/wrm_dms% echo "{# test #}" >> index/templates/index_new.html
fukuda@quadra:~/Git/wrm_dms% git status
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#	modified:   index/templates/index_new.html
#
no changes added to commit (use "git add" and/or "git commit -a")
fukuda@quadra:~/Git/wrm_dms% git commit -a -m "just for test 4"
[master a7312f2] just for test 4
 1 file changed, 1 insertion(+)
fukuda@quadra:~/Git/wrm_dms% git push
Counting objects: 9, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 425 bytes, done.
Total 5 (delta 4), reused 0 (delta 0)
To git://otacky.jp/wrm_dms.git
   9081aca..a7312f2  master -> master
fukuda@quadra:~/Git/wrm_dms% 
今度はきちんと変化が検出されて、commit -> push できた。 Lark の側でも
fukuda@lark:~/wrm_dms% git pull
remote: Counting objects: 9, done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 5 (delta 4), reused 0 (delta 0)
Unpacking objects: 100% (5/5), done.
From git://localhost/wrm_dms
   9081aca..a7312f2  master     -> origin/master
Updating 9081aca..a7312f2
Fast-forward
 index/templates/index_new.html | 1 +
 1 file changed, 1 insertion(+) 
のように、index_new.html だけが pull できている。 まさにこれが望みの動作だった!

で、「目出度し目出度し」であるが、実はここに来るまでに、 かなり悩まされた事がある。 というのは、MBA (Hawk: Mavericks) からだと、 上記の動作が実現できていたのだが、Desktop (Quadra: Lion) では、どうしても .gitignore が正しく解釈されない。 相当四苦八苦したが、要は、Quadra の上では、git が 2.1 だった、という事のようだ。(MacPort の git-2.1 をアンインストールして、 /usr/bin/git (-1.7.12.4) を使い始めたら、問題は解消した。 ちなみに Marvericks の方は、-1.8.5.2 で、Ubuntu の git は 1.9.1。)

ここは 2.1 で動くようにしておくべきかも知れないが、 もうそろそろ嫌になってきたので、Ubuntu の git が 2.x になってから考える事にする。 (それにしても、Git はややこしい VCS だねぇ :-p )

2015-05-17 (Sun): これは勘違い。$ git clone では、track されていないファイルもコピーされる事を知らずに「おかしい」と思っていた。 それを無視して、それ以降 pull/push だけをやるなら、git-2.1 と git-1.9 で何の問題もなくちゃんと動いてくれる。(Lion は最早動かないので、確認はできないが……)

2014-09-03 (Wed): Server Maintenance (2) — Django/Git-daemon

とにかく環境のお守りに割く手間は最小限にしたい、 で、そのためには、第一にパッケージ管理を統一しなくては…… という目標は一時はかなり達成していた。つまり、OSX では、MacPorts, Ubuntu では apt-get で、殆どのパッケージを管理するところまで行っていた。

しかし、先端的な(つまり、ちょっと怪しい)ツールを使い始めると、 どうも、それだけでは収まらない。

Wireshark がその典型で、 これを最初に OSX (Lion と Mavericks) に入れた時は、XQuartz ともども MacPorts 版だったのだが、なかなかうまく動いてくれず、紆余曲折を経て、 今やバイナリ版同士の組合せになっている。 (最近、バイナリ版同士だと Wireshark のアイコンをクリックしても XQuartz が立ち上がらないという問題が出ていたが、最新版 (XQuartz-2.7.7, Wireshark-1.12.0) ではそれが解消されている。)

Django

これに加えて、MacPorts では、Django が 1.5.1 のまま一向に更新されなくなった。 これに留まる、というのも妥当な選択だが、自宅サーバ (Lark: ubuntu-14.04-server) の Django (python-django) が 1.6.1 になっていて、しかも、1.5 と 1.6 の間で request の serializer がらみで非互換性があるので、OSX の側も 1.6.x にする必要が有った。 どうするか、ちょっと迷ったが、また pip でインストールする事に…… ついでに、これに使う Python も、2.7 から 3.4 に上げた。

それに引っぱられて、自宅サーバの方でも、python3 (何と -3.4.0) で、Django を使う事にし、こちらでも

fukuda@lark:~% sudo apt-get install python3-pip   
fukuda@lark:~% sudo pip3 install django
Downloading/unpacking django
  Downloading Django-1.6.6-py2.py3-none-any.whl (6.7MB): 6.7MB downloaded
Installing collected packages: django
Successfully installed django
Cleaning up...
    
fukuda@lark:~/waremo_dms% python3 manage.py runserver 0.0.0.0:8080 
Validating models...

0 errors found
August 27, 2014 - 12:36:29
Django version 1.6.6, using settings 'mysite.settings'
Starting development server at http://0.0.0.0:8080/
Quit the server with CONTROL-C.
[27/Aug/2014 12:36:41] "POST /index/list/ HTTP/1.1" 200 11849
[27/Aug/2014 12:36:50] "POST /index/list/ HTTP/1.1" 200 6244 
とした。 要するに、「apt-get だけ」の原則はあっさり崩れてしまった訣たが、 おかげで、最新版 (-1.6.6) の python3 用がインストールされ、python-3.4 でちゃんと動いている。

Git

Mercurial から Git に移った時は、かなり真面目にとり組んだのだが、 最近では、かつての CVS と同じような使い方しかしていなかった。 しかし、それだけでも、git は値打ちが有る。例えば、 先にも書いたように wanderlust とそれに必要なパッケージ群を一つのディレクトリに置いておけば、 コマンド一つで、outdated になっているパッケージを更新してくれる。
fukuda@quadra:~/Git/Mail% for i in *; (cd $i && print "**" $i && git pull)
** apel
Already up-to-date.
** flim
Already up-to-date.
** semi
Already up-to-date.
** w3m
Already up-to-date.
** wanderlust
Already up-to-date.
ちなみに、wanderlust の最新版は、今は https://github.com/ikazuhiro/wanderlust ではなく、 https://github.com/wanderlust/ になっているようなので、この ~/Git/Mail の下のディレクトリも、あらためて
fukuda@quadra:~/Git/Mail% git clone http://github.com/wanderlust/semi 
fukuda@quadra:~/Git/Mail% cd ../semi
fukuda@quadra:~/Git/Mail/semi% git log

commit 63c97b6f5f9db3c9f0acdc723512c5fefe1d362e
Author: Juliusz Chroboczek <jch@pps.univ-paris-diderot.fr>
Date:   Thu May 29 21:43:19 2014 +0200

    Use last highest score part in multipart/alternative.
    ....

fukuda@quadra:~/Git/Mail/semi% cd ../../Mail-ito/semi-epg 
fukuda@quadra:~/Git/Mail-ito/semi-epg% git log

commit 63c97b6f5f9db3c9f0acdc723512c5fefe1d362e
Author: Juliusz Chroboczek <jch@pps.univ-paris-diderot.fr>
Date:   Thu May 29 21:43:19 2014 +0200

    Use last highest score part in multipart/alternative.
    ....
などとして、リポジトリを作り直し、 かつ、元のリポジトリと同じ版である(もしくはより新しい)事を確認した。 (この例では semi は semi-epg と同じ版となっている。)

Git-Daemon

以上は、デスクトップで、Git をバージョン管理に使っているという話だったが、 同時に(またぞろ)自分のささやかな Python programming のために、本格的に Git を使ってみたいと思い始めた。勿論「GitHub を使う」が、 最も手っ取り早いアプローチなのは承知しているが、 「公開するのはちょっと不味い(大分恥ずかしい)」という事があり、 とりあえず、自宅サーバを Git サーバにしてみた。

実は、ちょろっと試した事があるのだが、 その時はどうしても上手く行かなかった。 いや、なんとなくそれらしい動作をするようにはなったのだが、 「(とっても煩雑で)それがどうして嬉しいのか分らない……」 の為体だった。

今回は心機一転、master repository を working directory (repository) と分ける事にした(「当り前の事」かも知れないが……) まずは、サーバに、空の「共有」(master?) repository を作る。

fukuda@lark:~% sudo apt-get install git-daemon-sysvinit
fukuda@lark:~% sudo apt-get install sysv-rc-conf
fukuda@lark:~% sudo sysv-rc-conf --list | grep git
git-daemon   0:off	1:off	2:on	3:on	4:on	5:on	6:off
fukuda@lark:/var/lib/git% sudo mkdir wrm_dms.git
[sudo] password for fukuda: 
fukuda@lark:/var/lib/git% cd wrm_dms.git 
fukuda@lark:/var/lib/git/wrm_dms.git% sudo git init --bare
Initialized empty Git repository in /var/lib/git/wrm_dms.git/
fukuda@lark:/var/lib/git/wrm_dms.git% sudo chown -R gitdaemon:root .. 
ここで、git init --bare とする事、ディレクトリの owner を gitdaemon:root にする事がミソ。 こうしておいて、今度は、開発、動作確認中のディレクトリから
fukuda@quadra:~/Git/waremo_dms% git commit -m "0.91: author field modified"
fukuda@quadra:~/Git/waremo_dms% git remote add origin git://otacky.jp/wrm_dms.git
fukuda@quadra:~/Git/waremo_dms% git push origin master
のように push すると
fukuda@lark:/var/lib/git/wrm_dms.git% ls
branches/  config  description  HEAD  hooks/  info/  objects/  refs/
fukuda@lark:/var/lib/git/wrm_dms.git% git log
ESC[33mcommit 5ceed5cbaee4c0c47640c05db2a1450f1e694750ESC[m
Author: Taka Fukuda <fukuda@lark.otacky.jp>
Date:   Wed Aug 27 15:01:58 2014 +0900

    0.91: author field modified
... 
のように、共有 repository ができる。 (一見「空のまま」だが、これで OK。これに気がつかず、 何度かここまで来ては「あ、また失敗か」とやってしまった…… 先に、 このサイトを見れば良かった。) 実際、この共有サイトから、clone できて
fukuda@lark:~% git clone git://localhost/wrm_dms.git
fukuda@lark:~% cd wrm_dms
fukuda@lark:~/wrm_dms% git log
ESC[33mcommit 5ceed5cbaee4c0c47640c05db2a1450f1e694750ESC[m
Author: Taka Fukuda <fukuda@lark.otacky.jp>
Date:   Wed Aug 27 15:01:58 2014 +0900

    0.91: author field modified
    ....
    
fukuda@lark:~/wrm_dms% python3 manage.py runserver 0.0.0.0:8080 
Validating models...

0 errors found
September 03, 2014 - 08:59:06
Django version 1.6.6, using settings 'mysite.settings'
Starting development server at http://0.0.0.0:8080/
Quit the server with CONTROL-C. 
のように、問題なく Django の開発用サーバがスタートできる。

勿論、サーバの外からアクセスするためには、

fukuda@lark:~/wrm_dms% sudo ufw allow 9418    
として、iptables に「穴」を明けておいてやる必要がある。 ちなみに、この git-daemon も、wrm_dms も、 local network の外からはアクセスできません。

2014-08-30 (Sat): Server Maintenance (1) — Sitemap/RSS

自宅サーバの sitemap-gen が作ってメールで送ってくる log が、5 MB もある事に気付き、「なんでやろ」と思ったのが事の起こり。 それを減らすのは簡単(verbose level が "2" だったのを "1" にするだけ)だったけど、そのついでに sitemap と RSS を新しくしたら、 ページビューががっくり減ってしまった。

Sitemap

Google の search engine で上位にランクされるとアクセスが増えるだろうという事は想像に難くない。 何しろ、SEO (Search Engine Optimization) などという職業というか技術分野があるくらいだ…… しかし、(私の知る範囲では)Google はその基準を公表していない。 なので、そんなもんに凝ってもしようがない、とも思うが、 一方で、順位は措いても、全くリストアップされないと世の中に存在しないのと同じ、 という気もする。

そのためには、 各社の crawler (robot) が見に来てくれないと始まらない。 何時見に来てくれるかは、勿論各 search site 様の胸前三寸なのだが、 それを促す方法というのが有るようで、まず第一には、 sitemap を作って、その作製完了を Google 他に知らせる事。 実はこれは大分前からやっていて、1 日に 1 回、crontab で、sitemap_gen.py というのを走らせている。(これが、sitemap.xml を作った後に、google.com に通知する。) このお陰か、週一程度の改訂が、比較的早く反映されていた。 (Crawler の来訪が集中して、稀に 500 views/day もアクセスカウントが稼げる事がある、というオマケまで付いていた。)

がしかし、これはどうも「正しい」sitemap ではないようだ。 sitemap_gen-1.4 だと、できた sitemap.xml の先頭付近は、

<?xml version="1.0" encoding="UTF-8"?>
<urlset
  xmlns="http://www.google.com/schemas/sitemap/0.84"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.google.com/schemas/sitemap/0.84
       http://www.google.com/schemas/sitemap/0.84/sitemap.xsd">
 <url>
  <loc>http://www.otacky.jp/20questions.html</loc>
  <lastmod>2010-04-03T16:12:16Z</lastmod>
  <priority>0.5000</priority>
 </url>
....
となるのだが、このページは deprecated になっている。 これは不味かろう、という事で (態々これに留まってきた理由が有ったような気もするのだけど) えいやっ、と sitemap_gen-1.5 にした。 すると、できた sitemap の該当部分は
<?xml version="1.0" encoding="UTF-8"?>
<urlset
  xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
       http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
となる。

メデタシメデタシの筈だが、これらの変更を実施したあたりから、 めっきりアクセスが減ってしまった。アップデートも滞っているようだ……。 (要は、crawler が全く来ていない? うーむ、その昔一旦は -1.5 にしながら、また -1.4 に戻してそのままにしておいたのは、このせいだったのか。)

一瞬「また -1.4 に戻そうか」とも思ったが、 あまり一喜一憂するのも情け無いような気がして、しばらくこのままで行く。

RSS

これも上手く使えば、アクセスを増やす手段になるらしい。 (一体どれくらいの人が、本サイトの RSS を購読してくれているか分らないが……。) 大昔のある日、ふと思いついて、とあるサイトの rss.xml を訣も分らずコピーして始めたのだが、 「そのうちちゃんとしたものにしよう」と思いながら、 ついつい……。

改めてよく眺めてみると、これはどうやら、RSS 1.0 という規格だったらしい。 今は、RSS 2.0 が主流になりつつあり(すなわち、殆どのブラウザが対応し) しかも、 この方が記述が簡便になるんだそうな。 確かに、同じ url が何回も表われる、という事がなくて、スッキリしているようだ。 となれば、移行しない手はない……

<?xml version="1.0" encoding="utf-8" ?>
<rss version="2.0"
     xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
     xmlns:admin="http://webns.net/mvcb/"
     xmlns:atom="http://www.w3.org/2005/Atom">

  <channel>
    <title>Otacky Taka's Home Page</title>
    <link>http://www.otacky.jp/rss.xml</link> 
    <atom:link href="http://www.otacky.jp/rss.xml" rel="self" type="application/rss+xml"/> 
    <description>無線・有線ネットワーク、起業日記、他</description> 
    <dc:creator>Taka Fukuda</dc:creator>
    <dc:language>ja</dc:language>
    <dc:date>2014-08-20</dc:date>    

    <item>
      <title>Win8.1 on Fusion</title>
      <link>http://www.otacky.jp/otaku_comm-14Q3.html#08-20</link>
      <description>
        色々問題が多かったが、このところ目立って改善されてきている。
      </description>
      <guid>http://www.otacky.jp/otaku_comm-14Q3.html#08-20</guid>
      <dc:creator>Taka Fukuda</dc:creator>
      <dc:subject>オタク日記</dc:subject>
      <dc:date>2014-08-20</dc:date>
    </item>

    <item>
    .... 
    </item>
    ....
  </channel>
</rss>
てな具合に、<channel><item> がきれいに分離され、 1.0 の時のように、同じ URL が都合 3 回も出てくる、なんて事はなくなった。 (<guid> が無ければ、3 回が一回に減った事になる。)

素晴しい!ついでに、index.html に Valid RSS のボタン (valid-rss button) をつけてみた。 なかなか格好良い。が、これで診断すると、「<guid> が無い」という警告が出る。必要性がよく理解できないし、"guid" なんて意味不明の綴りだし(多分 guide の 'e' を省略した?) 気に入らないが、警告が出るよりは、という事で、付け加える事にした。 おかげで、一旦は 3 回から 1 回まで減っていた「同一の URL」が、2 回に増えてしまった。


2014-08-20 (Wed): Win8.1 on Fusion

と言っても、8/13 のとんでもアップデートの話ではない……。 以下にある「Windows のアップデート」は、8/11 までにやり、その後は、 シャットダウンしてない(Win はサスペンドして、Fusion を Quit していた)ので、 アップデートもしていない……「ズボラ」で怪我の功名 :-)。

件の "0xC0000142 error" を克服 できてからは、 何とか使えるようにはなっていたが、それでも、Window がスムースに動かない、 McAfee がインストールできない、Cygwin のアップデートが完了しない……云々で、Win8.1 on VMware Fusion には嫌気が差してきて、このところずっと御無沙汰であった。

しかし、このところ、またぞろ出番が…… 最初は、MathML を使い始め、その後 MathJax に移行したので、 数式の見栄えの確認にしばらく使った。 次に、日本語ファイル名の zip アーカイブを展開するのだが、 OSX ではどうしてもうまくゆかず、Windows が必要だった。 その際、久し振りという事で、Windows のアップデートと、 VMware Tools のアップデート(修復)をやってみた。 これらと、 少し前にやった Fusion 本体の 6.0.4 へのアップデートのうち、 どれが本当に効いたのかは分らないが、とにかく……

等がすぐ分る改善点。この頃は、remote-folder (?) に頼らず、scp や rsync でファイルをやりとりしている (こちらの方が、格段に便利)ので、Cygwin と LTspice が揃ってスムースに動くようになった事はとても嬉しい。 一方で、 という問題は残っている。(X11 上のアプリ、例えば Wireshark を使う場合は、これは結構ツライ。) まあしかし、このところの最大の「コノヤロ」は、MS Reader だろう——全般的なレスポンスが悪い事もアレだが、 「止め方」が分らないのが最も情無い :-p

2014-08-09 (Sat): 流石は JavaScript ……

Local ではどうしても動かない、と匙を無げていた prettify だが、 ひょんな事からその原因が解った。 要は、*.js*.css ファイルに others の read permission が無い事だった…… *^_^*。 いや面目無い。 それにしても、Google さん、何だってわざわざ file permission を
fukuda@quadra:~/public_html/script/prettify% ls -l prettify*
-rw-r----- 1 fukuda fukuda   675 Mar  5  2013 prettify.css
-rw-r----- 1 fukuda fukuda 14551 Mar  5  2013 prettify.js 
にして出すかねぇ……。セキュリティの観点からは、httpd の privilege を others にしているのが普通だろうから、 殆んどの人が引っ掛るのではなかろうか。 (しかも、自分はその「普通」を忘れていて、なかなか気付かなかった。)

ともあれ、-rw-r--r-- とすることで、local で動くようになった。早速、prettify.css を触って、と思うが、くくりが大まかで、これではあまり大した事はできないようだ。 しかし、まあ、最初の一歩という事で、 keyword は maroon, comment は gray にしてみたが、これだけでも結構「それらしく」なってくれた。

import numpy as np
import sys
## 2012-02-23 (Thu): Added matching_ckt_shunt
## 2012-02-24 (Fri): uncommented *1)
def norton_equiv(Rs, Xs, freq=403.5e+6):
    pi2f = np.pi*2.0*freq
    Z = Rs + Xs * 1.0j
    Y = 1.0/Z
    Rp = 1.0/np.real(Y)
    Xp = 1.0/np.imag(Y)
    if Xs <= 0.0:
        Cp = 1.0/(pi2f*Xp)
        print("Rs: %.5g, Xs: %.5g, NortonEquiv: Rp: %.5g, Xp: %.5g, Cp: %.5g (pF)"
              % (Rs, Xs, Rp, Xp, Cp * 1.0e+12))
Literal や、関数の引数にまで色をつけてくれるのはちょっと新鮮だが、 肝心の関数には指定の色がつかない……そもそも関数名を認識していないようだ。 lang-py だけのバグだろうか。

2014-08-06 (Wed): やっぱり JavaScript は……

ちょっと手が空いたので、懸案にアタックしてみた。

MathJax

動いた直後は「感動モノ」だった MathJax だが、最初の興奮が醒めてくると、 「なんだかなぁ」も出てくる。第一、 (MathML がディフォルトでは小さすぎたのに対し)、 こちらはちょっと表示が大きすぎる気がする。 加えて実行に時間がかかる……。

これらを一気に解決するには、自分のところで script を持つべきだろうと思い至り、 最初の「すったもんだ」の際にダウンロードしておいたものを、 public_html/script/MathJax/ に展開して、<head> 内の

<script type="text/javascript"
src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=MML_HTMLorMML">  
</script>
<script type="text/javascript"
src="/script/MathJax/MathJax.js?config=MML_HTMLorMML">  
</script>
とした。意外にもこれはあっさり動いてくれて、表示できるようになった。 が、数式が表示されるまでにワンテンポ余計にかかるのは前と同じ。

「ちょっと大き過ぎだろ?」については、 ダウンロードしてインストールした *.js ファイルの中には、font-size: のような記述が幾つかあるので、 これらを弄ってみるが、結局どうにもならない。

が、半分あきらめてしまった頃に、Stack overflow で示唆されていたのを思い出して(「うまく行かない」という結論だったようだが)、

<script type="text/x-mathjax-config">
      MathJax.Hub.Config({
         "HTML-CSS": { scale: 90 }
    });
</script>
としてみたら、スンナリうまく行った。Inline 表示の時の括弧がちょっと大きいのはそのままだが、 その他の違和感は大分減ったように思う。
(2014-08-09 (Sat): 補遺)
例えば、このような「スケールの補正」無しでは、
mathjax inline の埋め込み scale = 100%
Mathjax linline の埋め込み (scale = 100%)
のようだったのが、
mathjax inline の埋め込み scale = 90%
Mathjax linline の埋め込み (scale = 90%)
のようにできた。ちなみに、Firefox native の MathML によると
mathml inline, font-size: 115%
Firefox native の MathML inline (font-size: 115%)
のような感じだった。<mfenced> がつける"( )" (括弧)のサイズはこの方が適切だったような気がする。

Prettify

Google のアプリ全般に言える事だが、 そのままで使うに分には、まあまあの使い勝手だが、 ちょっとでも「推奨の方法」から外れようとすると往生する。

何と「ダウンロードして使いたい」からして、推奨から外れるようで、 どうしても、local に置いたスクリプトから動くようにできない。 「CSS はちゃんと置いて、link を張るべし」とか「<body onload="prettyPrint()">を加える」とかが、 非常に上手く隠されている。(それより、何で link を張った場合と同じようにできないんだ?) ともあれ、それらを一つ一つ実行してみた……

<script type="text/javascript"
    src="/script/prettify/prettify.js">
</script>
<link rel="stylesheet" type="text/css"
    href="/script/prettify/prettify.css">
    ....
</head>
<body onload="prettyPrint()">
が、やっぱり動かない……。

という事で、色分けを自分好みに直す、という、 面白いけど「時間食い」の楽しみはしばらくお預け。


2014-07-28 (Mon): 画像処理再入門(その 2)— Homography 変換によるカメラ較正

Sift も馴染みが無かったけど、Homography も知らなかった……。しかも、どうやらこっちの方が「より基本的」で、 知らないと「より恥かしい」らしい。

まあ、それはともかく、二次元の面内での Homography 座標変換は、 x y w = a b tx c d ty e f 1 x y 1 で表わされるんだそうな。「何で三次元マトリックスなの?」とか、 「w って何?」という疑問がすぐ浮かぶが、 e=f=0 とすると、 x y 1 = a b tx c d ty 0 0 1 x y 1 となり、これは x y = a b c d x y + tx ty と同値で、Affine 変換を表わしている事が分る。 つまり並行移動も含めて、 行列とベクトルのかけ算だけで表わすために三次元にした訣だ。

ここで、先に 0 と置いた ef を元に戻すと、w w=ex +fy+1 となるが、ここで x/ w y/ w を元の平面上の座標と解釈すると、 そのスケール(拡大・縮小の率)が x, y に依存するようになり、このため長方形を台形に変形できるようになる…… すなわち、Affine 変換の自然な拡張になっている…… という事で直感的な意味は解った(事にしよう。)

こんな事して何が嬉しいかというと、カメラの歪みのうち、 視点のズレまで補正できるようになる事(完全に補正できるのは、 対象物が、同一平面内にある場合に限る。) もっと言うなら、二つのカメラが、 少し違う方向を見ている上に、 視野が光軸の回りに回転している、というような場合は、 先の Affine 変換で事が足りるが、それに加えて、 光軸とは垂直方向の取り付け位置の誤差がある場合でも、 両者の画像をぴったり重ね合わせるような、 座標変換(Homography 変換)を求める事ができる、という事。

座標変換の行列 H を求める事は、対応する 4 点の座標 (8 組のデータからできる 8 個の方程式)から、H 内の 8 個の要素(右下隅は '1' と決まっている)を決める事だから、8 元の連立方程式を解く事に帰着する。 となれば、ここは SVD (Singular Value Decomposition) の出番である。 (これにはいささか経験が……と言いたいところであるが、 自分がこれを勉強したのは大昔の事で、何とサンプルコードは FORTRAN だった。) なので、ここは Numpy の linalg.svd() を使う。 それへの入力(引数)を作るのも面倒というか私の理解を超えているので (condition, uncodition って何?) Solem さんの PCV ライブラリをそのまま使わせて頂く事にする。(そう言えば、これ、 homography.H_from_points() も FORTRAN の匂いがするなあ。)

ともあれ、その 4 点の選び方が問題で、この場合立体視のためだから、 理想的には無限遠点にあって、 かつ両方のカメラから見える点が望ましいのであるが、 残念ながら、そのような点はなかなか無い。 特に Sift から two sided match で選んだ点には良いのが少かった。 仕方なく、目視でそれらしい点を選び出す事にした。

fukuda@quadra:~/Work% python2.7
Python 2.7.8 (default, Jul 13 2014, 02:30:56) 
    ....
>>> from PIL import Image
>>> import numpy as np
>>> import cv2
>>> import matplotlib.pyplot as plt
>>> import PCV.geometry.homegraphy as gh    
>>> import sift2  # Work/sift2.py
>>> im_r = np.array(Image.open("diamond_right.png"))
>>> im_l = np.array(Image.open("diamond_left.png"))
>>>  # 後方のほぼ同一面内にある点を選び出した(一部本棚の棚と側板
>>>  # の交点を推測して使っている。:-)
>>> rp = np.array([[273.8, 273.2, 573.7, 617.5], 
... [142.0, 272.3, 144.0, 358.2], 
... [1, 1, 1, 1]])
>>> lp = np.array([[266.6, 249.8, 567.2, 592.8], 
... [141.4, 267.1, 169.8, 385.8], 
... [1, 1, 1, 1]])
>>> H = gh.H_from_points(lp, rp)  # Solem さんの PCV より
>>> H
array([[  1.02694947e+00,   1.64336922e-01,  -1.67093236e+01],
       [ -9.00371239e-02,   1.08108308e+00,   1.65163814e+01],
       [  2.53566087e-05,   1.20410689e-04,   1.00000000e+00]])
>>> warp_im_l = cv2.warpPerspective(im_l, H, (640, 480))    
>>> im3 = sift2.appendimages(im_r, warp_im_l)
>>> plt.imshow(im3)    
>>> plt.show()
>>> result = Image.fromarray(im3)
>>> result.save("diamond_stereo_warp.png")
Homography 変換後の立体視
オリジナル画像による立体視画像
Homography 変換後の立体視
Homography 変換で「カメラの較正」をした後の立体視画像
オリジナルの画像のままでは、10度弱の「回転」が入っていたので、 立体視には少々努力が必要だったが、これくらい較正できていれば、 比較的楽に立体視ができ、しかも像が安定している。 (慣れれば、上下二つの組が同時に立体視できるようになり、 「安定性」が比較できるようになります!頑張って下さい :-)

2014-07-26 (Sat): JavaScript に走る—MathJax, prettyprint

諸般の理由(実は自分で「うまく使えたためし」が無いだけ)で、 JavaScript はできるなら使いたくないと思ってきた。 なので、Chrome や IE が MathML をサポートしないと知った時も、 MathJax の存在を知らなかったわけではなく、そっちへ走るよりも Native HTML5 で閉じていた方が良いだろう、と思ったのだった。

MathML は「行列」が不得意

しかし、「行列」や「ベクトル」を含む数式を書く段になると、 Firefox や Safari でさえ問題が出はじめた。

MathType on Keynote
Firefox の MathML による行列
MathType on Keynote
Safari の MathML による行列

Firefox (左側)は縦に間延びしているのと、Matrix と Vector の間が詰み過ぎているのが問題。間延びは <mtable rowspacing=xxx> で修正できる筈であるが、Firefox は、 そのあたりはまだサポートしていないのだそうな。 しかし、これくらいならまだ我慢の範囲内だが、Safari はもっと悲惨で、 これはどの attribute を弄ったら良いのかさえ分らないレベル。 それより問題なのは、双方のおかしいところが異るので、どの attribute をどう弄っても、 Firefox と Safari 両方で同じように見えるようにはできそうもない事……

MathJax

思い余って、一度捨てた Mathjax を再度試してみた。 といっても、このページソースに、
<head>
<style>
    ....
</style>
<script type="text/javascript"
src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=MML_HTMLorMML">  
</script>
</head>
とするだけ。MathML のソース
<math display='block'>
    <mfenced open='[' close=']'>
    <mtable>
    <mtr>
    <mtd><mi>x</mi><mo>′</mo></mtd>
    </mtr>
    <mtr>
    <mtd><mi>y</mi><mo>′</mo></mtd>
    </mtr>
    <mtr>
    <mtd><mi>w</mi><mo>′</mo></mtd>
    </mtr>
    </mtable>
    </mfenced>
    
    <mo>=</mo>
    
    .....
    
    </math>
は一切触らずとも x y w = a b tx c d ty e f 1 x y 1 のような表示が得られる。しかも、Chrome や IE でも OK となれば、これはもう宗旨替えするしかないだろう。 ソースは MathML で統一しておき、当面 MathJax.js のリンクでしのぎ、各ブラウザのサポートが充実してきたら、 このリンクを外せば良いだけ(だと思うが、どうなんだろう。)

Source Highliting — prettify.js

一旦、タガが外れると、ついつい JavaScript が多くなっていく。 これまでソースコードの highlighting は source-highlight を使って手でやっていた。

しかし、この JavaScript も試すだけなら Link を張るだけでよいので、試してみた。 つまり、

<head>
<style>
    ....
</style>
<script type="text/javascript"
src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js">
</script>
</head>
とするだけ。 これで、殆んどの言語を適切に認識して、問題なく色付けしてくれる。 例えば、Python のソースだと、
def plot_matches2(im1,im2,locs1,locs2,matchscores):
    
    im3 = appendimages(im1,im2)
    color = "bgrcmykw"
    
    def draw_circle(c, r, n):
        c_color = color[n % 8]
        t = arange(0,1.01,.01)*2*pi
        x = r*cos(t) + c[0]
        y = r*sin(t) + c[1]
        plot(x, y, c_color, linewidth=2)
    # show image
    imshow(im3)
    
    # draw lines for matches
    cols1 = im1.shape[1]
    for i,m in enumerate(matchscores):
        if m>0:
            draw_circle(locs1[i][:2], locs1[i][2], i)
            draw_circle((locs2[m][0] + cols1, locs2[m][1]), locs2[m][2], i)

    axis('off')
てな具合。 手でハイライトしたコードは、html ファイルでは <span style="..."></span> だらけになって、とても読めたものではない。この点だけでも、prettyprint.js のメリットは大きい。 ただ Python のハイライト等は Emacs 上で長らく我流を通してきたので、 色使いに馴染めないところもあるが、 それは追々直していく事にする。 (そもそも「人様のため」なので、このままで我慢すべきかも。)

2014-07-16 (Wed): MathType, MathML, Chrome

>> 2014-07-26 (Sat): 数式を MathJax で表示する事にしたので、若干見栄えが変わりますが、 IE や Chrome でも見えるようになりました。

Chrome の株が上がる

ウェブ・ブラウザはどれも洗練されつくしていて、 主な機能に関しては、もはやどれも同じ、と思っていた。 (止め処なく安全性に問題が出る某 IE シリーズは除く。) それでも、Firefox を使っていたのは、 設定やプラグインの管理の方法が比較的良い(もしくは単に慣れている)から。 しかし、ここに来て、まだ歴然とした差が有る分野が存在する事を再認識した。

一つには、Video Streaming 受信の際の問題。Streaming と言っても、H.264 云々ではなくて、(Motion)JPG の受信の話だが、Firefox (30.0) は Respberry Pi 上の mjpg_streamer からの画像を満足に受けられない。 いや、受信そのものは一時的には可能なのだが、動画をずっと受けていると、 メモリの使用量がやたら増えていき、その内ハングする。 一方、「ダメもと」で試してみた Chrome (35.0.1916.153) だと、そのような問題は全く無かった。

こうなると俄然、Chrome の株は大いに上がり、 それまでの「なんだかなぁ」は我慢できる気がしてくる。 ちょっと使ってみると、確かにメモリ使用量は小さいし、起動、 ページ表示とも、Firefox より速い気がする。 メニューやブックマークの文字が小さい、という不満は残るが、最近 Firefox も小さくなってきたので「不利の程度」が減少したとも言える :-p。

MathType は良いが……

そうこうしているうちに、どうしてもウェブページに数式が書きたい、 と思うようになってきた。Mac の Pages, Keynotes, MS Word, MS PowerPoint 他では、 MathType を使っていて、略不自由がなかった。 (使うのがほんの「偶に」なので、使い方を忘れてしまうのが玉にキズ。)
MathType on Keynote
MathyType で書いた Maxwell 方程式(Keynote 文書)
MathType Editing Pane
上記数式 (Eq-1) を MathType で編集中
また、それが使えない Emacs や、その上で作る HTML では、Python の書式を流用してとりあえず凌いでいた。 しかし、例えば SIFT に関する説明をするのに、 微分演算子他が書けないのはどうしてもツラい。

MathML

先々、そういう機会は増えそうなので、ちょっと真面目に調べてみた。 WikiPedia のように MathType のようなアプリで書いてそれを画像にするのがポピュラーのようだが、 WikiPedia も時々醜い数式が出て来るようなので、ちょっと敬遠。 結局 MathML (Mathematical Markup Language) を使う事にした。これは、なかなか便利で、 かつできあがりがとても美しい。 ただ、XML の流れを引くので、書き方が大仰になるというか、 ソースの可読性が今一。 しかし意外に、書く事自体はさほど苦にならない。 (Tutorial が素晴しい!)

上記の Maxwell 方程式の一つを書いてみると、

<math display='block'>
  <mo>&Del;</mo><mo>&times;</mo><mi mathvariant='bold'>H</mi>
  <mo>=</mo><mi mathvariant='bold'>I</mi><mo>+</mo>
  <msub><mi>&epsilon;</mi><mn>0</mn></msub>
  <mfrac>
        <mrow>
          <mo>&part;</mo><mi mathvariant='bold'>E</mi>
        </mrow>
        <mrow>
          <mo>&part;</mo><mi>t</mi>
        </mrow>
  </mfrac>
</math>
が、 ×H =I+ ε0 E t のようにレンダリングされる。さらに MathType の出力と比較するため、"mathvariant='bold'" を取ってみると ×H =I+ ε0 E t

のようになり、MathType と比較しても遜色無いと言えるレベルだと思う。 実は完全にディフォルトだと地の文に比較して若干フォントが小さいようなので、 mathml.css に、

math {
   font-size: 115%; 
 } 
を加えた。(色々欲張って設定しようとして別ファイルにしたのだが、 どうやら、関連 CSS への対応はまだ各ブラウザでまちまちのようで、 これしか確実に働かない……。つまり、これだけを default.css へ戻す事にする。)
>> 2014-07-26 (Sat): MathJax はディフォルトで、このサイズに近くなっていますが、 この CSS は効きません。また、括弧が少々大きすぎるようです。

で、先々週の記事ができあがったのだが、 ここで問題が……。その時点で Chrome はようやくディフォルトのブラウザに成りかけていたのだが、 これが MathML の部分を全くレンダリングしてくれない。 "MathML Chrome" でググると 「一年も前からサポートしている」という記事が沢山ヒットする。 (というか、これらを見たから MathML で行こうとなったのに。) どこか設定が違うのかな、とあちこち触ってみたが、どうしてもダメ。 又、the Internet に戻って調べてみたら、Chrome は MathML のサポートを敢えて落したのだとか。MathML は今や W3C の「公式」の標準だから、勿論の事「何故サポートをやめたんだ!?」の批判は多いのだが、 それに応えて言わく「応答性と安全性を最優先している……」 なんだかがっかりするねぇ Google さん(今そのページが見つからないけど。)

ちなみに、Chrome と IE は非対応だが、Firefox, Safari は OK で、何と Seamonkey でも問題無かった。

それやこれやで、自然に「常用のブラウザ」は、Firefox に戻り、Chrome のを使うのは、Video stream を受信する時だけ、となった。 (それも今や殆んど使わない。 Python スクリプトで受ける事が「あたり前」となったので。)


2014-07-02 (Wed): 画像処理再入門(その 1)— SIFT

  >>2014-07-07 (Mon): 改訂

>> 2014-07-26 (Sat): 数式を MathJax で表示する事にしたので、若干見栄えが変わりますが、 IE や Chrome でも見えるようになりました。
大昔のことだが画像処理を飯の種にしていた事がある。 とは、言っても、センサが 64x64 の IR-CCD とか、50 - 100 画素の FLIR だから、そんなに大した事はしていない。 なにしろ、当時のその分野では、 DARPA 様が一般的な処理フローとして contrast/gain control → 二値化 → segmentation → acquisition というのを定めていた(うろおぼえ)。 つまり早々と二値化してしまうのが前提で、 この事だけからも、そんなに大した事はしていなかったと想像がつく。 しかも、それからン十年経っている。

そんな状態から「手っ取り早く現状に追い付いてやろう」なんてのは、 今思えば、まあ虫の良すぎる料簡だった。 そもそも、全く分らない用語が幾つもある。中でも極め付けは、Homography、SIFT (Scale-invariant Feature Transform) あたり。

SIFT

この SIFT は、 J. E. Solem, "Programming Computer Vision with Python" を読み始めて直ぐに出て来た。 とても強力そうなのだが、非常に分り難い。 「ちょこっとやっつけたろ」という自分の料簡が甘いのは勿論だが、 どうやら、処理速度を上げるための実装が込み入ったものになっていて、 しかもその解説が不十分だったり、時々間違っているせいも有るようだ。

LoG (Laplacian of Gaussian) の代りに DoG (Difference of Gaussian) を使う事、スケール(規模)が二倍になる度にピクセルを間引きしていく、 という「詳細」を省くなら、 アルゴリズムはちょっとだけ明快になる。 (それでも完全な記述は「とてもとても」であるが、VLflea の SIFT を使うための option が理解できればいいや、という事で自分なりのまとめ。)

元の画像(グレースケール)を、 Ixy とし、これを分散σ の Gaussian フィルタで平滑化したものを Iσ xy とする。

  1. 特徴点抽出
    1. 上記のグレースケール画像 Ixy に分散 σ の LoG との畳み込みを取ったものを Lxyσ と表わす。
    2. これを、 σ= σ 0 2 Omin +(k/S) (k =0, 1 , ) について繰返す。結果として、xy σ (面座標と scale を合わせた空間) 上の関数 Lxyσ が得られる。 (σ0= 1.6 が前提。)
    3. 上記三次元空間の中で L の「極値」を検出する。 これらを 'keypoint' の候補とする。
    4. L の絶対値が閾値 (tp) を超えない keypoint 候補を「低コントラストである」と看做して除外。
    5. さらに、各点で L の曲率を計算し、 主軸での曲率 (α< β) の比 r (=β/α) が大きい場合 (r> rth) は、単純(直線的)なエッジに対応するピークであると看做し、これも除外。
  2. 傾斜方向の検出
    1. 各 keypoint について、半径 1.5 σ の範囲内の各ポイント (pixel) で、Iσ の傾斜の絶対値 m とその方向 θ を算出。
    2. m を重みとして、10度ごとの θ のヒストグラムを作り、このピークから傾斜方向を決定する。
  3. 特徴記述
    1. ひとつの keypoint について、そのスケール (σ) の M (Magnification Factor) 倍の正方形 (spacial bin) を、その keypoint が中心に来るように 4x4 個並べる。
    2. 各 spacial bin の中の各ピクセルごとに、 Iσ xy (=[ I σ /x, I σ /y] t ) を計算。傾斜の絶対値で重み付けした 「方向」のヒストグラムを作る(角度の刻みは π/ 4。spacial bin が 16個、それぞれに角度の bin が 8個で、計 128個の bin からなる。)

VLFeat SIFT

VLFeat の sift コマンドは、上記のアルゴリズムを離散化し、簡略化した本来の Lowe のアルゴリズムを実装している。有難い事に、これは MacPorts からインストールできる。また、その Tutorial は曖昧なところが少くとても有用。 (しかし、その DoG がらみの説明は明らかに間違っていて、 これが上の LoG での整理を試みた理由でもある。)
fukuda@quadra:~% sudo port install vlfeat
fukuda@quadra:~% port installed vlfeat
The following ports are currently installed:
  vlfeat @0.9.18_0 (active)
fukuda@quadra:~% port contents vlfeat    
Port vlfeat contains:
  /opt/local/bin/mser
  /opt/local/bin/sift
  /opt/local/include/vl/aib.h
    .....
  /opt/local/include/vl/vlad.h
  /opt/local/lib/libvl.dylib    
これへの Python wrapper (vlfeat-ctypes) もあり、PyPI でインストールできるが、 これから呼んだ sift の出力は、何故か scale と orientation が含まれないので、とりあえず上記の command を直に叩いて使う事にする。

VLFeat sift のオプション(パラメータ)
Option Default DefinitionNotes *1)
--octaves6 scale range in octave*2)
--levels3 levels per octave S in §1-b
--first-octave-1index of first octaveOmin in §1-b
--edge-thresh10the edge threshold rth in §1-e
--peak-thresh0the peak threshold tp in §1-d
--magnif3the magnification factor M in §3-a
  1. *1) このコラムの §1-b などは、上記のアルゴリズム記述の処理ステップを表わしている。
  2. *2) §1-b の σ の変化の範囲を octave で表わしたもの。 S=3 で、k=0-18 ならば、変化の範囲は 6 octave となる。

sift による特徴抽出

先日の両眼視用のサンプル画像に sift によって特徴抽出をやってみる。

まず、上記、"Programming Image Processing in Python" で使われているルーチンをモジュールに……と思っていたら、 既にインストール可能な形のパッケージが有った。(本の内容まで入っている……) 著者さん、ありがとう。しかし、これ、Py3k では動かない……。 なので、py27 を使ってインストール、かつ、py27-scipy も必要。 Git でインストール:

fukuda@quadra:~/Git% git clone https://github.com/jesolem/PCV
fukuda@quadra:~/Git% cd PCV 
fukuda@quadra:~/Git/PCV% sudo python2.7 ./setup.py install
Password:
running install
running build
running build_py
running install_lib
copying build/lib/PCV/__init__.py -> /opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/PCV
copying build/lib/PCV/classifiers/__init__.py -> /opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/PCV/classifiers
copying build/lib/PCV/classifiers/bayes.py -> /opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/py    
....   
fukuda@quadra:~% sudo port install py27-scipy
まず、グレースケール画像を作る
fukuda@quadra:~/Work% python2.7
Python 2.7.7 (default, Jun  2 2014, 01:33:49) 
[GCC 4.2.1 Compatible Apple LLVM 4.2 (clang-425.0.28)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from PIL import Image
>>> im = Image.open("diamond_left.png").convert('L')
>>> im.save('diamond_left.pgm')
>>> im = Image.open("diamond_right.png").convert('L')
>>> im.save('diamond_right.pgm') 
>>> # Ctrl-Z でエスケープ
[1]  + 32600 suspended  python2.7
fukuda@quadra:~/Work%     
fukuda@quadra:~/Work% sift -vv diamond_left.pgm --output diamond_left.dsc --first-octave 0 --peak-thresh 5
fukuda@quadra:~/Work% sift -vv diamond_right.pgm --output diamond_right.dsc --first-octave 0 --peak-thresh 5
fukuda@quadra:~/Work% %  # python に戻る
>>> import PCV.localdescriptors.sift as lds
>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> loc, fea = lds.read_features_from_file("diamond_left.dsc")
>>> lds.plot_features(im, loc, circle=True)
>>> plt.show()    
これによって、以下のような特徴点が抽出された。
Features by SIFT algorithm
SIFT (Omin = 0, tp = 5) による特徴点とそのスケール
青い円の中心が、特徴点 (key point)、その半径がスケールを表わしている。

対応する特徴点を検出

次に、左右の視野の対応する特徴点を検出してみる。 今度も PCV のルーチンを利用する。
>>> locs_l, desc_l = lds.read_features_from_file('diamond_left.dsc')
>>> locs_r, desc_r = lds.read_features_from_file('diamond_right.dsc')
>>> matches_rl = lds.match_twosided(desc_r, desc_l)
>>> im_r = np.array(Image.open('diamond_right.png'))
>>> im_l = np.array(Image.open('diamond_left.png'))
>>> lds.plot_matches(im_r, im_l, locs_r, locs_l, matches_rl, show_below=True)
>>> plt.show()    
lds.match_twosided() は、 概略次のステップ従って、特徴点を対応させる:
  1. 片方のイメージの一つの特徴点の descriptor に対して、別のイメージの特徴点の中から その descriptor がユークリッド距離 (Euclidean Distance: histogram の各 bin を vector の一成分と看做す) が最少になるものを選ぶ。 すなわち、正規化した vector (v i) の間の角 δ ( =arccos v i v j) が最少(δ min) になるものを取り出す。
  2. さらに、次に小さいもの (δ 2) を選び、 δ min< 0.6δ 2 となる δ min を与える特徴点のみを残す。
  3. さらに別の側から同様の事を行い、 得られる対応リストの中から共通の組み合わせのみを抽出する。
lds.plot_matches() は、以上の対応を、 対応する特徴点同士を直線で線結びつける事によって表示するもので、 下のような図が得られる。
Two-sided match of SIFT features
SIFT features の two-sided match
しかし、これでは対応が非常に見難いので、 plot_matches()を少し改変した plot_matches2() を作って、 それを sift.py に追加、sift2.py と名付ける。
fukuda@quadra:~/Work% diff sift.py sift2.py                            
114a115,140
> def plot_matches2(im1,im2,locs1,locs2,matchscores):
>     
>     im3 = appendimages(im1,im2)
>     color = "bgrcmykw"
>     
>     def draw_circle(c, r, n):
>         c_color = color[n % 8]
>         t = arange(0,1.01,.01)*2*pi
>         x = r*cos(t) + c[0]
>         y = r*sin(t) + c[1]
>         plot(x, y, c_color, linewidth=2)
>     # show image
>     imshow(im3)
>     
>     # draw lines for matches
>     cols1 = im1.shape[1]
>     for i,m in enumerate(matchscores):
>         if m>0:
>             draw_circle(locs1[i][:2], locs1[i][2], i)
>             draw_circle((locs2[m][0] + cols1, locs2[m][1]), locs2[m][2], i)
> 
>     axis('off')
> 
これを使って、再プロット:
>>> import sift2
>>> sift2.plot_matches2(im_r, im_l, locs_r, locs_l, matches_rl)
>>> plt.show() 
plot_maches2() の中では、(plot_matches() 同様) imshow()matplotlib.pyplot のフレームを作っているので、 plt.show() で次のような出力が表示される。
Two-sided match of SIFT features
SIFT features の two-sided match (表示を改良した)
Two-sided match を採用する事で、特徴点の数はかなり減少するものの、 残った点の間での「誤認識(誤対応)」はほぼ皆無と言って良さそう。 画像内の人物の右肩の「しわ」のあたりのように稀にスケール(円の半径)が異なる事があるが、 その場合でも中心点はほぼ対応している。 (これは、次のステップの「カメラ補正」のためには有用な特徴。) しかし一方、そもそも何を特徴点(領域)として捉えるかという点に関しては、 人の直感とかなりずれているように思える。天井の煙探知機、 及び電灯のスイッチなどは、人の目からは明白な object であるのに、対応付け前の特徴点に含まれていない。 また人物の顔の上半分は、視差の影響は少ないと思われるのに、 対応付けの後殆んどの特徴点が失なわれている。 画像理解、画像認識の基礎技術としては、もう一工夫必要かなという印象を持った。
172/1,073,970 Valid CSS! Valid HTML 5.0
Taka Fukuda
Last modified: 2016-06-15 (Wed) 11:40:50 JST