LoginSignup
10
11

More than 5 years have passed since last update.

OpenCV3で画像キャプチャして顔検出してモザイク処理してから表示×TBBパイプライン並列

Last updated at Posted at 2015-11-14

せっかくのマルチコアマシンなので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
10
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
11