2014-06-05

Raspberry Piにつないだカメラの画像をfluentdに送ってみる

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Raspberry Piにつないだカメラで撮影した静止画のデータを別のマシンのfluentdに送って、保存してもらうことを試して見ました。


Raspberry Piでカメラ画像を処理するのにはOpenCVを使ってみます。

Raspberry PiでOpenCVを使えるようにする方法は、以下を参照してください。
Raspberry PiでOpenCVをrubyで使ってみた

そして、画像でデータを受け取るfluentdの方の設定については以下を参照してください。
fluentdに画像データを送ってみる


ここでは、Raspberry Piでカメラデータを取得して、fluentdにデータを送る部分を紹介します。

Raspberry Piでfluentdにデータを送れるようにするためにfluent-loggerをインストールします。
sudo gem install fluent-logger

カメラ画像をfluentdに送るプログラムは以下のような感じです。

vi send_image.rb
require 'opencv'
require 'fluent-logger'
require 'base64'

log = Fluent::Logger::FluentLogger.new(nil, :host=>'fluentdが起動しているホスト', :port=>24224)
cap = OpenCV::CvCapture.open

loop do
  #撮影間隔を以下のsleepで調整
  sleep 1

  img = cap.query
  #おくる画像のサイズを指定する場合は、以下のコメントをとる
  #img = img.resize OpenCV::CvSize.new 640, 360
  mat = img.to_CvMat
  data = Base64.encode64(mat.encode('.jpg').pack('C*'))

  unless log.post("exec_test.image", {"sender"=>"raspberry pi","image_data"=>data})
    p log.last_error # You can get last error object via last_error method
  end
end


これで
ruby send_image.rb
とすれば画像データをfluentdに送って、fluentd側では指定したディレクトリに画像を溜め込んでいきます。


そして、ため込んだ静止画データを利用して動画を作ってみたいと思ったわけです。
タイムラプスとかいうやつです。

ここからはRaspberry Pi側ではなく、fluentdが動いている側での作業になります。

静止画を動画に変換するためにffmpegを利用してみます。

なので、まずはインストールです。
yum --enablerepo=rpmforge install ffmpeg

ffmpegで静止画を動画に変換するには、ファイルに連番がついていないといけない模様です。
今回は、データを受け取った時間でファイル名が決まるようにしていたので、そのままでは使えません。

なので以下でファイル名を連番に変換します。
c=1 ; for i in *.jpg ; do ln $i img`printf %06d $c`.JPG ; c=$((c+1)) ; done

ファイル名を連番にできたら、以下を実行して動画に変換します。
ffmpeg -r 15 -i img%06d.JPG  out.avi


ネットワークさえつながればRaspberry Piのディスク容量を気にすることなく、いっぱい撮影をすることができるようになります。

データの送る方法としてfluentdを利用するのが最適なのか?という疑問はありますけどね。


2014-06-04

fluentdに画像データを送ってみる

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
fluentdの使い方として適切でないような気がするのですが、画像データをfluentdに送って処理してもらうことを試しました。

ちなみにfluentdのインストール方法は、以下を参照してください。
centosにfluentdをインストールしてrubyでデータを投げてみた


imageデータを受け取って、指定したフォルダに保存してくれるpluginもある気配です。
https://github.com/bash0C7/fluent-plugin-imagefile

でも今回はデータを受け取ったら、プログラムを起動させて、そのプログラムに処理させる設定をしてみようと思います。


まずは試しに簡単なプログラムを起動させてみます。

起動させるプログラムやデータを保存する場所を準備します。
mkdir -p /var/td-agent/bin
mkdir -p /var/td-agent/tmp
mkdir -p /var/td-agent/data/test

fluentdから起動されるプログラムを作ります。
fluentdはプログラムを呼び出す際に、受け取ったデータをファイルにしてプログラムに渡すようです。

vi /var/td-agent/bin/out_test.rb
open("/var/td-agent/data/test/hoge.txt", "w") {|f|
  f.write ARGV
  f.write File.new(ARGV[0]).read
}

所有者情報を変更しておきます。
chown -R td-agent:td-agent /var/td-agent

fluetndには、以下のような設定を追加します。
vi /etc/td-agent/td-agent.conf
---------------------------
<match exec_test.**>
  type exec
  command /usr/local/bin/ruby /var/td-agent/bin/out_test.rb
  time_key got_at
  format json
  flush_interval 5s
  buffer_path /var/td-agent/tmp/buf
</match>
---------------------------

プログラムを実行させるにはtypeをexecにします。
実行させるプログラムはcommandで指定して、データを受け渡す際に受け取った時間をtime_kleyで指定したkeyに設定することができるようです。
そして、受け渡すファイルの形式をformatで選択します。jsonを選択した場合は、1行が一つのjsonデータになるようで、一つのファイルが一つのjsonになるわけではないようです。
flush_intervalで実行するプログラムの間隔を指定することになり、buffer_pathにプログラムに受け渡すファイルが一時的に格納されるようです。

設定後に設定を反映させます。
/etc/init.d/td-agent reload

テストで以下を実行してみます。
curl -X POST -d 'json={"json":"message"}' http://localhost:8888/exec_test.test

するとjsonデータが
/var/td-agent/data/test/hoge.txt
に保存されていることを確認できます。


ここで画像を受け取って保存できるようにプログラムを修正してみます。
vi /var/td-agent/bin/out_test.rb
require 'json'
require 'base64'

inf = open(ARGV[0])
inf.each do |l|
  data = JSON.parse l

  file_name=data['got_at'] + ".jpg"
  File.open("/var/td-agent/data/test/#{file_name}", 'wb') {|f|
    f.write Base64.decode64(data["image_data"])
  }
end


画像データを投げるプログラムは以下のような感じです。
vi image_send.rb
require 'fluent-logger'
require 'base64'

filename='aaa.jpg'
image=File.new(filename).read
image_data=Base64.encode64(image)
log = Fluent::Logger::FluentLogger.new(nil, :host=>'localhost', :port=>24224)
unless log.post("exec_test.image", {"file_name"=>filename,"image_data"=>image_data})
  p log.last_error # You can get last error object via last_error method
end

aaa.jpgを用意してimage_send.rbを実行すると
/var/td-agent/data/test/xxxxxxx.jp
としてaaa.jpgと同じものが保存されます。

2014-06-03

centosにfluentdをインストールしてrubyでデータを投げてみた

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
ログをいい感じにいろいろ何かをしてくれる
fluentd
の話題をよく聞くような気がしたのでcentosにインストールしてみました。


まずは準備です。

vi /etc/security/limits.conf
に以下を追加します。
---------------
root soft nofile 65536
root hard nofile 65536
* soft nofile 65536
* hard nofile 65536
---------------

追加したら
reboot

再起動後
ulimit -n
として
65535
となることを確認します。

そして
vi /etc/sysctl.conf
以下を追加します。
---------------
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 10240    65535
---------------

そして設定を反映させます。
sysctl -w


fluentdをインストールします。
インストールの仕方にはいくつかあるのですが、以下の手段でインストールします。

curl -L http://toolbelt.treasuredata.com/sh/install-redhat.sh | sh

これでfluentdがtd-agentという名前でインストールされます。

fluentdの起動は以下のとおりです。
/etc/init.d/td-agent start


設定ファイルは以下になります。
/etc/td-agent/td-agent.conf

インストールされて正しく動くことを確認です。
curl -X POST -d 'json={"json":"message"}' http://localhost:8888/debug.test

以下を実行して上記のjsonの内容が出力されていることを確認します。
cat /var/log/td-agent/td-agent.log


fluentdがインストールできたので、rubyからデータを投げて見ます。

rubyからデータを投げるためにfluent-loggerを利用してみます。
他にもいくつかgemがありそうな気配ではあります。

まずはインストール
gem install fluent-logger

データを投げるプログラムを作ります。
vi test.rb
require 'fluent-logger'

log = Fluent::Logger::FluentLogger.new(nil, :host=>'localhost', :port=>24224)
unless log.post("debug.aaaa", {"agent"=>"foo","bbbb"=>"cccc"})
  p log.last_error # You can get last error object via last_error method
end

ruby test.rb
を実行して、以下に投げたjsonデータが出てきていることを確認します。
cat /var/log/td-agent/td-agent.log