LionでGoogle App Engine用の仮想環境構築
MacOSX Lionでvirtualenv, virtualenvwrapperを使ってGoogle App Engine(GAE)用の仮想環境を構築しようとして少しはまったのでメモ。
環境
- MacOSX Lion
- Python2.7.2 (virtualenv起動)
- Python2.5.6 (仮想環境のinterpreter、macにdefaultで入っているもの。/usr/bin/python2.5)
エラーと解決法
mkvirtualenv --python=/usr/bin/python2.5 --no-site-packages gae
と入力したところ、
distutils.errors.DistutilsPlatformError $MACOSX_DEPLOYMENT_TARGET mismatch: now "10.5" but "10.7" during configure
エラー発生。エラーを吐いている部分のソースコードを読んでみると,
if sys.platform == 'darwin' and g.has_key('MACOSX_DEPLOYMENT_TARGET'): cfg_target = g['MACOSX_DEPLOYMENT_TARGET'] cur_target = os.getenv('MACOSX_DEPLOYMENT_TARGET', '') if cur_target == '': cur_target = cfg_target os.putenv('MACOSX_DEPLOYMENT_TARGET', cfg_target) elif map(int, cfg_target.split('.')) > map(int, cur_target.split('.')): my_msg = ('$MACOSX_DEPLOYMENT_TARGET mismatch: now "%s" but "%s" during configure' % (cur_target, cfg_target)) raise DistutilsPlatformError(my_msg)
cur_targetはmacの環境変数$MACOSX_DEPLOYMENT_TARGETを読んだ値,
cfg_targetは/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/config/MakefileのMACOSX_DEPLOYMENT_TARGETの値らしいんで,.zshrcに,
export MACOSX_DEPLOYMENT_TARGET=10.7
と書いて,sourceしたら無事に環境構築できました。
使ってるOSはLionなので10.7に設定しても問題ないよね...?
PythonでSQLite3を使う
Python2.5以降はsqlite3が標準モジュールとして使えるらしいので、
の問題点の一つである「一度取得した書籍情報を再び取得してしまう」を解決するために、書籍情報を保存するデータベースを生成する。
参考
データベースについては完全な初心者なので、一般知識については、MySQL/PostgreSQLなどデータベースの学習ならDBOnlineの(移転しました)、SQLite入門を見て勉強した。
また、Pythonのsqlite3モジュールの使用法については、http://www.python.jp/doc/2.5/lib/module-sqlite3.html、SQLite3を使用する - Python Tipsを参考にした。
まだ、勉強し始めたばかりなので上手いデータベースデザインの勘は掴めていないと思うが、
- メンテナンス性を高く保つ(正規化)
- アクセス速度を保つ(ディスクアクセス量を出来るだけ減らす)
に注意してアプリケーションにあったデザインを素直に考えれば今のところは大丈夫じゃないかなと思う。普段のプログラミングのクラス設計と似ている部分も多くあるだろう。
というわけで、実際に簡単なサンプルを実装してみた。
データベースの生成
#!/usr/bin/env python # -*- coding: utf-8 -*- import sqlite3 db = sqlite3.connect('data.db', isolation_level=None) c = db.cursor() sql = u""" create table books ( title varchar(100), price integer, id integer ); """ c.execute(sql) sql = u"insert into books values ('python', 2000, 1)" c.execute(sql) items = ( ('perl', 3000, 2), ('ruby', 1500, 3) ) for t in items: c.execute(u"insert into books values (?,?,?)", t) sql = u"select * from books" c.execute(sql) for record in c: print record[0], record[1], record[2] db.close()
データベースからレコードの取得
#!/usr/bin/env python # -*- coding: utf-8 -*- import sqlite3 db = sqlite3.connect('data.db') c = db.cursor() sql = u"select * from books" c.execute(sql) for record in c: print record[0], record[1], record[2] db.close()
基本的には、
- connect関数で対象のデータベースと接続したConnectionオブジェクトが返る
- ConnectionオブジェクトのcursorメソッドでCursorオブジェクトが返る
- CursorオブジェクトのexecuteメソッドでSQL文を実行し、結果が返る
これだけ分かっていれば、とりあえずデータベースの操作はできそうだ。
SQLite3を使用する - Python TipsではConnectionオブジェクトに対してテーブルの生成やレコードの追加を行っていたが、http://www.python.jp/doc/2.5/lib/module-sqlite3.htmlではCursorオブジェクトに対して行っている。両者の違いについて調べたところ、
Connection オブジェクトの非標準的なメソッド execute, executemany, executescript を使うことで、 (しばしば余計な) Cursor オブジェクトをわざわざ作り出さずに済むので、 コードをより簡潔に書くことができます。Cursor オブジェクトは暗黙裡に 生成されショートカットメソッドの戻り値として受け取ることができます。この方法を 使えば、 SELECT 文を実行してその結果について反復することが、 Connection オブジェクトに対する呼び出し一つで行なえます。
http://www.python.jp/doc/2.5/lib/node353.html
ということらしい。つまり、Connectionオブジェクトのexecuteメソッドは名無しのCursorオブジェクトを勝手に生成してSQL文を実行してくれるショートカットで、ソースコードの簡略化が目的らしい。そこまで深く考える必要はなかったようだ。
次回は、実際にAmazonのProduct Advertising APIを使ってISBNから書籍情報を取得する - 脳みそHackと組み合わせてみる。複数のテーブルを持つデータベースの作成も行いたい。
AmazonのProduct Advertising APIを使ってISBNから書籍情報を取得する
- PythonからOpenCV 2.2を使う(MacOSX SnowLeopard + homebrew) - 脳みそHack
- OpenCVとZBarを使ってPythonでバーコードリーダを作る - 脳みそHack
の続きで、バーコードから読み取ったISBNをAmazonから提供されているAmazonログインに入力して書籍情報を取得する。
Product Advertising APIの使用方法
Representational State Transfer - Wikipediaを用いたWebAPIで、
- 認証情報や欲しい情報を取得するための引数をつなげたURLを送信
- 帰ってきたxmlから情報を取得
という流れになる。
URLの生成やリクエストの送信を隠蔽したモジュールを公開してくださっている方がいたので、ありがたく使わせていただく。
PythonでAmazon Product Advertising APIを使う - 人工知能に関する断創録
PythonでWebカメラからバーコードを読み、取得したISBNからProduct Advertising APIを使って書籍情報の取得
ソースコードのタイトルがだんだん長くなってきましたが、今回も分割せず一本道のソースコードになっております。そろそろリファクタリングした方がいいかな...
import cv import time import zbar import Image from amazon import Amazon from BeautifulSoup import BeautifulStoneSoup cv.namedWindow("camera", 1) capture = cv.CreateCameraCapture(0) width = None height = None if width is None: width = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH)) else: cv.SetCaptureProperty(capture,cv.CV_CAP_PROP_FRAME_WIDTH,width) if height is None: height = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT)) else: cv.SetCaptureProperty(capture,cv.CV_CAP_PROP_FRAME_HEIGHT,height) amazon = Amazon("your_access_key","your_secret_access_key") while True: img = cv.QueryFrame(capture) size = cv.GetSize(img) gray_img = cv.CreateImage(size, cv.IPL_DEPTH_8U, 1) cv.CvtColor(img, gray_img, cv.CV_BGR2GRAY) scanner = zbar.ImageScanner() scanner.parse_config('enable') zbar_img = zbar.Image(gray_img.width, gray_img.height, 'Y800', gray_img.tostring()) scanner.scan(zbar_img) for symbol in zbar_img: print 'decoded', symbol.type, 'symbol', '"%s"' % symbol.data if symbol.type == 'ISBN10': xml = amazon.itemLookup(symbol.data, SearchIndex="Books", IdType="ISBN", ResponseGroup="Large,Similarities", ReviewPage="1") print amazon.url soup = BeautifulStoneSoup(xml) item = soup.find("item") print item.asin print item.itemattributes.title print item.itemattributes.listprice.amount cv.ShowImage("camera", gray_img) k = cv.WaitKey(10); if k == 'f': break
前回から追加した部分は、
現時点での問題点としては、
- 同じ書籍でもISBNが取得されれば10msごとにProduct Advertising APIを叩いてしまう
- 柄のある背景にバーコードが印刷されている場合に認識率が悪い
- グレースケールではなく背景の柄を消すような二値化処理が出来れば認識率は上がるはず
- ソースコードが醜い
上記の問題点を修正しつつ、次回は、mechanizeと絡めていきたい。
MacVim-KaoriYaでcolorschemeの設定
.vimrcでcolorschemeを設定していたが、何故かうまく反映されなかった。正確に言うと、MacVimを起動してからsource .vimrcをしないと反映されなかった。
.vimrcの最終行にcolorschemeの設定を書いてみたりいろいろ悩んだ挙句、MacVim-KaoriYaのReadmeを読み返してみると、
GUIに関係しない設定、たとえば tabstop, shiftwidth, expandtab, wrap, showmatch などの設定はホームフォルダ/.vimrcにて設定することをオススメします。
http://code.google.com/p/macvim-kaoriya/wiki/Readme
GUIに関する設定、たとえば columns, lines, guioptions, transparency, antialias, colorscheme などの設定は ホームフォルダ/.gvimrcにて設定することをオススメします。
MacVim.app/Contents/Resources/vim/vimrc
ホームフォルダ/.vimrc または _vimrc
MacVim.app/Contents/Resources/vim/gvimrc
ホームフォルダ/.gvimrc または _gvimrc
の順番で読み込まれます。
.gvimrcを作成してcolorschemeを設定しvimを起動するとあっけなく成功。灯台下暗し。
ちなみに使用しているcolorschemeはVim color scheme: Wombat | Not Really A Blog。
OpenCVとZBarを使ってPythonでバーコードリーダを作る
PythonからOpenCV 2.2を使う(MacOSX SnowLeopard + homebrew) - 脳みそHackの続きで、ZBar bar code readerと組み合わせてバーコードリーダを作る。
ZBarのインストール
homebrewを用いてZBarをインストールする.
brew install zbar
その後,ZBarのpythonラッパーをpipを用いてインストールする.コンパイルにPIL(Python Image Library)を使用するので、先にPILをインストールする必要がある。
pip install PIL pip install zbar
また、ZBarの実行にはnumpyも必要なので、numpyもインストールする。
しかし、pipやeasy_installでnumpyをインストールしてZBarを使ったコードを実行しようとすると、
RuntimeError: module compiled against ABI version 2000000 but this version of numpy is 1000009 Traceback (most recent call last): File "cv_gray.py", line 1, in <module> import cv ImportError: numpy.core.multiarray failed to import
というエラーメッセージが出てしまう。pipやeasy_installで入るnumpyのバージョンは1.6.0だが、どうやら、ZBarはnumpy2.0.0を使いたいらしい...。
MacOSX SnowLeopard用のnumpy2.0.0インストーラがなかなか見つからない中、http://stronginference.com/scipy-superpack/を見つけたので、インストールしてみる。実行...うまくいった!
virtualenv
virtualenv使ってる人は、共通のsite-packagesから仮想環境のsite-packagesにnumpy-2.0.0.dev_f72c605_20110113-py2.6-macosx-10.6-universal.eggをコピーして、仮想環境上で、
easy_install numpy
という手順を踏むと、仮想環境上でnumpy2.0.0が使えるようになります。
もっとスマートな解決法があれば誰か教えてください。
webカメラで取得した画像中のバーコードをデコードする
Hello Absurd World! Webカメラを使ったバーコードスキャン on pythonを参考に作った。
import cv import time import zbar import Image cv.namedWindow("camera", 1) capture = cv.CreateCameraCapture(0) width = None height = None if width is None: width = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH)) else: cv.SetCaptureProperty(capture,cv.CV_CAP_PROP_FRAME_WIDTH,width) if height is None: height = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT)) else: cv.SetCaptureProperty(capture,cv.CV_CAP_PROP_FRAME_HEIGHT,height) while True: img = cv.QueryFrame(capture) size = cv.GetSize(img) gray_img = cv.CreateImage(size, cv.IPL_DEPTH_8U, 1) cv.CvtColor(img, gray_img, cv.CV_BGR2GRAY) scanner = zbar.ImageScanner() scanner.parse_config('enable') zbar_img = zbar.Image(gray_img.width, gray_img.height, 'Y800', gray_img.tostring()) scanner.scan(zbar_img) for symbol in zbar_img: print 'decoded', symbol.type, 'symbol', '"%s"' % symbol.data cv.ShowImage("camera", gray_img) k = cv.WaitKey(10); if k == 'f': break
- webカメラから画像を取得する
- グレースケールに変換
- Zbar.Image形式に変換
- 画像をスキャン
- デコード結果を表示
という処理をループしている。
ZBarライブラリ内にもvideoの入力を扱う関数が用意されているが、iSight(Macに標準で搭載されているwebカメラ)の指定方法が分からなかった。/dev/にiSightを示すドライバが見当たらないので、iSightは通常のusb接続のwebカメラとは扱い方が異なるようだ。OpenCVではcv.CreateCameraCaptureで引数0をとるとiSightからの画像を取得できる。このあたりよく分かっていないので要勉強。
次は、PythonでAmazon Product Advertising APIを使う - 人工知能に関する断創録を参考にバーコードから書籍情報を取得する。
PythonからOpenCV 2.2を使う(MacOSX SnowLeopard + homebrew)
Pythonを使って画像処理をやってみたいなと思っていたところ、こんな記事を発見。
Starting with OpenCV release 2.2, OpenCV will have completed it's new Python interface to cover all the C and C++ functions directly using numpy arrays.
http://opencv.willowgarage.com/wiki/PythonInterface
インストール
macportsヤメてhomebrewにしました。でopencvをsnow leopardに入れる方法 - ( ꒪⌓꒪) ゆるよろ日記を参考に、homebrewを使ってOpenCVをインストール。後はOpenCVのPythonバインディング(動的ライブラリ)であるcv.soをPYTHONPATHの通った場所にコピーすれば、PythonからOpenCVが使えるようになっているはず。
Macに初めから入っているPythonを使う場合の手順は以下のようになります。
brew install opencv cp /usr/local/Cellar/opencv/2.2/lib/python2.6/site-packages/cv.so /Library/Python/2.6/site-packages/
webカメラで取得した画像をそのまま表示
とりあえず簡単なデモを試してみたいなとググッてみると、ちょうどいいサンプルを発見。
http://www.betasix.net/opencv-2-2-python-examples/
import cv import time cv.NamedWindow("camera", 1) capture = cv.CreateCameraCapture(0) width = None #leave None for auto-detection height = None #leave None for auto-detection if width is None: width = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH)) else: cv.SetCaptureProperty(capture,cv.CV_CAP_PROP_FRAME_WIDTH,width) if height is None: height = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT)) else: cv.SetCaptureProperty(capture,cv.CV_CAP_PROP_FRAME_HEIGHT,height) while True: img = cv.QueryFrame(capture) cv.ShowImage("camera", img) k = cv.WaitKey(10); if k == 'f': break
動いた!
次は、ZBar bar code readerと絡ませて遊んでみたい。