Beagle Bone Blackの環境が整ったので次はカメラが使えるか試してみた. そしてOpenCVで顔検出することを目指す.

今回使うカメラはこれ. 2014-10-16 21.52.50

大須のジャンク屋で売っていたもので,正体不明だったがとりあえず3個購入.1個800円.かなり古そうなので少なくともUVCには対応していないだろう. 何者か調べるためにUSBの情報を見てみる.

lsusb
ID 046d:08d9 Logitech, Inc. QuickCam IM/Connect

どうやらこの製品らしいhttps://support.logitech.com/en_us/product/222

どんな画像が取れるのか試しに見てみる.

sudo apt-get install xawtv
xawtv -c /dev/video0

Screenshot from 2014-10-16 22^%11^%05

ロボットの目として使うには十分な画質はありそうだ. ちなみにレンズ周りにあるリング部分でピント調節することができる.ジャンクだったためリングの動きが渋くて,なかなかピント調節の方法を見つけられなかった.

さて次はBBBの上でOpenCVをビルドして使えるようにする. OpenCV2.4.9のセットアップは大方このサイトhttp://www.kkaneko.com/rinkou/opencv/opencvinstalllinux.html の通りに進めた(執筆現在は最新の2.4.10のものに置き換わっている).

ただし,ダウンロードに時間がかかったり,エラーが出たりしたのでcmakeの部分は以下に変えた

cmake -DCMAKE_BUILD_TYPE=RELEASE -DWITH_TBB=ON -DWITH_GTK=ON -DWITH_OPENGL=ON -DWITH_OPENCL=OFF -DWITH_CUDA=OFF -DWITH_UNICAP=ON -DWITH_V4L=ON -DWITH_XINE=ON  .

それでもBBB上では一連のセットアップに16時間程度かかった.もうどれだけ時間が掛かろうと寝るだけだったのでサンプル等一緒に入れておけばよかった. サンプル画像が無いと不便なので母艦のOpenCV環境からコピーした.トホホ.

sudo scp -P 22 /usr/local/share/OpenCV/samples/c/*.png ubuntu@192.168.7.2:/usr/local/share/OpenCV/samples/c

まずOpenCVからカメラが読めるか試してみる.以下のコードを使った.

// cam.cpp
#include <cv.h>
#include <highgui.h>
#include <ctype.h>

#ifndef CV_WINDOW_FREERATIO
#define CV_WINDOW_FREERATIO 0
#endif

int main( int argc, char **argv )
{
	cv::VideoCapture cap1(0);

	cap1.set( CV_CAP_PROP_FRAME_WIDTH, 320 );
	cap1.set( CV_CAP_PROP_FRAME_HEIGHT, 240 );

	cv::namedWindow("camera1", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);
	while ( 1 ) {
		cv::Mat img1;
		cap1 >> img1 ;
		cv::imshow("camera1", img1 );
		char ch = cv::waitKey(100);
		if ( ch == 27 ) break;
	}
	return 0;
}

コンパイルする.

g++ -o cam.out cam.cpp -I/usr/local/include/opencv2 -I/usr/local/include/opencv -L/usr/local/lib -lopencv_core -lopencv_highgui

これでカメラを読めることが確認できた.ただ残念ながらこのカメラを複数台同時に読み取ることはできなかった.

次は顔検出をしてみる.こちらのサイトhttp://unasuke.com/howto/2013/face-recognition-in-opencv/のコードをほぼそのまま使わせていただいた.学習済みのデータとしてhaarcascade_frontalface_alt2.xmlを使った.

#include <cv.h>
#include <highgui.h>
#include <ctype.h>

#ifndef CV_WINDOW_FREERATIO
#define CV_WINDOW_FREERATIO 0
#endif

int main( int argc, char **argv )
{
	cv::VideoCapture cap1(0);

	cap1.set( CV_CAP_PROP_FRAME_WIDTH, 320 );
	cap1.set( CV_CAP_PROP_FRAME_HEIGHT, 240 );
	cv::namedWindow("camera1", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);
	std::string cascadeName = "/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_alt2.xml";
	cv::CascadeClassifier cascade;
	if(!cascade.load(cascadeName)) return -1;
	double scale = 4.0;
	cv::Mat img, gray;

	while ( 1 ) {
		cap1 >> img;

		//Trans to glay scale
		cv::cvtColor(img, gray, CV_BGR2GRAY);
		cv::Mat smallImg(cv::saturate_cast<int>(img.rows/scale), cv::saturate_cast<int>(img.cols/scale), CV_8UC1);

		// 処理時間短縮のために画像を縮小
		cv::resize(gray, smallImg, smallImg.size(), 0, 0, cv::INTER_LINEAR);
		cv::equalizeHist( smallImg, smallImg);

		std::vector<cv::Rect> faces;
		/// マルチスケール(顔)探索xo
		// 画像,出力矩形,縮小スケール,最低矩形数,(フラグ),最小矩形

		cascade.detectMultiScale(smallImg, faces, 1.1, 2, CV_HAAR_SCALE_IMAGE, cv::Size(30, 30));

		// 結果の描画
		std::vector<cv::Rect>::const_iterator r = faces.begin();
		for(; r != faces.end(); ++r) {
			cv::Point center;
			int radius;
			center.x = cv::saturate_cast<int>((r->x + r->width*0.5)*scale);
			center.y = cv::saturate_cast<int>((r->y + r->height*0.5)*scale);
			radius = cv::saturate_cast<int>((r->width + r->height)*0.25*scale);
			cv::circle( img, center, radius, cv::Scalar(80,80,255), 3, 8, 0 );
		}
		cv::imshow("camera1", img );
		char ch = cv::waitKey(30);
		if ( ch == 27 ) break;
	}
	return 0;
}

コンパイルする.

g++ -o facedetect.out facedetect.cpp -I/usr/local/include/opencv2 -I/usr/local/include/opencv -L/usr/local/lib -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_objdetect

こんな感じで顔を検出して赤い円を描画できた. kao

メガネをかけていると蛍光灯の光の加減で認識が難しかった.メガネかけてる人の学習データも入れないといけない. とりあえずメガネを取れば顔検出できた.

おわり