ProcessingとRubyの連携
ProcessingはMacとWindowsとLinuxで簡単に動かせて、どの環境でも同じコードで一番楽にUSBカメラを扱えるので愛用してたんだけど
Javaなのでいろいろネットワークまわりの所に俺が慣れてない。
今回はwebcamで撮影して簡単な画像処理をして、httpでform-multipartで画像をpostするかんたんなアプリを作りたかったけど挫折したのでメモしておく。
試したもの
action-coding
http://code.google.com/p/action-coding/
JRubyでprocessingを使う。
processing最新版だとcore.jarの位置が変わったぽい。
aco.rbの54行目で/Application/Processing.app/Contents/Resources/Java/core.jarを参照するように修正したら動いた。
include_class 'processing.video.Capture'
しても見つからないとエラーがでて挫折。
Ruby-Processing
https://github.com/jashkenas/ruby-processing/wiki
CRubyからどういうわけかProcessingが使えるようになる、rp5というコマンドラインツールがインストールされる。
rp5は動くけど、Rubyのライブラリと混在させて書くとダメ。
例えば
require 'open-uri' puts open('http://shokai.org').read
というのを混ぜるとMacだとブラウザでwebページを開いてしまって挫折。
JMFを使う
http://www.oracle.com/technetwork/java/javase/tech/index-jsp-140239.html
JMFでJavaからカメラが使える。という事はJRubyからカメラが使える。
i-sightが認識されなくて挫折。
JMF自体はMac版が無いが、linux版をダウンロードしてきてjmf.jarを /Library/Java/Extensions/ の中にコピーすれば使える。
まだ
apache-mime4jとhttpmimeを使う
たぶん http://shokai.org/blog/archives/5401 の下の方で書いたのを、processingからやればできる。けどなんか・・パッケージ管理システムが無いだけでこんなにやる気が無くなるものとは。
最終的に、
Processingでカメラの画像を定期的にcamera.jpgに保存して
import processing.video.*; Capture camera; void setup(){ size(320, 240); // width, height camera = new Capture(this, width, height, 1); // 1fps } void draw(){ image(camera, 0, 0); saveFrame("camera.jpg"); // capture delay(1000); } void captureEvent(Capture camera){ camera.read(); }
アップロード先に合わせたアップロードライブラリ作って
lib/upload_client.rb
#!/usr/bin/env ruby require 'rubygems' require 'uri' require 'json' require 'httpclient' class UploadError < Exception end module UploadClient def self.upload(filename, url) c = HTTPClient.new res = nil open(filename){|file| postdata = { 'file' => file } res = c.post_content(url, postdata) } begin res = JSON.parse(res) raise UploadError.new res['error'] if res['error'] raise UploadError.new 'file size error' if res['size'].to_i != File.size(filename) return res['url'] if res['url'] rescue => e throw e end raise UploadError.new 'unknown error' end end
これでcamera.jpgの更新日時を定期的に監視してアップロードするようにした・・
uploader.rb
#!/usr/bin/env ruby require 'rubygems' require 'yaml' require 'ArgsParser' require 'FileUtils' require File.dirname(__FILE__)+'/lib/upload_client' $KCODE = 'u' parser = ArgsParser.parser parser.bind(:loop, :l, 'do loop') parser.bind(:file, :f, 'upload file') parser.bind(:interval, :i, 'uplaod interval : default 5 (sec)') parser.bind(:url, :u, 'upload URL') parser.bind(:help, :h, 'show help') first, params = parser.parse(ARGV) params[:interval] = 5 unless params[:interval] unless parser.has_params([:file, :url]) or parser.has_param(:help) puts parser.help exit end p params f = params[:file] unless File.exists? f STDERR.puts 'upload file not exists' exit 1 end last_mtime = 0 loop do if File.mtime(f).to_i != last_mtime last_mtime = File.mtime(f).to_i tmp_file = File.dirname(__FILE__)+'/tmp' FileUtils.cp(f, tmp_file) begin url = UploadClient::upload(tmp_file, params[:url]) rescue => e STDERR.puts e url = nil rescue UploadError => e STDERR.puts e url = nil end puts "[#{last_mtime}] #{url}" if url end break unless params[:loop] sleep params[:interval].to_i end