https://forum.opencv.org/t/simple-example-of-traditional-inference-using-gapi/2872
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/gapi.hpp"
#include "opencv2/gapi/core.hpp"
#include "opencv2/gapi/imgproc.hpp"
#include "opencv2/gapi/infer.hpp"
#include "opencv2/gapi/infer/ie.hpp"
#include "opencv2/gapi/cpu/gcpukernel.hpp"
#include "opencv2/gapi/streaming/cap.hpp"
// 命令行参数
const std::string about = "This is an OpenCV-based version of Security Barrier Camera example";
const std::string keys =
"{ h help | | print this help message }"
"{ input | | Path to an input img file }"
"{ fdm | | IE face detection model IR }"
"{ fdw | | IE face detection model weights }"
"{ fdd | | IE face detection device }";
namespace custom {
//! [G_API_NET]
// 面部检测器:接受一个Mat,返回另一个Mat
G_API_NET(Faces, <cv::GMat(cv::GMat)>, "face-detector");
// SSD后处理函数 - 这不是网络而是内核。
// 内核体单独声明,这只是一个接口。
// 此操作接受两个Mats(检测结果和源图像),
// 并返回ROI的向量(由默认阈值过滤)。
// 阈值(或要选择的类)可能成为参数,但由于
// 此内核是自定义的,因此没有太大意义。
G_API_OP(PostProc, <cv::GArray<cv::Rect>(cv::GMat, cv::GMat)>, "custom.fd_postproc") {
static cv::GArrayDesc outMeta(const cv::GMatDesc &, const cv::GMatDesc &) {
// 此函数需要由G-API引擎确定
// 给定输入参数时输出格式是什么。
// 由于输出是数组(具有特定类型),
// 因此没有什么可描述的。
return cv::empty_array_desc();
}
};
// 上述内核的基于OpenCV的实现。
GAPI_OCV_KERNEL(OCVPostProc, PostProc) {
static void run(const cv::Mat &in_ssd_result,
const cv::Mat &in_frame,
std::vector<cv::Rect> &out_faces) {
const int MAX_PROPOSALS = 200;
const int OBJECT_SIZE = 7;
const cv::Size upscale = in_frame.size();
const cv::Rect surface({0,0}, upscale);
out_faces.clear();
const float *data = in_ssd_result.ptr<float>();
for (int i = 0; i < MAX_PROPOSALS; i++) {
const float image_id = data[i * OBJECT_SIZE + 0]; // batch id
const float confidence = data[i * OBJECT_SIZE + 2];
const float rc_left = data[i * OBJECT_SIZE + 3];
const float rc_top = data[i * OBJECT_SIZE + 4];
const float rc_right = data[i * OBJECT_SIZE + 5];
const float rc_bottom = data[i * OBJECT_SIZE + 6];
if (image_id < 0.f) { // indicates end of detections
break;
}
if (confidence < 0.5f) { // a hard-coded snapshot
continue;
}
// 将浮点坐标转换为绝对图像
// 帧坐标;剪切源图像边界。
cv::Rect rc;
rc.x = static_cast<int>(rc_left * upscale.width);
rc.y = static_cast<int>(rc_top * upscale.height);
rc.width = static_cast<int>(rc_right * upscale.width) - rc.x;
rc.height = static_cast<int>(rc_bottom * upscale.height) - rc.y;
out_faces.push_back(rc & surface);
}
}
};
//! [Postproc]
} // namespace custom
int main(int argc, char *argv[])
{
cv::CommandLineParser cmd(argc, argv, keys);
cmd.about(about);
if (cmd.has("help")) {
cmd.printMessage();
return 0;
}
const std::string input = cmd.get<std::string>("input");
// 表达我们的处理管道。使用基于lambda的构造函数
// 用于在专用作用域中保留所有临时对象。
//! [GComputation]
cv::GComputation pp([]() {
// 声明一个空的GMat - 管道的开端。
cv::GMat in;
// 在输入帧上运行面部检测。结果是一个单独的GMat,
// 在内部表示1x1x200x7 SSD输出。
// 这是infer的单补丁版本:
// - 推理在整个输入图像上运行;
// - 图像自动转换并调整为网络预期的格式。
cv::GMat detections = cv::gapi::infer<custom::Faces>(in);
// 使用自定义内核解析SSD输出到ROI(矩形)列表。
// 注意:解析SSD可能成为“标准”内核。
cv::GArray<cv::Rect> faces = custom::PostProc::on(detections, in);
// 现在指定计算的边界 - 我们的管道消耗
// 一个图像并产生一个输出。
return cv::GComputation(cv::GIn(in), cv::GOut(faces));
});
//! [GComputation]
// 注意:此时加载尺寸可能非常有用!
// 在我们的计算定义之后,指定它应如何执行。
// 执行由我们用于编译管道(这是不同步骤)的推理后端和内核后端定义。
// 声明FaceDetection网络的IE参数。注意这里custom::Face
// 是我们先前在GAPI_NETWORK()中指定的类型名称。
// cv::gapi::ie::Params<>是通用配置描述,它是
// 针对我们使用的每个特定网络进行专门化。
//
// OpenCV DNN后端将具有其自己的带有设置的参数结构
// 与OpenCV DNN模块相关。其他可能的推理也适用
// 后端...
//! [Param_Cfg]
auto det_net = cv::gapi::ie::Params<custom::Faces> {
cmd.get<std::string>("fdm"), // read cmd args: path to topology IR
cmd.get<std::string>("fdw"), // read cmd args: path to weights
cmd.get<std::string>("fdd"), // read cmd args: device specifier
};
// 形成一个内核包(带有我们的单个基于OpenCV的后处理实现)
// 和一个网络包(持有我们的三个网络)。
auto kernels = cv::gapi::kernels<custom::OCVPostProc>();
auto networks = cv::gapi::networks(det_net);
{ // inference !
// 声明我们将从管道接收的数据对象。
cv::Mat in_frame = cv::imread("input"); // the input !
// 捕获到的帧本身
std::vector<cv::Rect> faces; // 检测到的面部数组
pp.apply(cv::gin(in_frame), cv::gout(faces), cv::compile_args(kernels, networks));
// do something with the face rects
}
return 0;
}
评论