#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const std::string keys = "{ h help | | Print this help message }" "{ detector | | Path to compiled .blob face detector model }" "{ duration | 100 | Number of frames to pull from camera and run inference on }"; namespace custom { G_API_NET(FaceDetector, , "sample.custom.face-detector"); using GDetections = cv::GArray; using GSize = cv::GOpaque; using GPrims = cv::GArray; G_API_OP(BBoxes, , "sample.custom.b-boxes") { static cv::GArrayDesc outMeta(const cv::GArrayDesc &) { return cv::empty_array_desc(); } }; GAPI_OCV_KERNEL(OCVBBoxes, BBoxes) { // This kernel converts the rectangles into G-API's // rendering primitives static void run(const std::vector &in_face_rcs, std::vector &out_prims) { out_prims.clear(); const auto cvt = [](const cv::Rect &rc, const cv::Scalar &clr) { return cv::gapi::wip::draw::Rect(rc, clr, 2); }; for (auto &&rc : in_face_rcs) { out_prims.emplace_back(cvt(rc, CV_RGB(0,255,0))); // green } } }; } // namespace custom int main(int argc, char *argv[]) { cv::CommandLineParser cmd(argc, argv, keys); if (cmd.has("help")) { cmd.printMessage(); return 0; } const auto det_name = cmd.get("detector"); const auto duration = cmd.get("duration"); if (det_name.empty()) { std::cerr << "FATAL: path to detection model is not provided for the sample." << "Please specify it with --detector options." << std::endl; return 1; } // Prepare G-API kernels and networks packages: auto detector = cv::gapi::oak::Params(det_name); auto networks = cv::gapi::networks(detector); auto kernels = cv::gapi::combine( cv::gapi::kernels(), cv::gapi::oak::kernels()); auto args = cv::compile_args(kernels, networks); // Initialize graph structure cv::GFrame in; cv::GFrame copy = cv::gapi::oak::copy(in); // NV12 transfered to host + passthrough copy for infer cv::GOpaque sz = cv::gapi::streaming::size(copy); // infer is not affected by the actual copy here cv::GMat blob = cv::gapi::infer(copy); // FIXME: OAK infer detects faces slightly out of frame bounds cv::GArray rcs = cv::gapi::parseSSD(blob, sz, 0.5f, true, false); auto rendered = cv::gapi::wip::draw::renderFrame(copy, custom::BBoxes::on(rcs)); // on-the-fly conversion NV12->BGR cv::GMat out = cv::gapi::streaming::BGR(rendered); auto pipeline = cv::GComputation(cv::GIn(in), cv::GOut(out, rcs)) .compileStreaming(std::move(args)); // Graph execution pipeline.setSource(cv::gapi::wip::make_src()); pipeline.start(); cv::Mat out_mat; std::vector out_dets; int frames = 0; while (pipeline.pull(cv::gout(out_mat, out_dets))) { std::string name = "oak_infer_frame_" + std::to_string(frames) + ".png"; cv::imwrite(name, out_mat); if (!out_dets.empty()) { std::cout << "Got " << out_dets.size() << " detections on frame #" << frames << std::endl; } ++frames; if (frames == duration) { pipeline.stop(); break; } } std::cout << "Pipeline finished. Processed " << frames << " frames" << std::endl; return 0; }