2014-05-04

Raspberry PiでOpenCVをrubyで使ってみた

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Rapberry PiでUSBカメラを使う際にmotionを使うのを試してみたのですが、さらに画像からいろいろ認識するとかも試してみたいと思ってみました。

ちなみにmotionを利用する方法に関しては、以下をご覧ください。
Raspberry Piに大人の科学マガジンUSB特撮カメラをつないでみた
Raspberry PiにつないだUSBカメラの画像をブラウザから確認するものをrubyで作ってみた

画像から顔やらなんやらを認識するにはOpenCVを利用するわけです。
OpenCVは
sudo apt-get install libopencv-dev
でもインストールできるのですが、インストールされるバージョンは2.3系のものが入るようです。

OpenCVをrubyから使おうと思ったりする場合は、ruby-opencvというものを利用するのですが、こちらは2.4系を必要とします。

今回はrubyで利用するので、apt-getを利用せずにインストールします。

OpenCVは、以下のようにインストールします。

コンパイルに必要になるものを準備します。以下がすべて本当に必要なのかはよくわかりません。
sudo apt-get install build-essential libboost1.46-all-dev libqt4-dev libgtk2.0-dev pkg-config opencl-headers libjpeg-dev libopenjpeg-dev  libjasper-dev libjasper-runtime libpng12-dev libpng++-dev libpng3 libpnglite-dev libtiff-dev libtiff-tools pngtools zlib1g-dev zlib1g-dbg v4l2ucp python autoconf libeigen2-dev cmake openexr gstreamer-plugins-* freeglut3-dev libglui-dev libavc1394-dev libdc1394-22-dev libdc1394-utils libxine-dev libxvidcore-dev libva-dev libssl-dev libv4l-dev libvo-aacenc-dev libvo-amrwbenc-dev libvorbis-dev libvpx-dev

ソースを取得して展開します。今回は2.4.9を持ってきました。
wget http://downloads.sourceforge.net/project/opencvlibrary/opencv-unix/2.4.9/opencv-2.4.9.zip
unzip opencv-2.4.9.zip
cd opencv-2.4.9

コンパイルします。cmakeで指定したパラメータの意味は正直よく分かりません。そしてmakeはすごく時間がかかります。
mkdir build
cd build
cmake -DBUILD_DOCS=ON -DBUILD_EXAMPLES=ON -DCMAKE_BUILD_TYPE=RELEASE -DWITH_TBB=OFF -DWITH_GTK=ON -DWITH_OPENGL=ON -DWITH_QT=OFF -DINSTALL_C_EXAMPLES=ON -DWITH_OPENCL=OFF -DWITH_CUDA=OFF -DWITH_OPENNI=OFF -DWITH_UNICAP=ON -DWITH_V4L=ON -DWITH_XINE=ON  ..
make

インストールします。
sudo make install


そして、ruby-opencvをインストールします。
sudo gem install ruby-opencv


ここまでのものが正しくインストールされたことを確認します。
以下のソースを実行してoutput.jpgにカメラ画像が保存されていればOKです。

require 'opencv'
capture = OpenCV::CvCapture.open
mat = capture.query.to_CvMat
mat.save('output.jpg')
view raw opencv_test.rb hosted with ❤ by GitHub

カメラ画像から顔認識して顔の部分を四角で囲ってみます。カメラ画像はwebsocketを利用してブラウザで確認できるようにします。

rubyでwebsocketを利用するためem-websocketをインストールします。
sudo gem install em-websocket

で以下のソースを実行します。

require 'opencv'
require 'em-websocket'
require 'base64'
EM::run do
cap = OpenCV::CvCapture.open
det_file = "/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_default.xml"
det = OpenCV::CvHaarClassifierCascade::load det_file
connections = Array.new
EM::WebSocket.start(:host => '0.0.0.0', :port => 51234) do |ws|
ws.onopen do |handshake|
puts 'connected'
connections.push(ws)
end
ws.onclose do |handshake|
puts 'closed'
connections.delete(ws)
end
end
EM::defer do
loop do
sleep 0.1
next if connections.size == 0
img = cap.query
img = img.resize OpenCV::CvSize.new 640, 360
det.detect_objects(img).each do |rect|
puts "detect!! : #{rect.top_left}, #{rect.top_right}, #{rect.bottom_left}, #{rect.bottom_right}"
img.rectangle! rect.top_left, rect.bottom_right, :color => OpenCV::CvColor::Red
end
mat = img.to_CvMat
data = Base64.encode64(mat.encode('.jpg').pack('C*'))
connections.each do |con|
con.send(data);
end
end
end
end
実行したらwebsocketで画像を受け取るクライアントを用意します。とりあえず以下のhtmlを用意してブラウザで見れるようにします。
サーバ側においてもいいし、手元のPCにファイルとして用意してもよいのでブラウザから開くと顔認識した画像が見れるはずです。
ブラウザはchromeでしか試していないです。

<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>WebCam</title>
</head>
<body>
<div id="capture-area">
</div>
<script src="http://codeorigin.jquery.com/jquery-2.0.3.min.js"></script>
<script>
$(function() {
var ws = new WebSocket('ws://raspberrypi.local:51234');
ws.onopen = function() {
$('#capture-area').append($('<img>').attr('id', 'capture'));
$('#capture').css("width","800px");
};
ws.onclose = function() {
};
ws.onmessage = function(evt) {
var src = 'data:image/jpeg;base64,' + evt.data;
$('#capture').attr('src', src);
};
});
</script>
</body>
</html>

ちなみに処理はすごく遅いです。体感的には2秒ぐらいで1回画面が切り替わる感じです。


以下がすごく参考になりました。
http://naohiro7.hatenablog.com/entry/2013/04/22/142243
http://shokai.org/blog/archives/8627