When it’s ready.

出来るまで出来ない

Python温泉 #10 ファイナル

Youtube APIとOpenCVだらだら触った2日間だった。

OpenCV2.3.1aとPythonの組み合わせの資料が少なくて思いの外時間を食った。
ジェスチャーまで行けなかったけど、顔切り出しまでのコード

OpenCVをインストール

Brewで2.3台が入るのでそれを利用させてもらった

brew install opencv

Python ソース

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

import sys
import cv

def detect(image):
  image_size = cv.GetSize(image)

  # create grayscale version
  grayscale = cv.CreateImage(image_size, 8, 1)
  cv.CvtColor(image, grayscale, cv.CV_BGR2GRAY)

  # create storage
  storage = cv.CreateMemStorage(0)

  # equalize histogram
  cv.EqualizeHist(grayscale, grayscale)

  # detect objects
  cascade = cv.Load('haarcascade_frontalface_alt.xml')#, (1, 1))
  faces = cv.HaarDetectObjects(grayscale, cascade, storage, 1.2, 2, cv.CV_HAAR_DO_CANNY_PRUNING, (50, 50))

  if faces:
    for ((x,  y,  w,  h),  n) in faces:
      print "posX, Y, N : ", x, y, n
      print "Width, Height : ", w, h
      cv.Rectangle(image, ( int(x), int(y)),
                   (int(x + w), int(y + h)),
                   cv.RGB(0, 255, 0), 3, 8, 0)
  return faces


if __name__ == "__main__":
  print "Press ESC to exit ..."

  # create windows
  cv.NamedWindow('Camera', cv.CV_WINDOW_AUTOSIZE)

  # create capture device
  device = 0
  capture = cv.CreateCameraCapture(0)
  cv.SetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH, 640)
  cv.SetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT, 480)

  # check if capture device is OK
  if not capture:
    print "Error opening capture device"
    sys.exit(1)

  while 1:
    frame = cv.QueryFrame(capture)
    if frame is None:
        break

    # mirror
    cv.Flip(frame, None, 1)

    # face detection
    faces = detect(frame)

    if len(faces)>0:
      frame = cv.GetSubRect(frame,  faces[0][0])


    # display webcam image
    cv.ShowImage('Camera', frame)

    # handle events
    k = cv.WaitKey(10)

    if k == 0x1b: # ESC
      print 'ESC pressed. Exiting ...'
      break

顔だけ抜き出して、表示する。顔がないとカメラ全体を表示する。
朝までに、複数顔対応したい。

クロームレス Youtubeプレーヤー

http://youtube.atu.si/
コントロールを表示させないプレーヤーを生成して、外部からボタン等でコントールする。

<script type="text/javascript">

var params = { allowScriptAccess: "always" };
var req_urls = "http://www.youtube.com/apiplayer?enablejsapi=1&version=3&wmode=transparent&video_id="
var atts = { id: "myytplayer" };
var win_width = window.innerWidth * 0.8;
var win_height = window.innerHeight * 0.8;
swfobject.embedSWF(req_urls + "xLYiIBCN9ec&playerapiid=ytplayer",
    "ytapiplayer", ""+win_width, ""+win_height,  "9",  null,  null,  params,  atts);

function onYouTubePlayerReady(playerId) {
  ytplayer = document.getElementById("myytplayer");
}

function play() {
  if (ytplayer) {
    ytplayer.playVideo();
  }
}

function stop() {
  if (ytplayer) {
    ytplayer.stopVideo();
  }
}

</script>


Python温泉は、今回の10回をもって終了らしい。
ここでの出会いと、経験はとても貴重でユニークなモノだった。
毎回まとめてくれたV、クマ。そして参加者の皆様、有り難うございました。
( 写真アップしました )
またいつか近いうちによろしくお願いします。

次は忘年会かな?

超シンプルな、pushState + Ajax = PJAXのサンプル Flask編

HTML5熱いですね。いろんな意味で

BigPipeやら、HTMLでテンプレートエンジンとかいろいろ出ていますがユーザービリティ下げちゃいけないよねって事は、どの技術でも大切な共通項ですね。pjax = pushState + ajax使えば、リッチな人にはサクサクなUIを、そうじゃない人にもそれなりに提供できる。その上、戻るボタンもサーチエンジンにも優しいとくれば、これは試さないわけには行かないですね。

動作サンプル: http://pjax.atu.si/

Pjaxするとどうなるのか?

非同期動作時

http://pjax.atu.si にアクセスをして、リンクをクリックすると要素が非同期に変更される。
非同期に更新されているがURLは、シンプルなものに変更される。

同期動作時

http://pjax.atu.si/parts/xhttp://pjax.atu.si/parts/y にアクセスするとページ全体が、同期的に更新される。ローカルブラウザでレンダリングされない。


Pythonのサンプルが全然無かったので、Flaskで実装してみました。メチャシンプルですぉ
ファイル構成

.
├── __init__.py
├── main.py
├── static
│&#160;&#160; └── js
│&#160;&#160;     ├── jquery-1.6.2.min.js
│&#160;&#160;     └── jquery.pjax.js
└── templates
    └── pjax.html

クライアント側

<!DOCTYPE HTML>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>PJAX and Flask</title>
  <script src="/static/js/jquery-1.6.2.min.js" type="text/javascript"></script>
  <script src="/static/js/jquery.pjax.js" type="text/javascript"></script>
  <script>
  //$(function() {
  $(document).ready(function() {
    console.log('load done');
    $('a').click(function(evt){
      evt.preventDefault();
      console.info(evt);
    });
    $("a.js-pjax").pjax("#main");
  });
  </script>
</head>
<body>
<a href="/parts/x" data-pjax="main" class='js-pjax'>パーツX</a><br>
<a href="/parts/y" data-pjax="main" class='js-pjax'>パーツY</a><br>
<div id="main">
{% if p.main  %}
 {{ p.main }}
{% endif %}
</div>
</body>
</html>
  • aタグのデフォルト動作をキャンセルし、パーツXとパーツYのリンクを乗っ取る。
  • $(リンク要素).pjax(DOM要素) で、リンク要素が押されるとX-PJAXヘッダー付きのリクエストが流れて、レスポンスがDOM要素に詰め込まれる。
#!/usr/bin/env python
#coding:utf-8


from flask import Flask,render_template, request
import os

os.chdir('/var/www/pjax_flask/src')
app = Flask(__file__)

@app.route('/')
def index():
  p = {}
  return render_template('pjax.html', p=p)

@app.route('/parts/<type>')
def get_parts(type):
  p = {}
  if "X-PJAX" in request.headers:
    return 'only parts %s'%(type)
  p['main'] = 'all page with parts %s'%(type)
  return render_template('pjax.html', p=p)

def main():
  app.run(host='0.0.0.0')

if __name__ == '__main__':
  app.debug = 1
  main()

パーツのリクエストが非同期で飛んで来る時は、jquery.pjaxがヘッダーにX-PJAX付与される。直接リクエストが来るときには、X-PJAXが付与されない。よって、非同期の時はパーツのみレスポンスし、直接リクエストが来る場合には、テンプレートを使ってレンダリングし全体をレスポンスとして返す。

やってみて

jquery.pjax理解するのが、大変だったけど実際に実装するのは簡単だった。
これくらいの手数が増える程度で、戻る対応出来たり、JS非対応ブラウザに対応出来たりするのは感動もの。
今後大きく利用される可能性があると感じるのは、動かしてみて挙動自体に違和感がなく想像通りに動いているっていうのところ。何でもかんでも新しいモノに変われば良いってもんじゃない、以前と同じように使えてるように見えて実はAJAX出来たり、それと同じ様に見えてるのに、非AJAXで動作してるっていうのがいいよね。

ソースはこちら : https://bitbucket.org/a2c/pjax_flask/

オールドPython2.4.xでのtimeoutの仕込み方

Python2.6だと

import urllib2
def hoget():
  try:
    result = urllib2.urlopen(req_url, timeout=5)
    return result.read()
  except urllib2.URLError, e:
    print e

で仕込めるらしいが、Python2.4.3だと使えない。(いまさら2.4なのが痛いが)

で、2.4だとどうすればいいのか分かったのでメモ

import urllib2
import socket
socket.setdefaulttimeout(5)

def hoget():
  try:
    result = urllib2.urlopen(req_url, timeout=5)
    return result.read()
  except urllib2.URLError, e:
    print e

これでいける。カツル!

情弱ユーザーにも使えるRedmine @sakuraVPS(ubuntu10.04)

こんにちわこんにちわ。ニュースではめっちゃ雪降ってるところがあるのにまだ今シーズン雪を見たことないJJなa2cです。

今日は、Redmineのインスコねたです。
0.12から、hgが使いやすくなっただの日本語が標準で入ってるだの噂を聞いてTracでもいれてみようとしたのですが、5時間かかっても全然うまく動かなくて涙目。
同じようなソフトでRedmineがあるので、そっちも試してみようとやってみたら、1時間もかからないでセットアップ出来てしまったのでその手順。

ubuntu10.04 serverで、sakuraVPS上に入れてみました。

aptitude install redmine

と、50個くらいいろんなモノをインストールして、途中でDBは何にしますか?的なダイアログが出てくるので
Yes と sqlite3 を選択する。

インストール作業は以上

バーチャルホストで動かしたいので、sitesの設定をする
/etc/apache2/sites-avalable/redmine を作成

<VirtualHost *:80>
    ServerName rm.example.com
    ServerAdmin rm-admin@exsample.com

    DocumentRoot /usr/share/redmine/public
    <Directory /usr/share/redmine/public/>
      Options All
      order allow,deny
      allow from all
    </Directory>
</VirtualHost>

このままだと、passengerモジュールの不具合でsession.ymlが読めないって怒られるのでモジュールの設定を変える
/etc/apache2/mods-available

<IfModule mod_passenger.c>
  PassengerRoot /usr
  PassengerRuby /usr/bin/ruby
  PassengerDefaultUser www-data
</IfModule>

最後の ”PassengerDefaultUser www-data” を追加した。

あとは、sitesを有効にするコマンドとアパッチを再起動

a2ensite redmine
/etc/init.d/apache2 restart

たったこれだけで、redmineが使えるようになる。

## 使い方

  1. 新規にプロジェクトを立てる
  2. リポジトリーのタイプをmercurialにする
  3. リポジトリーのパスを追加

以上!

これ以上無いくらい簡単でありがたや

xrange? OS? なんのちがいだろ?

xrangeで高速化 ? python練習帳

pythonのコードを多少高速化してみたみたいなエントリーを見つけて自分もやってみたけど、結果がえらい違った。
上記Blogでテストされている方は、i7のメモリ6GBとか結構ゴージャスな環境でやっているみたい、私はMBP15インチ上でOSX付属のPythonでやってみた。

atusiMBP15% python
Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49) 
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import profile
>>> profile.run('sum(xrange(1,10000001))')
         4 function calls in 0.144 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.007    0.007    0.007    0.007 :0(setprofile)
        1    0.136    0.136    0.136    0.136 :0(sum)
        1    0.000    0.000    0.136    0.136 <string>:1(<module>)
        0    0.000             0.000          profile:0(profiler)
        1    0.000    0.000    0.144    0.144 profile:0(sum(xrange(1,10000001)))


>>> 

一番軽いパターンで試してみたけど、0.144 CPU secondsで終わってる。上記エントリーやつだと0.811 CPU secondsかかってる。
5倍以上差があるんだけど、全く同じコードで、よりしょぼい環境で5倍速いってなんでだろうなぁって思った。

Ubuntuとかだったらどうなるんだろう・・・sakuraVPSのubuntuで試そうとしたけどprofileが無いって怒られた。

Flaskでおっきめのアプリになってきた時にモジュールで分ける方法

PythonHackathon2010.11に参加しました。redisチームに紛れてFlaskもやってました。

さて。PythonでWAFって、定番がないですよね。(良いか悪いかおいおいて)
個人的には、デカ目ならDjango、ちっさ目ならFlaskを選んでいます。とはいえ、最近はFlaskばっかりになっていますが・・
Flaskでちょいちょい色気づいてくるとドンドンURLが増えてきたり、ソースがでかくなってきます。そんな時に、Djangoだったらappに分けられるのに!とか公開したりするわけです。Flaskでも、同じようにProject内にAppが配置されるようになれば良いなぁと思っていたんですが、今日の勉強会でやり方を知りました。

flask.Flaskでappを作りますが、flask.Moduleという奴があります。それをappにURLと共に登録するとDjangoのAppの用に使うことが出来ます。

ファイル構成

.
|-- main.py
|-- appa
|   |-- __init__.py
|   |-- main_a.py
|-- appb
|   |-- __init__.py
|   `-- main_b.py
|-- main.py
|-- statics
|   |-- css
|   `-- js
`-- templates
    |-- appa
    |   `-- a_index.html
    `-- appb
        `-- b_index.html

フォルダー内に、main.pyがあります。同階層にアプリケーションA(appa)とアプリケーションB(appb)が存在ます。それぞれのアプリには、/a と /bを割てる感じにします。

main.py

  1 #!/usr/bin/env python                                                                                                                                                                 
  2 # coding:utf-8
  3 
  4 from flask import Flask
  5 from appa.main_a import appa
  6 from appb.main_b import appb
  7 
  8 app = Flask(__name__)
  9 app.debug = True
 10 
 11 
 12 @app.route('/')
 13 def index():
 14   return 'top'
 15 
 16 app.register_module(appa, url_prefix='/a')
 17 app.register_module(appb, url_prefix='/b')
 18 
 19 
 20 if __name__ == '__main__':
 21   app.run()

5,6行目 各モジュール内のモジュールオブジェクトをロードします。(モジュールオブジェクトは後述)

16,17行目 各モジュールに対してURLをアサインします。各モジュール内で定義したURLには、ここで指定したprefixが付加されたURLでアクセス可能となります。

appa/main_a.py

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

from flask import Module, render_template

appa = Module(__name__)

@appa.route('/')
def app_a_index():
  p = {}
  return render_template('appa/a_index.html', p = {}) 

main.pyでは、Flaskクラスでappを作りますが、ここではModuleクラスでappaをつくっています。ディスパッチ用のデコレータは、ココで作ったモジュールappaのrouteメソッドにURLを登録します。>@appa.route('/hoge')

テンプレートと静的ファイル

各モジュール内に”templates” フォルダを作ってもrender_template() での指定の仕方が分からなかったので、トップのtemplates内に各モジュール名のフォルダを掘ってテンプレートhtmlを作成しています。静的ファイルは、今までどおり。

追加日本語情報

http://a2c.bitbucket.org/flask/patterns/packages.html
完全に忘れていた。

リアルタイムWeb 勉強会に参加した

Greeさんの最高です!会場ありがとうございました。

node.jsのハカソンをやって、リアルタイムWeb関係のLTをやるという進行の会でした。node.jsはwktkですが、手が出せませんでした。
そのかわりFlaskとみんな大好きなmeinheldを使ったWebSocketアプリ作ってみました。

リアルタイムで出来たら嬉しいと思うことにサーバーの状態監視があります。sshが使えない環境でも、ブラウザ一つでtopがリアルタイムに更新されたら嬉しいなぁと思っていたのでこれを気にやってみたら意外と簡単に出来ました。

ファイル構成

ws_test/.

-- __init__.py
-- monitor.py
-- templates
-- websocket.html

`-- websocket_top.py

各ソース

websocket_top.py

from flask import Flask, render_template, request
from meinheld import server, middleware
from multiprocessing import Process
from subprocess import call

import commands, time

SECRET_KEY = 'development key'
DEBUG=True

app = Flask(__name__)
app.config.from_object(__name__)

participants = set()

@app.route('/')
def index():
  return render_template('websocket.html')

@app.route('/top')
def top():
  ws = request.environ.get('wsgi.websocket')
  participants.add(ws)
  try:
    while True:
      print "ws.wait()..."
      m = ws.wait()
      print "recv msg %s" % m
      if m is None:
        break
      for p in participants:
        print "send message %s" % m
        if m.isdigit():
          mp = Process(target=send_top, args=(p, int(m)))
          mp.start()
  finally:
    participants.remove(ws)
  return ""

def send_top(obj,  count=5):
  for i in range(count):
    str_top = ["%s"%x for x in commands.getoutput("top -b -n1").split('\n')[:10]]
    res_str = "<pre>" + '\n'.join(str_top) + '</pre>'
    obj.send(res_str)
        
if __name__ == "__main__":
  server.listen(("0.0.0.0", 5000))
  server.run(middleware.WebSocketMiddleware(app))


websocket.html

<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
window.onload = function() {
  var data = {};
  var s = new WebSocket("ws://main.atusi.me:5000/top");
  s.onopen = function() {
    s.send('New participant joined');
  };
  s.onmessage = function(e) {
    $("#top-stat").html("<div>" + e.data + "</div>");
  };
  s.onclose = function(e) {
    $("#top-stat").html("<div>" + 'close connection' + "</div>");
  }
  $('#connect').submit(function (evt) {
      var line = $('#connect [type=text]').val()
      $('#connect [type=text]').val(line)
      s.send(line);
      return false;
      });

  $('#disconnect').submit(function (evt) {
      s.onclose();
      return false;
      });
};
</script>

<style>
  #chat {
    font:12px "DejaVu Sans Mono","Bitstream Vera Sans Mono",monospace;
  }
</style>
</head>

<body>
  <h3>top</h3>
  <form id="connect">
    <input type="text" value=3 />
    <input type="submit" value='open' />
  </form>

  <form id="disconnect">
    <input type="submit" value='close' />
  </form>

  <div id="top-stat" style="width: 60em; height: 20em; overflow:auto;">
  </div>
</body>
</html>

はまりどこ

Pythonからtopの内容が抜けない

callでtop呼んでしまうと、標準出力されてしまうし返ってこないので困ります。
topに関しては、top -b -n1 オプション付けることで一回だけ実行して返ってくるようになったので解決>thx i386
callはもともと欲しい機能がついてないぽいので(2.7からそういう事が出来るようになってる)、commands.getoutput を使うことで標準出力部分を取得することが出来ました。

複数回topすると、他の閲覧者の人がブロックされてしまう

一回だけで実行すると、複数の閲覧者がいた場合にそれぞれのブラウザで交互に更新が行われて、それポイ動作をするんだけど、複数回のtopを実行すると一人に対して表示が更新され指定の回数が終了するまで、その他の人のブラウザは一切更新されません。これだと同時に複数ヶ所からのモニターが出来ない為NG。
どのように解決していいか未だベストがわかりませんが、今回は、wsオブジェクトをそのまま引数で渡す形でmultiprocessingで別プロセス化してブロッキングを回避しました。フォームに繰り返し回数を数値入力するとその回数だけtopを繰り返します。
もっと正しいやり方があるとおもうんだけど思いつかないです、プリーズヘルプミィですぉ
JSの部分なんだけど、WebSocketのcloseの仕方が分からない、どうすればいいんだろ?

リアルタイムについての妄想

”リアルタイムなんとか”と言うのを最近よく見かけるようになったけど、リアルタイムの定義ってなんだろう?とちょっと考えさせられる。低遅延とか、固定遅延とか、そういう意味で”リアルタイム”という言葉がWeb界隈で使われている気がする。現実時間はNot離散なので、PCで扱おうとすると何がしか離散させなくてはいけないとなると、その分解能をどれくらいにするのかに興味が湧く?映画だったら24F/secだし、テレビだったら60i/secだし、音楽ファイルだったら44.1KHzだし、CPUとかだと2.5GHzとか?多分人間の視覚的には250Update/Sec以上は認知不能だと思うのでそれくらいの分解能を基準してみるのはどうなんだろう?でも実際のところ、 画面のデータはリアルタイムで更新(250Update/Sec)しているつもりでも、液晶モニターがそもそも60Hzだとあまり意味がないし、ネットワークの行って来いで25msもかかってたら40回/secなわけ(非同期にすればなんぼでも行けるか?)で250っていう数字はあまり現実的じゃないのかな?最近の地デジテレビで4倍速とかは240F/sec相当なのでこれのちょっと上くらいの数字でPCリアルタイムの基準数字を作ったほうがいいかと思うんだけど、どうなんだろう?

とか、妄想させられた勉強会でした。

早くだれかタキオンを発見してください。