2014年11月10日月曜日

JSON文法チェック方法

データの送受信または記述のためよく使われるJSON(ジェイソン)という形式があります。
テキストなので、windowsなら標準で入っているメモ帳のようなテキストエディタで編集できます。

例えば、
{
   "name" : ["shimotomai", "takayuki"],
   "degree":"PhD"
}
こんな感じです。

入れ子構造にもでき、XML同様柔軟性が高い記述方式として最近よく使われています。

ただ、コンマ忘れやすいので、よく文法エラーになります。
もしくは最後の要素の後にコンマを入れたり、
コロンがなかったり、ダブルクォーテーションがシングルになっていたり。

ロボットの音声認識システムで、採用していたのでJSON形式よく利用していましたが、

記述が長いと、目で見てエラーをチェックするとか拷問に近いです。
あり得ません。

ということで、

自動的にチェックしてくれる方法をいくつか利用していました。
そのうちPythonを使って行う方法をご紹介します。
簡単です。

$ python -mjson.tool dummy.json



これだけです。
今回はプログラムさえ書きません。

エラーの場合

Expecting property name: line 12 column 2...
という風に行番号が表示されます。つまりこの場合は、12行目にエラーがありますよということです。


demjsonがインストールされていれば
jsonlint -v hoge.json
でもチェック可能です。

demjsonのインストールはubuntuの場合、
sudo aptitude install python-demjson
でできます。


pythonを使ったjson形式の取り扱いについてはそのうちまた詳しく書きます。




2014年11月8日土曜日

ラン ダム文字列生成

ご無沙汰しております。
最近仕事で、任意の長さのランダム文字列を生成するスクリプトを作りました。

CGIなどでセッション情報などをpythonで管理する場合、重複する可能性の低いランダムな文字列が必要になることがあります。

それで、英数字大小文字混合の26+26+10=62種類をまぜて任意の長さの文字列を作ります。
下のソースが作成したスクリプトです。

import string
import numpy
m=100
s = ''.join(numpy.random.choice( list( string.digits + string.letters ), m ))
print s


pythonはたくさんのライブラリがあって便利な反面、簡単なことをするにしても、ライブラリを複数読み込む必要があります。
今回もnumpyとstringを読み込んでいます。
numpyは以前も説明した通り、python標準ではありませんので、別にインストールする必要があります。

ポイントとしては
listで文字列をリストに変換しているところと、
numpy.random.choiceで配列要素から100個サンプリングしているところです。
string.lettersは'abcd.....'というようなすべての英数字を含んだ文字列が欲しかったので使いました。

もちろん、他の方法でもできますが、これが一番理解しやすくて簡潔だと思います。
是非使ってみてください。





2014年7月22日火曜日

mysql

今回はMySQLとの連携です。
PythonからMySQLに接続するためのライブラリはいくつかあります。

ここではMySQL標準の
mysql-connector-python
を使います。

MySQLのConnectorのページに行けばインストーラがあるはずです。
http://dev.mysql.com/downloads/connector/
ここからインストーラをダウンロードしてインストールします。



呼び出すコードは


import mysql.connector

con = mysql.connector.connect( user='x', password='xyz', host='127.0.0.1', database='test' )
cur = con.cursor()
sql = 'CREATE TABLE hoge( id int, value double, comment varchar(32) )'
cur.execute( sql )

con.commit()
cur.close()
con.close()


という感じです。

connectの時の引数は適宜入れ替えて使って下さい。
特にuserとpasswordです。ここでは適当な値を入れていますが、それぞれ、設定した通り入力してください。
sqlの中身に関しても同様です。今回はテーブルを作成していますが、SQLクエリを作成してexecuteに入れます。
ここはsqliteとだいたい一緒です。

データを引き出してくるときは

cur.execute( 'SELECT * from hoge;' )
for r in cur:
   print r

という感じで取ってこれます。
これもsqliteの時とだいたい一緒です。
sqliteとは違うのは、DBのサーバ設定が必要なところです。
そっちはMySQLのサイトなどを参照してください。


補足ですが、
MySQLに保存したデータの実体は
C:\ProgramData\MySQL\MySQL Server 5.6\data
というところにあります。
この下にSchema名のフォルダがあります。そのフォルダ下にtable名のファイルがあります。
commitすると更新されるようです。
逆に言うと、commitを実行しないと、更新されません。



2014年6月23日月曜日

OpenCV 4

Contourとは等高線を指しますが、輪郭という意味もあります。
OpenCVではcontourを輪郭情報という意味で使用しています。

cv2の中にはfindContoursというcontourを計算する関数があります。
つまり、画像から輪郭を抽出することができます。
たとえば、
ret, thresh = cv2.threshold( imgray, 127, 255, 0 )
c = cv2.findContours( thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE )
とすることによりimgrayの画像を閾値処理して輪郭抽出します。

ただし、imgrayというのは2値化された画像で、通常のカラー画像を入れるとエラーになります。
カラー画像imを2値画像gimに変換する場合は、
gim = cv2.cvtColor( im, cv2.cv.CV_BGR2GRAY )
とします。


contourを描画する場合、
cv2.drawContours( im, c, -1, (0,255,0), 3 )
とすると緑色で輪郭情報cを画像imに描画します。

輪郭情報を最小の長方形領域に納める場合
x,y,w,h = cv2.boundingRect(c)
とします。
この長方形領域は
cv2.rectangle(im,(x,y),(x+w,y+h),(0,255,0),2)

とすることによって描画できます。



以上を踏まえて、
WEBカメラから取得した画像から輪郭を抽出して描画するプログラムを作ってみました。
ENTERキーを押すと終了します。


import cv2
import numpy as nmp

cv2.namedWindow('CAMERA')
v = cv2.VideoCapture(0)
v.grab()
im = v.read()

### to binary
gim = cv2.cvtColor( im[1], cv2.cv.CV_BGR2GRAY )
### thresholded
ret, thresh = cv2.threshold( gim, 127, 255, 0 )

c = cv2.findContours( thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE )
for i, cc in enumerate(c[0]):
 cv2.drawContours( im[1], cc, -1, (50*i/255,255,i%255), 3 )
 print '%d,255,%d' % ( 20*i/255, i%255)


cv2.imshow( 'CAMERA', im[1] )
cv2.waitKey(0)


ラボの画像から輪郭抽出してみました。

たくさんの小さい輪郭ができてしまいました。
実際に使う場合は、いかにして目的とするものの輪郭を計算するかという工夫が重要だと思います。

2014年6月9日月曜日

フラクタル 第4回

フラクタルシリーズの4回めです。

今回も、マンデルブロのアレンジを作ってみました。
ただ、毎回関数を別に作るのは無駄なので、P乗で一般化してみました。
つまり、

z(n+1) = z(n)**p + c
z(0)=0

とした時のcと最終のzの値を出力します。


import numpy as np

def makeMandelbrotP( itrn, p=2, n=100, xrange=None, yrange=None ):
if xrange == None:
xrange = (-2.5, 2.5)
if yrange == None:
yrange = (-2.5, 2.5)
r = np.random.uniform( xrange[0], xrange[1], n) + 1j*np.random.uniform( yrange[0], yrange[1],n)

c = r.copy()
z = 0
for i in range(itrn):
z = z**p + c
return c, z

今回はp=4として4乗にした時、このzの値が発散しているかどうかを複素平面上に表示しました。


予想通り、120度の回転対称です。
前回の3乗で180度対称だったので、p乗で306/(p-1) 度の回転対称になるものと想像できます。
この図は16回の繰り返しです。


繰り返し回数については、8回ぐらいでだいたいフラクタルっぽくなります。


繰り返し2回

繰り返し3回

繰り返し4回

繰り返し5回

繰り返し6回

繰り返し7回
繰り返し8回
という感じです。
一枚あたりのデータ量が多く、リスト内表記を使うとメモリアロケーションのエラーになるので、
仕方なくforループを使いました。
通常書類作成用に使っているPC(Core2Quad 2.4GHz)で、上の画像作成時間は一枚あたり6分位かかりました。






2014年6月6日金曜日

pythonからsqlite(DB)の使用

今日はsqliteの話です。
簡単なことしか書いていませんが、しばらく使わないと手順を忘れてしまうこともありますので自分自身の備忘録です。


シミュレーションや分析で、パラメータが多いとデータの管理に手間がかかります。
一度のシミュレーションデータが膨大な場合もどのように保存するかで後々の分析の効率が悪くなったり問題が起こったりします。

一度のシミュレーションにかかる時間が長い(1日とか)と次にどのパラメータでシミュレーション(または分析)をするべきか悩むことがあります。
また、観点を変えて分析をしてみたいと思ったときに、データがそろっているとは限りません。判断をするために足りないデータが何なのかを知る必要があります。


そこで、データの管理のため、データベースを使うと便利なことがあります。


python2.6では標準モジュールとしてsqliteが入っています。
sqliteはフリーのデータベースです。

使い方は


データベースに接続
c = sqlite.connect( 'hogehoge.db' )

切断
c.close()

SQLクエリ送信
sql = 'create table ccc ( iteration integer, realpart float, imagpart float );'
c.execute( sql )

結果受信
sql = 'select * from ccc'
cc = c.cursor()
for r in cc.execute( sql ):
   print r

という感じで使います。

大事なのが、コミット
c.commit()
です。

とりあえずは「これで保存します」の意味だと思って下さって構わないと思います。
これがないと保存されません。

SQLに関してはネット上を検索すればわかりやすいサイトがたくさんあると思いますので、そちらに任せます。




2014年5月29日木曜日

フラクタル 第3回


今度は前回のマンデルブロ集合の変則的な形として、試してみたものです。


今回は

z(n+1) = z(n)^3 + c

という漸化式による収束性について複素平面の図を作ってみました。

できたのは下のような左右対称な図です。


各c(複素数)の点で、zの発散しなかった領域が黒い部分です。緑部分は発散領域です。
この場合もフラクタルのような図形になりました。
図の中央が原点で、左右対称な図形となりました。
範囲は実数軸、虚数軸ともに-1.5から1.5までです。

データ点は約14M 個生成して作成しました。
漸化式の繰り返し回数は10回です。

今回はpythonからデータを生成して、MySQLを使ってデータを管理しましたが、30分程度かかりました。
今回の計算結果はWEBを検索しても簡単に見つからなかったので、ちょっとした課題としていいかもしれません。



作った関数はこんなかんじです。

def makeMandelbrot3( itrn, n=100, xrange=None, yrange=None ):
if xrange == None:
xrange = (-2.5, 2.5)
if yrange == None:
yrange = (-2.5, 2.5)
c = np.random.uniform( xrange[0], xrange[1], n) + 1j*np.random.uniform( yrange[0], yrange[1],n)

z = 0
for i in range(itrn):
z = z**3 + c
return c, z


itrnは繰り返し回数で、データ数はnです。
戻り値はcとzなので、
この関数を使用するときは

c, z = makeMandelbrot3( 10, 1000 )

のようにします。
これで繰り返し10回のデータcとzが1000点分生成されます。
メモリ確保の問題さえなければ、nの値を大きくすればその分データが生成されます。