2021-08-18 01:11:22 +08:00
# include <algorithm>
# include <fstream>
# include <iostream>
# include <cctype>
2021-10-20 17:43:32 +08:00
# include <tuple>
2021-08-18 01:11:22 +08:00
# include <opencv2/imgproc.hpp>
# include <opencv2/gapi.hpp>
# include <opencv2/gapi/core.hpp>
# include <opencv2/gapi/cpu/gcpukernel.hpp>
# include <opencv2/gapi/infer/ie.hpp>
# include <opencv2/gapi/render.hpp>
2021-08-24 20:41:57 +08:00
# include <opencv2/gapi/streaming/onevpl/source.hpp>
2021-08-18 01:11:22 +08:00
# include <opencv2/highgui.hpp> // CommandLineParser
2021-11-26 19:31:15 +08:00
# include <opencv2/gapi/infer/parsers.hpp>
2021-08-18 01:11:22 +08:00
2021-10-20 17:43:32 +08:00
# ifdef HAVE_INF_ENGINE
# include <inference_engine.hpp> // ParamMap
# ifdef HAVE_DIRECTX
# ifdef HAVE_D3D11
# pragma comment(lib,"d3d11.lib")
// get rid of generate macro max/min/etc from DX side
# define D3D11_NO_HELPERS
# define NOMINMAX
# include <cldnn/cldnn_config.hpp>
# include <d3d11.h>
# pragma comment(lib, "dxgi")
# undef NOMINMAX
# undef D3D11_NO_HELPERS
# endif // HAVE_D3D11
# endif // HAVE_DIRECTX
# endif // HAVE_INF_ENGINE
2021-08-18 01:11:22 +08:00
const std : : string about =
" This is an OpenCV-based version of oneVPLSource decoder example " ;
const std : : string keys =
2021-12-08 15:09:33 +08:00
" { h help | | Print this help message } "
" { input | | Path to the input demultiplexed video file } "
" { output | | Path to the output RAW video file. Use .avi extension } "
" { facem | face-detection-adas-0001.xml | Path to OpenVINO IE face detection model (.xml) } "
" { faced | AUTO | Target device for face detection model (e.g. AUTO, GPU, VPU, ...) } "
" { cfg_params | <prop name>:<value>;<prop name>:<value> | Semicolon separated list of oneVPL mfxVariants which is used for configuring source (see `MFXSetConfigFilterProperty` by https://spec.oneapi.io/versions/latest/elements/oneVPL/source/index.html) } "
2022-04-14 01:06:37 +08:00
" { streaming_queue_capacity | 1 | Streaming executor queue capacity. Calculated automatically if 0 } "
2022-01-24 22:05:26 +08:00
" { frames_pool_size | 0 | OneVPL source applies this parameter as preallocated frames pool size} "
2022-04-01 18:06:47 +08:00
" { vpp_frames_pool_size | 0 | OneVPL source applies this parameter as preallocated frames pool size for VPP preprocessing results} "
" { roi | -1,-1,-1,-1 | Region of interest (ROI) to use for inference. Identified automatically when not set } " ;
2021-08-18 01:11:22 +08:00
namespace {
std : : string get_weights_path ( const std : : string & model_path ) {
const auto EXT_LEN = 4u ;
const auto sz = model_path . size ( ) ;
2022-04-01 18:06:47 +08:00
GAPI_Assert ( sz > EXT_LEN ) ;
2021-08-18 01:11:22 +08:00
auto ext = model_path . substr ( sz - EXT_LEN ) ;
std : : transform ( ext . begin ( ) , ext . end ( ) , ext . begin ( ) , [ ] ( unsigned char c ) {
return static_cast < unsigned char > ( std : : tolower ( c ) ) ;
} ) ;
2022-04-01 18:06:47 +08:00
GAPI_Assert ( ext = = " .xml " ) ;
2021-08-18 01:11:22 +08:00
return model_path . substr ( 0u , sz - EXT_LEN ) + " .bin " ;
}
2021-10-20 17:43:32 +08:00
2022-04-01 18:06:47 +08:00
// TODO: It duplicates infer_single_roi sample
cv : : util : : optional < cv : : Rect > parse_roi ( const std : : string & rc ) {
cv : : Rect rv ;
char delim [ 3 ] ;
std : : stringstream is ( rc ) ;
is > > rv . x > > delim [ 0 ] > > rv . y > > delim [ 1 ] > > rv . width > > delim [ 2 ] > > rv . height ;
if ( is . bad ( ) ) {
return cv : : util : : optional < cv : : Rect > ( ) ; // empty value
}
const auto is_delim = [ ] ( char c ) {
return c = = ' , ' ;
} ;
if ( ! std : : all_of ( std : : begin ( delim ) , std : : end ( delim ) , is_delim ) ) {
return cv : : util : : optional < cv : : Rect > ( ) ; // empty value
}
if ( rv . x < 0 | | rv . y < 0 | | rv . width < = 0 | | rv . height < = 0 ) {
return cv : : util : : optional < cv : : Rect > ( ) ; // empty value
}
return cv : : util : : make_optional ( std : : move ( rv ) ) ;
}
2021-10-20 17:43:32 +08:00
# ifdef HAVE_INF_ENGINE
# ifdef HAVE_DIRECTX
# ifdef HAVE_D3D11
2021-10-22 00:12:03 +08:00
// Since ATL headers might not be available on specific MSVS Build Tools
// we use simple `CComPtr` implementation like as `ComPtrGuard`
// which is not supposed to be the full functional replacement of `CComPtr`
// and it uses as RAII to make sure utilization is correct
template < typename COMNonManageableType >
void release ( COMNonManageableType * ptr ) {
if ( ptr ) {
ptr - > Release ( ) ;
}
}
template < typename COMNonManageableType >
using ComPtrGuard = std : : unique_ptr < COMNonManageableType , decltype ( & release < COMNonManageableType > ) > ;
template < typename COMNonManageableType >
ComPtrGuard < COMNonManageableType > createCOMPtrGuard ( COMNonManageableType * ptr = nullptr ) {
return ComPtrGuard < COMNonManageableType > { ptr , & release < COMNonManageableType > } ;
}
using AccelParamsType = std : : tuple < ComPtrGuard < ID3D11Device > , ComPtrGuard < ID3D11DeviceContext > > ;
2021-10-20 17:43:32 +08:00
2021-10-22 00:12:03 +08:00
AccelParamsType create_device_with_ctx ( IDXGIAdapter * adapter ) {
2021-10-20 17:43:32 +08:00
UINT flags = 0 ;
D3D_FEATURE_LEVEL feature_levels [ ] = { D3D_FEATURE_LEVEL_11_1 ,
D3D_FEATURE_LEVEL_11_0 ,
} ;
D3D_FEATURE_LEVEL featureLevel ;
ID3D11Device * ret_device_ptr = nullptr ;
ID3D11DeviceContext * ret_ctx_ptr = nullptr ;
HRESULT err = D3D11CreateDevice ( adapter , D3D_DRIVER_TYPE_UNKNOWN ,
nullptr , flags ,
feature_levels ,
ARRAYSIZE ( feature_levels ) ,
D3D11_SDK_VERSION , & ret_device_ptr ,
& featureLevel , & ret_ctx_ptr ) ;
if ( FAILED ( err ) ) {
throw std : : runtime_error ( " Cannot create D3D11CreateDevice, error: " +
std : : to_string ( HRESULT_CODE ( err ) ) ) ;
}
2021-10-22 00:12:03 +08:00
return std : : make_tuple ( createCOMPtrGuard ( ret_device_ptr ) ,
createCOMPtrGuard ( ret_ctx_ptr ) ) ;
2021-10-20 17:43:32 +08:00
}
# endif // HAVE_D3D11
# endif // HAVE_DIRECTX
# endif // HAVE_INF_ENGINE
2021-08-18 01:11:22 +08:00
} // anonymous namespace
namespace custom {
G_API_NET ( FaceDetector , < cv : : GMat ( cv : : GMat ) > , " face-detector " ) ;
using GDetections = cv : : GArray < cv : : Rect > ;
using GRect = cv : : GOpaque < cv : : Rect > ;
using GSize = cv : : GOpaque < cv : : Size > ;
using GPrims = cv : : GArray < cv : : gapi : : wip : : draw : : Prim > ;
2022-04-01 18:06:47 +08:00
G_API_OP ( ParseSSD , < GDetections ( cv : : GMat , GRect , GSize ) > , " sample.custom.parse-ssd " ) {
static cv : : GArrayDesc outMeta ( const cv : : GMatDesc & , const cv : : GOpaqueDesc & , const cv : : GOpaqueDesc & ) {
return cv : : empty_array_desc ( ) ;
}
} ;
// TODO: It duplicates infer_single_roi sample
G_API_OP ( LocateROI , < GRect ( GSize ) > , " sample.custom.locate-roi " ) {
static cv : : GOpaqueDesc outMeta ( const cv : : GOpaqueDesc & ) {
2021-08-18 01:11:22 +08:00
return cv : : empty_gopaque_desc ( ) ;
}
} ;
G_API_OP ( BBoxes , < GPrims ( GDetections , GRect ) > , " sample.custom.b-boxes " ) {
static cv : : GArrayDesc outMeta ( const cv : : GArrayDesc & , const cv : : GOpaqueDesc & ) {
return cv : : empty_array_desc ( ) ;
}
} ;
GAPI_OCV_KERNEL ( OCVLocateROI , LocateROI ) {
// This is the place where we can run extra analytics
// on the input image frame and select the ROI (region
// of interest) where we want to detect our objects (or
// run any other inference).
//
// Currently it doesn't do anything intelligent,
// but only crops the input image to square (this is
// the most convenient aspect ratio for detectors to use)
2022-01-24 22:05:26 +08:00
static void run ( const cv : : Size & in_size ,
cv : : Rect & out_rect ) {
2021-08-18 01:11:22 +08:00
// Identify the central point & square size (- some padding)
2022-04-01 18:06:47 +08:00
const auto center = cv : : Point { in_size . width / 2 , in_size . height / 2 } ;
auto sqside = std : : min ( in_size . width , in_size . height ) ;
// Now build the central square ROI
out_rect = cv : : Rect { center . x - sqside / 2
, center . y - sqside / 2
, sqside
, sqside
} ;
2021-08-18 01:11:22 +08:00
}
} ;
GAPI_OCV_KERNEL ( OCVBBoxes , BBoxes ) {
// This kernel converts the rectangles into G-API's
// rendering primitives
static void run ( const std : : vector < cv : : Rect > & in_face_rcs ,
const cv : : Rect & in_roi ,
std : : vector < cv : : gapi : : wip : : draw : : Prim > & 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 ) ;
} ;
out_prims . emplace_back ( cvt ( in_roi , CV_RGB ( 0 , 255 , 255 ) ) ) ; // cyan
for ( auto & & rc : in_face_rcs ) {
out_prims . emplace_back ( cvt ( rc , CV_RGB ( 0 , 255 , 0 ) ) ) ; // green
}
}
} ;
2022-04-01 18:06:47 +08:00
GAPI_OCV_KERNEL ( OCVParseSSD , ParseSSD ) {
static void run ( const cv : : Mat & in_ssd_result ,
const cv : : Rect & in_roi ,
const cv : : Size & in_parent_size ,
std : : vector < cv : : Rect > & out_objects ) {
const auto & in_ssd_dims = in_ssd_result . size ;
GAPI_Assert ( in_ssd_dims . dims ( ) = = 4u ) ;
const int MAX_PROPOSALS = in_ssd_dims [ 2 ] ;
const int OBJECT_SIZE = in_ssd_dims [ 3 ] ;
GAPI_Assert ( OBJECT_SIZE = = 7 ) ; // fixed SSD object size
const cv : : Size up_roi = in_roi . size ( ) ;
const cv : : Rect surface ( { 0 , 0 } , in_parent_size ) ;
out_objects . 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 ] ;
const float label = data [ i * OBJECT_SIZE + 1 ] ;
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 ] ;
( void ) label ; // unused
if ( image_id < 0.f ) {
break ; // marks end-of-detections
}
if ( confidence < 0.5f ) {
continue ; // skip objects with low confidence
}
// map relative coordinates to the original image scale
// taking the ROI into account
cv : : Rect rc ;
rc . x = static_cast < int > ( rc_left * up_roi . width ) ;
rc . y = static_cast < int > ( rc_top * up_roi . height ) ;
rc . width = static_cast < int > ( rc_right * up_roi . width ) - rc . x ;
rc . height = static_cast < int > ( rc_bottom * up_roi . height ) - rc . y ;
rc . x + = in_roi . x ;
rc . y + = in_roi . y ;
out_objects . emplace_back ( rc & surface ) ;
}
}
} ;
2021-08-18 01:11:22 +08:00
} // namespace custom
2021-08-24 20:41:57 +08:00
namespace cfg {
typename cv : : gapi : : wip : : onevpl : : CfgParam create_from_string ( const std : : string & line ) ;
}
2021-08-18 01:11:22 +08:00
int main ( int argc , char * argv [ ] ) {
cv : : CommandLineParser cmd ( argc , argv , keys ) ;
cmd . about ( about ) ;
if ( cmd . has ( " help " ) ) {
cmd . printMessage ( ) ;
return 0 ;
}
// get file name
2022-01-24 22:05:26 +08:00
const auto file_path = cmd . get < std : : string > ( " input " ) ;
const auto output = cmd . get < std : : string > ( " output " ) ;
2022-04-01 18:06:47 +08:00
const auto opt_roi = parse_roi ( cmd . get < std : : string > ( " roi " ) ) ;
2021-08-18 01:11:22 +08:00
const auto face_model_path = cmd . get < std : : string > ( " facem " ) ;
2021-12-10 16:58:59 +08:00
const auto streaming_queue_capacity = cmd . get < uint32_t > ( " streaming_queue_capacity " ) ;
2022-01-24 22:05:26 +08:00
const auto source_decode_queue_capacity = cmd . get < uint32_t > ( " frames_pool_size " ) ;
const auto source_vpp_queue_capacity = cmd . get < uint32_t > ( " vpp_frames_pool_size " ) ;
const auto device_id = cmd . get < std : : string > ( " faced " ) ;
2021-08-18 01:11:22 +08:00
2022-04-14 01:06:37 +08:00
// check output file extension
2021-08-18 01:11:22 +08:00
if ( ! output . empty ( ) ) {
auto ext = output . find_last_of ( " . " ) ;
if ( ext = = std : : string : : npos | | ( output . substr ( ext + 1 ) ! = " avi " ) ) {
std : : cerr < < " Output file should have *.avi extension for output video " < < std : : endl ;
return - 1 ;
}
}
2021-08-24 20:41:57 +08:00
// get oneVPL cfg params from cmd
std : : stringstream params_list ( cmd . get < std : : string > ( " cfg_params " ) ) ;
std : : vector < cv : : gapi : : wip : : onevpl : : CfgParam > source_cfgs ;
try {
std : : string line ;
while ( std : : getline ( params_list , line , ' ; ' ) ) {
source_cfgs . push_back ( cfg : : create_from_string ( line ) ) ;
}
} catch ( const std : : exception & ex ) {
std : : cerr < < " Invalid cfg parameter: " < < ex . what ( ) < < std : : endl ;
return - 1 ;
}
2022-01-24 22:05:26 +08:00
if ( source_decode_queue_capacity ! = 0 ) {
source_cfgs . push_back ( cv : : gapi : : wip : : onevpl : : CfgParam : : create_frames_pool_size ( source_decode_queue_capacity ) ) ;
}
if ( source_vpp_queue_capacity ! = 0 ) {
source_cfgs . push_back ( cv : : gapi : : wip : : onevpl : : CfgParam : : create_vpp_frames_pool_size ( source_vpp_queue_capacity ) ) ;
2021-12-08 15:09:33 +08:00
}
2021-08-18 01:11:22 +08:00
auto face_net = cv : : gapi : : ie : : Params < custom : : FaceDetector > {
face_model_path , // path to topology IR
2021-10-19 00:20:55 +08:00
get_weights_path ( face_model_path ) , // path to weights
2021-10-20 17:43:32 +08:00
device_id
2021-08-18 01:11:22 +08:00
} ;
2021-10-20 17:43:32 +08:00
// Create device_ptr & context_ptr using graphic API
// InferenceEngine requires such device & context to create its own
// remote shared context through InferenceEngine::ParamMap in
// GAPI InferenceEngine backend to provide interoperability with onevpl::GSource
// So GAPI InferenceEngine backend and onevpl::GSource MUST share the same
// device and context
2022-04-01 18:06:47 +08:00
cv : : util : : optional < cv : : gapi : : wip : : onevpl : : Device > accel_device ;
cv : : util : : optional < cv : : gapi : : wip : : onevpl : : Context > accel_ctx ;
2021-10-20 17:43:32 +08:00
# ifdef HAVE_INF_ENGINE
# ifdef HAVE_DIRECTX
# ifdef HAVE_D3D11
2021-10-22 00:12:03 +08:00
auto dx11_dev = createCOMPtrGuard < ID3D11Device > ( ) ;
auto dx11_ctx = createCOMPtrGuard < ID3D11DeviceContext > ( ) ;
2021-10-20 17:43:32 +08:00
2022-04-01 18:06:47 +08:00
if ( device_id . find ( " GPU " ) ! = std : : string : : npos ) {
2021-10-22 00:12:03 +08:00
auto adapter_factory = createCOMPtrGuard < IDXGIFactory > ( ) ;
2021-10-20 17:43:32 +08:00
{
IDXGIFactory * out_factory = nullptr ;
HRESULT err = CreateDXGIFactory ( __uuidof ( IDXGIFactory ) ,
reinterpret_cast < void * * > ( & out_factory ) ) ;
if ( FAILED ( err ) ) {
std : : cerr < < " Cannot create CreateDXGIFactory, error: " < < HRESULT_CODE ( err ) < < std : : endl ;
return - 1 ;
}
2021-10-22 00:12:03 +08:00
adapter_factory = createCOMPtrGuard ( out_factory ) ;
2021-10-20 17:43:32 +08:00
}
2021-10-22 00:12:03 +08:00
auto intel_adapter = createCOMPtrGuard < IDXGIAdapter > ( ) ;
2021-10-20 17:43:32 +08:00
UINT adapter_index = 0 ;
const unsigned int refIntelVendorID = 0x8086 ;
IDXGIAdapter * out_adapter = nullptr ;
while ( adapter_factory - > EnumAdapters ( adapter_index , & out_adapter ) ! = DXGI_ERROR_NOT_FOUND ) {
DXGI_ADAPTER_DESC desc { } ;
out_adapter - > GetDesc ( & desc ) ;
if ( desc . VendorId = = refIntelVendorID ) {
2021-10-22 00:12:03 +08:00
intel_adapter = createCOMPtrGuard ( out_adapter ) ;
2021-10-20 17:43:32 +08:00
break ;
}
+ + adapter_index ;
}
if ( ! intel_adapter ) {
std : : cerr < < " No Intel GPU adapter on aboard. Exit " < < std : : endl ;
return - 1 ;
}
2021-10-22 00:12:03 +08:00
std : : tie ( dx11_dev , dx11_ctx ) = create_device_with_ctx ( intel_adapter . get ( ) ) ;
2022-04-01 18:06:47 +08:00
accel_device = cv : : util : : make_optional (
cv : : gapi : : wip : : onevpl : : create_dx11_device (
reinterpret_cast < void * > ( dx11_dev . get ( ) ) ,
device_id ) ) ;
accel_ctx = cv : : util : : make_optional (
cv : : gapi : : wip : : onevpl : : create_dx11_context (
reinterpret_cast < void * > ( dx11_ctx . get ( ) ) ) ) ;
2021-10-20 17:43:32 +08:00
// put accel type description for VPL source
source_cfgs . push_back ( cfg : : create_from_string (
" mfxImplDescription.AccelerationMode "
" : "
" MFX_ACCEL_MODE_VIA_D3D11 " ) ) ;
}
# endif // HAVE_D3D11
# endif // HAVE_DIRECTX
// set ctx_config for GPU device only - no need in case of CPU device type
2022-04-01 18:06:47 +08:00
if ( accel_device . has_value ( ) & &
accel_device . value ( ) . get_name ( ) . find ( " GPU " ) ! = std : : string : : npos ) {
2021-10-20 17:43:32 +08:00
InferenceEngine : : ParamMap ctx_config ( { { " CONTEXT_TYPE " , " VA_SHARED " } ,
2022-04-01 18:06:47 +08:00
{ " VA_DEVICE " , accel_device . value ( ) . get_ptr ( ) } } ) ;
2021-10-20 17:43:32 +08:00
face_net . cfgContextParams ( ctx_config ) ;
2022-01-24 22:05:26 +08:00
2022-02-24 18:35:52 +08:00
// NB: consider NV12 surface because it's one of native GPU image format
face_net . pluginConfig ( { { " GPU_NV12_TWO_INPUTS " , " YES " } } ) ;
2021-10-20 17:43:32 +08:00
}
# endif // HAVE_INF_ENGINE
2022-04-01 18:06:47 +08:00
// turn on preproc
if ( accel_device . has_value ( ) & & accel_ctx . has_value ( ) ) {
face_net . cfgPreprocessingParams ( accel_device . value ( ) ,
accel_ctx . value ( ) ) ;
std : : cout < < " enforce VPP preprocessing on " < < device_id < < std : : endl ;
}
2021-08-18 01:11:22 +08:00
auto kernels = cv : : gapi : : kernels
< custom : : OCVLocateROI
2022-04-01 18:06:47 +08:00
, custom : : OCVParseSSD
2021-08-18 01:11:22 +08:00
, custom : : OCVBBoxes > ( ) ;
auto networks = cv : : gapi : : networks ( face_net ) ;
2021-12-08 15:09:33 +08:00
auto face_detection_args = cv : : compile_args ( networks , kernels ) ;
if ( streaming_queue_capacity ! = 0 ) {
face_detection_args + = cv : : compile_args ( cv : : gapi : : streaming : : queue_capacity { streaming_queue_capacity } ) ;
}
2021-08-18 01:11:22 +08:00
// Create source
2022-04-01 18:06:47 +08:00
cv : : gapi : : wip : : IStreamSource : : Ptr cap ;
2021-08-18 01:11:22 +08:00
try {
2022-04-01 18:06:47 +08:00
if ( accel_device . has_value ( ) & & accel_ctx . has_value ( ) ) {
2021-10-20 17:43:32 +08:00
cap = cv : : gapi : : wip : : make_onevpl_src ( file_path , source_cfgs ,
2022-04-01 18:06:47 +08:00
accel_device . value ( ) ,
accel_ctx . value ( ) ) ;
2021-10-20 17:43:32 +08:00
} else {
cap = cv : : gapi : : wip : : make_onevpl_src ( file_path , source_cfgs ) ;
}
2022-04-14 01:06:37 +08:00
std : : cout < < " oneVPL source description: " < < cap - > descr_of ( ) < < std : : endl ;
2021-08-18 01:11:22 +08:00
} catch ( const std : : exception & ex ) {
std : : cerr < < " Cannot create source: " < < ex . what ( ) < < std : : endl ;
return - 1 ;
}
cv : : GMetaArg descr = cap - > descr_of ( ) ;
auto frame_descr = cv : : util : : get < cv : : GFrameDesc > ( descr ) ;
2022-04-01 18:06:47 +08:00
cv : : GOpaque < cv : : Rect > in_roi ;
auto inputs = cv : : gin ( cap ) ;
2021-08-18 01:11:22 +08:00
// Now build the graph
cv : : GFrame in ;
auto size = cv : : gapi : : streaming : : size ( in ) ;
2022-04-01 18:06:47 +08:00
auto graph_inputs = cv : : GIn ( in ) ;
if ( ! opt_roi . has_value ( ) ) {
// Automatically detect ROI to infer. Make it output parameter
std : : cout < < " ROI is not set or invalid. Locating it automatically "
< < std : : endl ;
in_roi = custom : : LocateROI : : on ( size ) ;
} else {
// Use the value provided by user
std : : cout < < " Will run inference for static region "
< < opt_roi . value ( )
< < " only "
< < std : : endl ;
graph_inputs + = cv : : GIn ( in_roi ) ;
inputs + = cv : : gin ( opt_roi . value ( ) ) ;
2021-08-18 01:11:22 +08:00
}
2022-04-01 18:06:47 +08:00
auto blob = cv : : gapi : : infer < custom : : FaceDetector > ( in_roi , in ) ;
cv : : GArray < cv : : Rect > rcs = custom : : ParseSSD : : on ( blob , in_roi , size ) ;
auto out_frame = cv : : gapi : : wip : : draw : : renderFrame ( in , custom : : BBoxes : : on ( rcs , in_roi ) ) ;
auto out = cv : : gapi : : streaming : : BGR ( out_frame ) ;
cv : : GStreamingCompiled pipeline = cv : : GComputation ( std : : move ( graph_inputs ) , cv : : GOut ( out ) ) // and move here
. compileStreaming ( std : : move ( face_detection_args ) ) ;
2021-08-18 01:11:22 +08:00
// The execution part
2022-04-01 18:06:47 +08:00
pipeline . setSource ( std : : move ( inputs ) ) ;
2021-08-18 01:11:22 +08:00
pipeline . start ( ) ;
2021-11-26 19:31:15 +08:00
size_t frames = 0u ;
cv : : TickMeter tm ;
2021-08-18 01:11:22 +08:00
cv : : VideoWriter writer ;
if ( ! output . empty ( ) & & ! writer . isOpened ( ) ) {
const auto sz = cv : : Size { frame_descr . size . width , frame_descr . size . height } ;
writer . open ( output , cv : : VideoWriter : : fourcc ( ' M ' , ' J ' , ' P ' , ' G ' ) , 25.0 , sz ) ;
2022-04-01 18:06:47 +08:00
GAPI_Assert ( writer . isOpened ( ) ) ;
2021-08-18 01:11:22 +08:00
}
cv : : Mat outMat ;
2021-11-26 19:31:15 +08:00
tm . start ( ) ;
2021-08-18 01:11:22 +08:00
while ( pipeline . pull ( cv : : gout ( outMat ) ) ) {
cv : : imshow ( " Out " , outMat ) ;
cv : : waitKey ( 1 ) ;
if ( ! output . empty ( ) ) {
writer < < outMat ;
}
2021-11-26 19:31:15 +08:00
+ + frames ;
2021-08-18 01:11:22 +08:00
}
2021-11-26 19:31:15 +08:00
tm . stop ( ) ;
std : : cout < < " Processed " < < frames < < " frames " < < " ( " < < frames / tm . getTimeSec ( ) < < " FPS) " < < std : : endl ;
2022-04-01 18:06:47 +08:00
2021-08-18 01:11:22 +08:00
return 0 ;
}
2021-08-24 20:41:57 +08:00
namespace cfg {
typename cv : : gapi : : wip : : onevpl : : CfgParam create_from_string ( const std : : string & line ) {
using namespace cv : : gapi : : wip ;
if ( line . empty ( ) ) {
throw std : : runtime_error ( " Cannot parse CfgParam from emply line " ) ;
}
std : : string : : size_type name_endline_pos = line . find ( ' : ' ) ;
if ( name_endline_pos = = std : : string : : npos ) {
throw std : : runtime_error ( " Cannot parse CfgParam from: " + line +
" \n Expected separator \" : \" " ) ;
}
std : : string name = line . substr ( 0 , name_endline_pos ) ;
std : : string value = line . substr ( name_endline_pos + 1 ) ;
2022-01-24 22:05:26 +08:00
return cv : : gapi : : wip : : onevpl : : CfgParam : : create ( name , value ,
/* vpp params strongly optional */
name . find ( " vpp. " ) = = std : : string : : npos ) ;
2021-08-24 20:41:57 +08:00
}
}