せっかくのマルチコアマシンなのでIntel Threading Building Blocks(TBB)でマルチスレッド並列処理。
画像キャプチャ[逐次] → 顔検出+モザイク処理[フレーム並列] → ウインドウ表示[逐次] のパイプラインを構築。
http://qiita.com/yohhoy/items/505815587d1fbb57cc8b × http://d.hatena.ne.jp/yohhoy/20140514/p1
facemozp.cpp
# include <vector>
# include <string>
# include <iostream>
# include <opencv2/opencv.hpp>
# include <tbb/tbb.h>
struct workset {
cv::CascadeClassifier classifier;
};
std::vector<workset> ws;
const char * const file = "./haarcascade.xml";
cv::Size min_face;
//! initialize
void init(int w, int h, size_t nthread)
{
std::cout << "frame=" << w << 'x' << h << " nthread=" << nthread << std::endl;
ws.resize(nthread);
for (auto& w : ws) {
if (!w.classifier.load(file)) {
std::cout << "fail to load: " << file << std::endl;
std::exit(1);
}
}
const double scale = 0.10;
min_face = cv::Size(w * scale, h * scale);
std::cout << "min_face=" << min_face << std::endl;
}
//! process image frame
cv::Mat process(cv::Mat& frame, workset& w)
{
std::vector<cv::Rect> faces;
w.classifier.detectMultiScale(frame, faces, 1.1, 3, 0, min_face);
for (const auto& r : faces) {
// mosaic filter
const double f = 0.05;
cv::Mat tmp;
cv::resize(frame(r), tmp, {}, f, f);
cv::resize(tmp, frame(r), r.size(), 0, 0, cv::INTER_NEAREST);
// draw area border
cv::rectangle(frame, r.tl(), r.br(), {0,0,0});
}
return frame;
}
int main()
{
const char * const window = "Capture (Press ESC to exit)";
const double scale = 0.75;
const int delay = 32; // [msec]
const size_t nthread = tbb::task_scheduler_init::default_num_threads();
cv::VideoCapture cap(0);
if (!cap.isOpened()) {
std::cerr << "fail to open cv::VideoCapture" << std::endl;
return 2;
}
const double width = cap.get(cv::CAP_PROP_FRAME_WIDTH) * scale;
const double height = cap.get(cv::CAP_PROP_FRAME_HEIGHT) * scale;
cap.set(cv::CAP_PROP_FRAME_WIDTH, width);
cap.set(cv::CAP_PROP_FRAME_HEIGHT, height);
init(width, height, nthread);
cv::namedWindow(window);
std::vector<cv::Mat> frames(nthread);
size_t next_token = 0;
auto filter_chain =
tbb::make_filter<void, size_t>(
tbb::filter::serial_in_order,
[&](tbb::flow_control& fc) -> size_t {
if (cv::waitKey(delay) == '\x1b') {
fc.stop();
return -1;
}
size_t token = (next_token++ % ws.size());
cap >> frames[token];
return token;
}) &
tbb::make_filter<size_t, size_t>(
tbb::filter::parallel,
[&](size_t token) -> size_t {
process(frames[token], ws[token]);
return token;
}) &
tbb::make_filter<size_t, void>(
tbb::filter::serial_in_order,
[&](size_t token) -> void {
cv::imshow(window, frames[token]);
});
tbb::task_scheduler_init sched(nthread);
tbb::parallel_pipeline(nthread, filter_chain);
return 0;
}
$ brew install science/opencv3
...
$ brew install tbb
...
$ clang++ -std=c++14 -W -Wall -O2 -o facemozp facemozp.cpp -I/usr/local/opt/opencv3/include -I/usr/local/opt/tbb/include -L/usr/local/opt/opencv3/lib -L/usr/local/opt/tbb/include -lopencv_core -lopencv_highgui -lopencv_videoio -lopencv_objdetect -lopencv_imgproc -ltbb
$ cp /usr/local/opt/opencv3/share/OpenCV/haarcascades/haarcascade_frontalface_default.xml haarsascade.xml
$ ./facemozp