前回はWSGIアプリケーションからOpenCVを利用する例を挙げましたが、今回はクライアントをFlashとHTML5の両方で試してみます。といっても特別なことをする必要はなくて、公開されたURIからリソースを取得すればいいだけです。
、、
ということで既に先が見えて飽きてしまいましたが、簡単なデモと方針だけでも気力を振り絞って書いておきます。後はアプリ層の方々におまかせ;;
OpenCVはPythonバインディングを使いますので、この部分は前回と同じくFlaskを使うことにします。クライアントがFlashの場合はテンプレートエンジン不要で、URIルーティングを行うためのWerkzeugがあれば十分です。ただ、Flaskなら情熱がなくてもたぶん最後まで書ききれるのでオススメ。最後に処理結果ですが、今回はStar Detectorのデモを作ろうと思うので、以下のようなJSON形式で返すことにします。
{ 'width':256, 'height':256, 'keypoints':[ { 'x':107, 'y':83, 'response':-34.138824462890625, 'size':12 }, ... ] }
* Star Detector
Starキーポイント検出器、例では1つのパラメータを公開しています。また、画像の読み込みはI/Oが発生する重い処理ですので memcached にキャッシュしておきます。
[python]
from flask import Flask, abort, jsonify
import cv, numpy as np
import memcache
import os
application = Flask(__name__)
application.debug = True
## memcachedクライアント
mc = memcache.Client([‘localhost:11211’])
## パラメータを1つ公開する場合
@application.route(‘/starkeypoints/
@application.route(‘/starkeypoints/
def getstarkeypoints(image=None, maxsize=45):
path = os.path.join(application.root_path, “/path/to/images/”)
## numpy.ndarrayオブジェクトをmemcachedにキャッシュ
img = mc.get(str(image))
if img == None:
img = cv.imread(path + image + ‘.jpg’, 0)
mc.set(str(image), img, time=60*60*24)
params = (maxsize, 30, 10, 8, 5)
storage = cv.CreateMemStorage()
keypoints = cv.GetStarKeypoints(img, storage, params)
datalist = []
for keypoint in keypoints:
data = {‘x’:keypoint[0][0],
‘y’:keypoint[0][1],
‘size’:keypoint[1],
‘response’:keypoint[2]}
datalist.append(data)
return jsonify(width=img.shape[0],
height=img.shape[1],
keypoints=datalist)
## エラーハンドラ
@application.errorhandler(404)
def notfound(error):
return ‘page not found’, 404
## 以下エラーハンドラが続く..
[/python]
画像のストレージ周りは各々の環境に合った方法で。レスポンスをJSONにするなら flask.jsonify() を使うと楽です。以下、クライアントをFlash(Flex)で作ったデモになります。
Demo: Flash + OpenCV Integration
デモのソースコードを上げておきます。特に難しい所はないはず。
(zip: opencv_client)
次はこれをHTML5 Canvasと併せてみます。Canvasに画像データをdrawImageして上からデータを乗せていくだけ。
[javascript]
// jQuery を利用
$(function() {
var context = document.querySelector(‘#Canvas’).getContext(‘2d’);
context.fillStyle = ‘#ffffff’;
context.strokeStyle = ‘rgb(0, 196, 160)’;
var image = new Image();
image.src = ‘/path/to/image/foo.jpg’;
image.addEventListener(‘load’, function() {
context.drawImage(image, 0, 0);
}, false);
image.addEventListener(‘error’, function() {
alert(‘Cannot Load Image Data’);
}, false);
$(‘#Button’).click(function() {
var url = ‘http://bar.com/cv/starkeypoints/foo’;
// JSONデータを取得
$.getJSON(url, null, function(data) {
plot(context, image, data);
}
});
});
// データをCanvasにプロット
function plot(context, image, data) {
var ctx = context;
var keypoints = data.keypoints;
var len = data.keypoints.length;
var twopi = 2*Math.PI;
ctx.fillRect(0, 0, data.width, data.height);
ctx.drawImage(image, 0, 0);
for(var i=0; i
HTML5版ではパラメータを全て設定できるようにしました。
(Firefox3.6, Safari5.0, Chrome10.0, Opera11.0で動作確認)
Demo: HTML5 Canvas + OpenCV Integration
Star Detectorのアルゴリズムは厳密には知らないのですが、星形範囲(正方形とそれを45度回転したものを重ねた範囲)を積分する際、SURFと同様にIntegral Imageを使うことでO(1)で求めています。
また、ライン(エッジ)上に特徴が出るのを抑えていますが、その辺りはしきい値としてAPIで細かく指定できました。SIFTと比べて精度は劣るようですが、高速なのは魅力的です。Star Detectorって名前も綺麗ですね。
(参考: Common Interfaces of Feature Detectors)
今回のようにWebアプリケーションとして作る場合、サーバ側では「いかにI/Oを発生させないか」ということに集中し、画像処理のロジックはOpenCVを便利に使う感じでいいかと。基本的にはRESTful APIを提供する形で作ると綺麗になります。