アーカイブ
画像のだいたいの色を求める
カメラの入力画像から平均的な色を求めてRGBで出力する。
頻出色じゃなくて、全体的に赤っぽかったらr:200,g:50,b:50みたいなかんじで出す。赤っぽいとか青っぽいとかを求めたい。
数えて平均出そうかと思ったけどOpenCVで1×1ピクセルの画像にリサイズしてしまうのが速い&早いことに気づいた。
一応カメラのプレビューと、その色で塗りつぶしたウィンドウを出してみている。1ピクセルの画像はcvShowImageできないので、表示のために2ピクセルの画像を作っている
image1px.cpp
#include <stdio.h>
#include <cv.h>
#include <highgui.h>
int main(int argc, char** argv) {
CvCapture *capture;
IplImage *img, *img1px, *imgR, *imgG, *imgB, *img2px;
img1px = cvCreateImage(cvSize(1,1), IPL_DEPTH_8U, 3);
imgR = cvCreateImage(cvSize(1,1), IPL_DEPTH_8U, 1);
imgG = cvCreateImage(cvSize(1,1), IPL_DEPTH_8U, 1);
imgB = cvCreateImage(cvSize(1,1), IPL_DEPTH_8U, 1);
img2px = cvCreateImage(cvSize(2,2), IPL_DEPTH_8U, 3);
char *winNameCapture = "Capture";
char *winName1px = "Image1px";
cvNamedWindow(winNameCapture, CV_WINDOW_AUTOSIZE);
cvNamedWindow(winName1px, CV_WINDOW_AUTOSIZE);
capture = cvCreateCameraCapture(0);
while (1) {
img = cvQueryFrame(capture);
cvShowImage(winNameCapture, img);
cvResize(img, img1px, CV_INTER_CUBIC);
cvSplit(img1px, imgB, imgG, imgR, NULL);
printf("r:%d, g:%d, b:%d\n",
(unsigned char)imgR->imageDataOrigin[0],
(unsigned char)imgG->imageDataOrigin[0],
(unsigned char)imgB->imageDataOrigin[0]);
cvResize(img1px, img2px, CV_INTER_CUBIC);
cvShowImage(winName1px, img2px);
if (cvWaitKey(33) == 'q') break;
}
cvReleaseCapture(&capture);
cvDestroyWindow(winNameCapture);
cvDestroyWindow(winName1px);
return 0;
}
Makefile
SRC = image1px.cpp
DST = image1px
prefix=/opt/local
CV_INCPATH=$(prefix)/include/opencv
CV_LIBPATH=$(prefix)/lib
CV_LIBS= -lcv -lcvaux -lcxcore -lhighgui
all:
g++ -O $(SRC) -o $(DST) -I$(CV_INCPATH) -L. -L$(CV_LIBPATH) $(CV_LIBS)
赤いポストイットをカメラの前に

出力
赤いことがわかる
r:186, g:61, b:61
r:186, g:61, b:61
r:191, g:63, b:61
r:198, g:67, b:63
r:200, g:69, b:63

白い。
r:149, g:146, b:147
r:159, g:155, b:156
r:169, g:156, b:159
r:169, g:160, b:161
r:169, g:159, b:161
r:169, g:159, b:161

赤黒いのかな?
r:126, g:92, b:124
r:126, g:92, b:124
r:126, g:92, b:124
r:126, g:92, b:124
r:126, g:92, b:124
r:126, g:92, b:124
r:125, g:92, b:124

白い
r:126, g:119, b:126
r:126, g:119, b:126
r:126, g:119, b:125
r:125, g:118, b:125
r:125, g:118, b:125
r:125, g:118, b:125
r:125, g:118, b:125
opencv-haartrainingの進行状況をtwitterに流すbot
OpenCVをソースからビルドするとhaarlike分類器(顔認識などに使われているやつ)の学習ツールが手に入るんだけど、たくさんのマシンでたくさん学習させているとそれぞれの進行状況をチェックするのが面倒になってくる。
でも、入力した画像ファイルが壊れていると学習が強制終了してしまったり、データがばらつきすぎてて収束しなくてあきらめて終了されたりするので、プロセスが死んでいたらパラメータを直してすぐやり直しをさせたい。学習中は予断を許さない状況が続く。
なので、進行状況を監視してtwitterアカウントshokai_logにpostするbotを作った。
5分間隔でopencv-haartrainingの作業ディレクトリとプロセスが生きているかをチェックする。
学習stageが進む毎に適当に通知し、プロセスが強制終了していた場合は激しくreplyしてくれる。これで安心して寝れる。OpenCV1.0/2.0両方対応。
一見何言ってるのかわかりにくいpostもあるが、「ドドドド」だったらstage4が終わったという意味。

辞書はコード内にある。
第2引数にopencv-haartrainingの-dataオプションで渡した「結果の書き出し先ディレクトリ名」を指定する。第3引数は無しでもいいが、twitter投稿の末尾にメモを付けられる。複数のマシンで実行していてどれの進行状況かわからなくなる時は、マシンの名前を入れておけばいい。
ruby tweet-haartraining.rb /Users/sho/path/to/training/dir/ "Macbook黒"
tweet-haartraining.rb
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require 'rubygems'
require 'twitter'
# setting
USER = 'your-account'
PASS = 'your-password'
INTERVAL = 300 # sleep sec
YOU = 'shokai' # 時々replyしてくる nilでreplyなし
NOPOST = false # debug用
def post(message)
return if !message
message = "@#{YOU} #{message}" if rand(3)<1 if !(message =~ /@#{YOU}/) && rand(2)<1
puts message + "\t" + Time.now.to_s
return if NOPOST
httpAuth = Twitter::HTTPAuth.new(USER, PASS)
tw = Twitter::Base.new(httpAuth)
tw.update(message)
end
if ARGV.size < 1
puts '結果が出力されるディレクトリへのパスが必要です。メモも付けられます(オプション)'
puts 'e.g. ruby tweet-haartraining.rb /path/to/haar/training/dir/ "研究室の学習用パソコン"'
exit 1
end
puts path = ARGV.shift
memo = ARGV.shift || ""
dir_path = path
if path =~ /\/$/
dir_path = path
xml_path = path[0...path.size-1]+'.xml'
else
dir_path = path+'/'
xml_path = path+'.xml'
end
if stage_p = Dir.glob(dir_path+'*').delete_if{|i| File::ftype(i) != 'directory'}.map{|i| i.split(/\//).last.to_i}.max
post "ステージ#{stage_p}から開始" + " " + memo
else
messages = ["開始。",
"はじめ",
"起床",
"おきた",
"start",
"スタートしました",
"hello world",
"hello work",
"はじめますわっ",
"スタンバイレディ セタップ"]
post messages[rand(messages.size)] + " " + memo
end
while true do
sleep INTERVAL
stage = Dir.glob(dir_path+'*').delete_if{|i| File::ftype(i) != 'directory'}.map{|i| i.split(/\//).last.to_i}.max
if File.exists? xml_path
messages = ["全行程完了(ステージ#{stage})。お疲れ様でした。",
"全部オワタ(#{stage})",
"修了しました",
"寝る。#{stage}時に起きる。",
"終わったので、#{stage}時に帰ります",
"全段階完了しました。データを回収し、電源を落としてください(#{xml_path.split(/\//).last})",
"全ステージ完了しました(#{xml_path.split(/\//).last})",
"ⓢⓤⓨⓐⓡⓘ"]
post "@#{YOU} " + messages[rand(messages.size)] + " " + memo
exit 0
end
if nil == `ps aux | grep opencv-haartraining`.split(/[\r\n]/).delete_if{|m|m=~/grep opencv-haartraining/}.first
messages = ["#{stage}段階目まで来たけど異常終了したかも",
"落ちてる",
"ERROR! haartraining is not working. please restart \(^o^)/",
"異常終了",
"異常です",
"動いてないっぽい・・・",
"死んだかも",
"だめっぽい・・",
"おい、異常終了してるぞ",
"冒 険 の 書 (#{stage}) は 消 え ま し た",
"おお、死んでしまうとは情けない",
"\(^o^)/"*stage,
"ピッコロの気が消えた",
"なん・・だと・・",
"#{stage}面でピチュった"]
post "@#{YOU} " + messages[rand(messages.size)] + " " + memo
sleep INTERVAL*2
next
end
next if stage == stage_p or stage == nil
stage_p = stage
messages = ["#{stage}段階目まで進みました",
"バリバリです(stage#{stage})",
"ばっちりですわっ",
"------ここまで読んだ(#{stage})------",
"がんばってます(#{stage})",
"stage #{stage}",
"ステージ#{stage}なう",
"now finished stage#{stage}.",
"よし!ステージ#{stage}まで終わった!!!",
"うわ"+"あ"*stage,
"ド"*stage,
"ゴ"*stage,
"ゴ"+"ー"*stage,
"もりもり",
"ふむふむなるほど"+"・"*stage,
"頭が"*stage+"おかしくなりそうだ",
"もういや",
"無理"*stage,
"ズザ"+"ー"*stage,
"帰りたい",
"まだ#{stage}段階目だ",
"もうstage#{stage}まで終わった。超はやい",
"もうstage#{stage}まで終わった",
"stage#{stage}まで終わった",
"stage#{stage}まで終わったし",
"ククク・・遂に#{stage}界までまで昇ってきたか・・・",
"ⓢⓤⓨⓐ"*stage]
post messages[rand(messages.size)] + " " + memo
end
cvCalcOpticalFlowBM
オプティカルフローのサンプルコードをちょっといじって、カメラからの入力を表示してみた。
ブロックマッチングによるオプティカルフローを使った。
できたソースコード、Makefile





image.cpp
#include <cv.h>
#include <highgui.h>
#include <cxcore.h>
#include <ctype.h>
#include <stdio.h>
#include <iostream>
#include <boost/format.hpp>
using namespace std;
using namespace boost;
void detect_flow(IplImage *img, IplImage *img_p, IplImage *dst);
int main(int argc, char* argv[]) {
IplImage *img = NULL;
CvCapture *capture = NULL;
capture = cvCreateCameraCapture(0);
//capture = cvCaptureFromAVI("test.avi");
if(capture == NULL){
cerr << "capture device not found!!" << endl;
return -1;
}
CvSize size = cvSize(240, 180);
IplImage *img_resized = cvCreateImage(size, IPL_DEPTH_8U, 3);
IplImage *img_gray = cvCreateImage(size, IPL_DEPTH_8U, 1);
IplImage *img_gray_p = cvCreateImage(size, IPL_DEPTH_8U, 1);
IplImage *img_dst = cvCreateImage(size, IPL_DEPTH_8U, 3);
char winNameCapture[] = "Capture";
cvNamedWindow(winNameCapture, CV_WINDOW_AUTOSIZE);
while (1) {
img = cvQueryFrame(capture);
cvResize(img, img_resized);
cvCvtColor(img_resized, img_gray, CV_BGR2GRAY);
cvCopy(img_resized, img_dst);
detect_flow(img_gray, img_gray_p, img_dst);
cvShowImage(winNameCapture, img_dst);
cvCopy(img_gray, img_gray_p);
if (cvWaitKey(10) == 'q') break;
}
cvReleaseCapture(&capture);
cvDestroyWindow(winNameCapture);
return 0;
}
void detect_flow(IplImage *src_img1, IplImage *src_img2, IplImage *dst_img){
int i, j, dx, dy, rows, cols;
int block_size = 10;
int shift_size = 1;
CvMat *velx, *vely;
CvSize block = cvSize(block_size, block_size);
CvSize shift = cvSize(shift_size, shift_size);
CvSize max_range = cvSize(50, 50);
rows = int(ceil (double (src_img1->height) / block_size));
cols = int(ceil (double (src_img1->width) / block_size));
velx = cvCreateMat(rows, cols, CV_32FC1);
vely = cvCreateMat(rows, cols, CV_32FC1);
cvSetZero(velx);
cvSetZero(vely);
cvCalcOpticalFlowBM(src_img1, src_img2, block, shift, max_range, 0, velx, vely);
for (i = 0; i < velx->width; i++) {
for (j = 0; j < vely->height; j++) {
dx = (int)cvGetReal2D(velx, j, i);
dy = (int)cvGetReal2D(vely, j, i);
cvLine(dst_img, cvPoint(i * block_size, j * block_size),
cvPoint(i * block_size + dx, j * block_size + dy), CV_RGB(255, 0, 0), 1, CV_AA, 0);
}
}
}
Makefile
SRC = image.cpp
DST = image
prefix=/opt/local
INCPATH=$(prefix)/include
LIBPATH=$(prefix)/lib
OPT= -lcv -lcvaux -lcxcore -lhighgui
CC=g++ -O
CFLAGS= -I$(INCPATH)/opencv
LDFLAGS=-L. -L$(LIBPATH)
all:
$(CC) $(SRC) -o $(DST) $(CFLAGS) $(LDFLAGS) $(OPT)
輪郭で表示
アメリカ出張中に、こういう輪郭だけの表示もありかなと思って作ってみたけどまだ実機で試してないからわからないんだった
そのうちやる。

■ダウンロ〜ド
■参考
この2つを合体させた。
■boostでprintf風の文字列フォーマット
boost::formatを使う。
#include <boost/format.hpp>
using namespace std;
using namespace boost;
const int INIT_TIME = 50;
cout << str(format("輝度平均 %d/%d") % i % INIT_TIME) << endl;
■ソースコード
bgsubavg-contour/image.cpp
#include <cv.h>
#include <highgui.h>
#include <ctype.h>
#include <stdio.h>
#include <iostream>
#include <boost/format.hpp>
using namespace std;
using namespace boost;
int main(int argc, char **argv)
{
const int INIT_TIME = 50;
const double BG_RATIO = 0.02; // 背景領域更新レート
const double OBJ_RATIO = 0.005; // 物体領域更新レート
const double Zeta = 10.0;
IplImage *img = NULL;
CvMemStorage* storage_contour = cvCreateMemStorage(0);
CvSeq* find_contour = NULL;
CvCapture *capture = NULL;
capture = cvCreateCameraCapture(0);
//capture = cvCaptureFromAVI("test.avi");
if(capture == NULL){
cerr << "capture device not found!!" << endl;
return -1;
}
img = cvQueryFrame(capture);
CvSize size = cvSize(img->width, img->height);
IplImage *imgAverage = cvCreateImage(size, IPL_DEPTH_32F, 3);
IplImage *imgSgm = cvCreateImage(size, IPL_DEPTH_32F, 3);
IplImage *imgTmp = cvCreateImage(size, IPL_DEPTH_32F, 3);
IplImage *img_lower = cvCreateImage(size, IPL_DEPTH_32F, 3);
IplImage *img_upper = cvCreateImage(size, IPL_DEPTH_32F, 3);
IplImage *imgSilhouette = cvCreateImage(size, IPL_DEPTH_8U, 1);
IplImage *imgSilhouetteInv = cvCreateImage(size, IPL_DEPTH_8U, 1);
IplImage *imgResult = cvCreateImage(size, IPL_DEPTH_8U, 1);
IplImage *imgContour = cvCreateImage(size, IPL_DEPTH_8U, 1);
IplImage *imgSilhouette_p = cvCreateImage(size, IPL_DEPTH_8U, 1);
cout << "背景初期化中..." << endl;
cvSetZero(imgAverage);
for(int i = 0; i < INIT_TIME; i++){
img = cvQueryFrame(capture);
cvAcc(img, imgAverage);
cout << str(format("輝度平均 %d/%d") % i % INIT_TIME) << endl;
}
cvConvertScale(imgAverage, imgAverage, 1.0 / INIT_TIME);
cvSetZero(imgSgm);
for(int i = 0; i < INIT_TIME; i++){
img = cvQueryFrame(capture);
cvConvert(img, imgTmp);
cvSub(imgTmp, imgAverage, imgTmp);
cvPow(imgTmp, imgTmp, 2.0);
cvConvertScale(imgTmp, imgTmp, 2.0);
cvPow(imgTmp, imgTmp, 0.5);
cvAcc(imgTmp, imgSgm);
cout << str(format("輝度振幅 %d/%d") % i % INIT_TIME) << endl;
}
cvConvertScale(imgSgm, imgSgm, 1.0 / INIT_TIME);
cout << "背景初期化完了" << endl;
char winNameCapture[] = "Capture";
char winNameSilhouette[] = "Silhouette";
char winNameContour[] = "Contour";
cvNamedWindow(winNameCapture, CV_WINDOW_AUTOSIZE);
cvNamedWindow(winNameSilhouette, CV_WINDOW_AUTOSIZE);
cvNamedWindow(winNameContour, CV_WINDOW_AUTOSIZE);
bool isStop = false;
while(1){
if(!isStop){
img = cvQueryFrame(capture);
if(img == NULL) break;
cvConvert(img, imgTmp);
// 輝度範囲
cvSub(imgAverage, imgSgm, img_lower);
cvSubS(img_lower, cvScalarAll(Zeta), img_lower);
cvAdd(imgAverage, imgSgm, img_upper);
cvAddS(img_upper, cvScalarAll(Zeta), img_upper);
cvInRange(imgTmp, img_lower, img_upper, imgSilhouette);
// 輝度振幅
cvSub(imgTmp, imgAverage, imgTmp);
cvPow(imgTmp, imgTmp, 2.0);
cvConvertScale(imgTmp, imgTmp, 2.0);
cvPow(imgTmp, imgTmp, 0.5);
// 背景領域を更新
cvRunningAvg(img, imgAverage, BG_RATIO, imgSilhouette);
cvRunningAvg(imgTmp, imgSgm, BG_RATIO, imgSilhouette);
// 物体領域を更新
cvNot(imgSilhouette, imgSilhouetteInv);
cvRunningAvg(imgTmp, imgSgm, OBJ_RATIO, imgSilhouetteInv);
cvErode(imgSilhouette, imgSilhouette, NULL, 2); // 収縮
cvDilate(imgSilhouette, imgSilhouette, NULL, 4); // 膨張
cvErode(imgSilhouette, imgSilhouette, NULL, 2); // 収縮
cvAnd(imgSilhouette, imgSilhouette_p, imgResult);
// 輪郭抽出、青線で囲む
int contour_num = cvFindContours(cvCloneImage(imgResult), storage_contour, &find_contour,
sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE,
cvPoint(0,0));
CvScalar white = CV_RGB(255,255,255);
cvSetZero(imgContour);
cvDrawContours(imgContour, find_contour, white, white, 2, 2, 8, cvPoint(0,0));
cvNot(imgContour, imgContour);
cvShowImage(winNameCapture, img);
cvShowImage(winNameSilhouette, imgResult);
cvShowImage(winNameContour, imgContour);
cvCopy(imgSilhouette, imgSilhouette_p);
}
int waitKey = cvWaitKey(33);
if(waitKey == 'q') break;
if(waitKey == ' '){
isStop = !isStop;
if(isStop) cout << "stop" << endl;
else cout << "start" << endl;
}
}
cvReleaseCapture(&capture);
cvDestroyWindow(winNameCapture);
cvDestroyWindow(winNameSilhouette);
cvDestroyWindow(winNameContour);
return 0;
}
Makefile
SRC = image.cpp
DST = image
prefix=/opt/local
INCPATH=$(prefix)/include
LIBPATH=$(prefix)/lib
OPT= -lcv -lcvaux -lcxcore -lhighgui
CC=g++ -O
CFLAGS= -I$(INCPATH)/opencv
LDFLAGS=-L. -L$(LIBPATH)
all:
$(CC) $(SRC) -o $(DST) $(CFLAGS) $(LDFLAGS) $(OPT)
OpenCVのhaar-like特徴分類器の確認ツール
3週間ぐらい前に作った、OpenCVのhaarcascadeで認識した部分に円を描画するツールがけっこう便利なので公開する。
Mac OSXおよびUbuntu用でOpenCV1.0とboostが入ってれば動くはず。
OpenCVをダウンロードして付いてくるサンプルにも似た物が入ってるけど、カメラや動画や画像を入力としてGUIで表示するものだった。
俺は大量の静止画を判定して振り分けたりしたかったので、認識した物体の位置とサイズをスクリプト言語で受け取るために標準出力したり、マーキングした後の画像をファイル名を指定して保存したり、プレビューウィンドウを出すか選べるように改造した。
それと今後のためにboostとOpenCVを同時に使ってみたかったというのもある。
パラメータの解析にはboost::program_optionsを使って、画像まわりは全部OpenCVで書いてある。
■ダウンロード
■実行例
ふつうに顔認識。プレビューウィンドウも出す。結果はresult.jpgに保存。
haartest -p -c ~/haarcascades/haarcascade_frontalface_default.xml -p -i ~/Pictures/faces/shokai-umbrella.jpg -o result.jpg

sourceforgeのOpenCVのリポジトリの開発版に、目にマッチするhaarcascadeファイルがあるので持ってきて使った。目に似ている部分がたくさんあるので誤認識した。
haartest -p -c ~/haarcascades/haarcascade_mcs_righteye.xml -p -i ~/Pictures/faces/emushi-2face.jpg -o --nogray

■boost::program_optionsで引数を取る
引数なし、もしくは–helpで実行するとこんなのが出るようにしてある。
cascadeとinputが必要です–input shokai.jpgとか-i shokai.jpgとかで引数を指定。(inputもiも同じとみなすようにヒモ付けできる)
options:
-h [ --help ] ヘルプを表示
-c [ --cascade ] arg haarcascade設定ファイル
-i [ --input ] arg 入力画像ファイル名
-o [ --output ] arg 出力ファイル名
-p [ --preview ] プレビュー表示
-f [ --flip ] 左右反転した画像も判定(青でマーク)
--nogray グレースケール、ヒストグラム均一化せずに判定
左右反転は、左右非対称なものを認識する時に使える。右手のひら判定で左手も検出したい時とか。
詳しくは下記へ
ちなみにprogram_optionsで取った引数をOpenCVに渡すときは
cvLoadImage( argmap["input"].as<string>().c_str() )のような感じでC++のstring型からCのchar配列にcastして渡す。
■スクリプト言語から使う
Rubyのワンライナーからディレクトリ内のJPG画像をまとめて顔認識して結果をresultsディレクトリに保存する例
mkdir results
ruby -e 'Dir.glob("*.jpg").each{|f| `haartest -c ~/haarcascades/haarcascade_frontalface_default.xml -i #{f} -o results/#{f}`}'
■コード
haartest.cpp
#include "cv.h"
#include "highgui.h"
#include <boost/program_options.hpp>
#include <iostream>
using namespace boost;
using namespace std;
void detect_draw(IplImage *img, IplImage *dst, CvHaarClassifierCascade *cascade, CvScalar color, bool isFlip);
int main(int argc, char* argv[]) {
program_options::options_description opts("options");
opts.add_options()
("help,h", "ヘルプを表示")
("cascade,c", program_options::value<string>(), "haarcascade設定ファイル")
("input,i", program_options::value<string>(), "入力画像ファイル名")
("output,o", program_options::value<string>(), "出力ファイル名")
("preview,p", "プレビュー表示")
("flip,f","左右反転した画像も判定(青でマーク)")
("nogray", "グレースケール、ヒストグラム均一化せずに判定");
program_options::variables_map argmap;
program_options::store(parse_command_line(argc, argv, opts), argmap);
program_options::notify(argmap);
if (argmap.count("help") || !argmap.count("cascade") || !argmap.count("input")) {
cerr << "cascadeとinputが必要です" << endl;
cerr << opts << endl;
return 1;
}
CvHaarClassifierCascade *cascade;
cascade = (CvHaarClassifierCascade*)cvLoad(argmap["cascade"].as<string>().c_str(), 0, 0, 0);
if(!cascade){
cerr << "error! Cascade not Found" << endl;
return -1;
}
IplImage *image = cvLoadImage(argmap["input"].as<string>().c_str());
IplImage *image_orig = cvCreateImage(cvSize(image->width, image->height), 8, 3);
cvCopy(image, image_orig);
if(!image){
cerr << "error! Image File not Found" << endl;
return -11;
}
if(!argmap.count("nogray")){
IplImage* gray = cvCreateImage(cvSize(image->width, image->height), 8, 1);
cvCvtColor(image, gray, CV_BGR2GRAY);
cvEqualizeHist(gray, gray);
image = gray;
}
if(argmap.count("preview")||argmap.count("output")){
detect_draw(image, image_orig, cascade, CV_RGB(255, 0, 0), false);
if(argmap.count("flip")){
cvFlip(image, image);
detect_draw(image, image_orig, cascade, CV_RGB(0, 0, 255), true);
}
}
if(argmap.count("output")){
string out_filename = argmap["output"].as<string>();
cout << "save! " << out_filename << endl;
cvSaveImage(out_filename.c_str(), image_orig);
}
if(argmap.count("preview")){
char winName[] = "haarcascade test";
cvNamedWindow(winName, CV_WINDOW_AUTOSIZE);
cvShowImage(winName, image_orig);
while (1) {
if (cvWaitKey(1) == 'q') break;
}
cvDestroyWindow(winName);
}
cvReleaseImage(&image);
cvReleaseImage(&image_orig);
return 0;
}
void detect_draw(IplImage *img, IplImage *dst, CvHaarClassifierCascade *cascade, CvScalar color, bool isFlip = false){
CvMemStorage *storage = 0;
storage = cvCreateMemStorage(0);
CvSeq* faces = cvHaarDetectObjects(img, cascade, storage,
1.1, 2, CV_HAAR_DO_CANNY_PRUNING,
cvSize(30, 30));
for(int i = 0; i < faces->total; i++){
CvRect *rect = (CvRect*)cvGetSeqElem(faces, i);
cout << "x:" << rect->x << ", y:" << rect->y
<< ", width:" << rect->width << ", height:" << rect->height << endl;
CvPoint center;
center.x = rect->x + rect->width/2.0;
center.y = rect->y + rect->height/2.0;
if(isFlip){
center.x = dst->width - center.x;
center.y = dst->height - center.y;
}
int r = (rect->width + rect->height)/4.0;
cvCircle(dst, center, r, color, 2, CV_AA, 0);
}
}
Makefile (Mac用)
# Mac用Makefile
SRC = haartest.cpp
DST = haartest
prefix=/opt/local
INCPATH=$(prefix)/include
LIBPATH=$(prefix)/lib
CV_LIBS= -lcv -lcvaux -lcxcore -lhighgui
BOOST_LIBS= $(LIBPATH)/libboost_program_options-mt.dylib
all:
g++ -O $(SRC) -o $(DST) -I$(INCPATH)/opencv -L. -L$(LIBPATH) $(CV_LIBS) -I$(INCPATH)/boost $(BOOST_LIBS)
Makefile (Linux用)
# Ubuntu用Makefile
SRC = haartest.cpp
DST = haartest
prefix=/usr
INCPATH=$(prefix)/include
LIBPATH=$(prefix)/lib
CV_LIBS= -lcv -lcvaux -lcxcore -lhighgui
BOOST_LIBS= $(LIBPATH)/libboost_program_options-mt.a
all:
g++ -O $(SRC) -o $(DST) -I$(INCPATH)/opencv -L. -L$(LIBPATH) $(CV_LIBS) -I$(INCPATH)/boost $(BOOST_LIBS)

最近のコメント