G-API: Add standalone fix for graph empty input#20184
Conversation
modules/gapi/src/api/gproto.cpp
Outdated
| { | ||
| const auto desc = cv::descr_of(util::get<cv::Mat>(arg)); | ||
| GAPI_Assert(desc.size.height != 0 && desc.size.width != 0 && "incorrect dimensions of Mat!"); break; | ||
| GAPI_Assert(desc.size.height != 0 && desc.size.width != 0 && "incorrect dimensions of Mat!"); |
There was a problem hiding this comment.
I believe the problem was in using != intead of >, and at some point we get -1 there which passed through the test, isnt it?
There was a problem hiding this comment.
yes, it is.
But, i've decided that empty_gmat_descr comparison is more clearest here, isnt it ?
There was a problem hiding this comment.
I don't know, does it actually works for the case?
| if(cv::empty_gmat_desc() == cv::util::get<cv::GMatDesc>(meta)) | ||
| { | ||
| is_valid = false; | ||
| tracer << "empty cv::Mat is not allowed as compile argument"; |
There was a problem hiding this comment.
Empty cv::Mat (as the cv::Mat in general) is not a compile argument, so this message may be misleading
There was a problem hiding this comment.
Also - does this check handle the case when an empty cv::Mat is passed to .apply() ?
There was a problem hiding this comment.
I've checked the code and found:
- this parts is called from compile()
- compile() can be called as standalone method
or - be part of apply(), when arguments set was changed (recompile)
So, message looks like really misleading in direct apply() case.
And empty cv::Mat cannot be passed to .apply() because recompile would be triggered in first and invoke this compile()
@dmatveev What do you thinks about the message?
empty cv::Mat is not allowed as graph input argument
There was a problem hiding this comment.
It is more correct but again, we don't deal with cv::Mat at all when compiling a graph, so referring to a structure which may not exist at the time can be misleading.
| bool validate_input_meta_arg(const GMetaArg& meta, std::ostream* tracer = nullptr); | ||
| bool validate_input_meta(const GMatDesc& meta, std::ostream* tracer = nullptr); |
There was a problem hiding this comment.
Why do we need this here? It is a public header - it is exposed in the installed library package. Is it supposed to be used somehow by end users? I believe it is not
There was a problem hiding this comment.
it's actually the common part between gproto.cpp & gcompiled.cpp -which uses the same validation fucntionality
I've added it similarly in the same way with validate_input_args because i got the impression after file inspection that entire file exposes a set of auxiliary functions - additionally, i didn't face with usage other function in this file as public interface. This overall assumption score told me that file is utility file
But maybe I wrong and this utility-like function should be implemented in other place
There was a problem hiding this comment.
moved to src/ai/gmeta_chec.hpp/cpp
There was a problem hiding this comment.
gproto.cpp and gproto_priv.hpp are the right ones.
modules/gapi/src/api/gproto.cpp
Outdated
| "incorrect description of cv::UMat! " | ||
| "Dimensions, channel and depth must be positive"); |
There was a problem hiding this comment.
I believe the check itself and the error message here mix levels of abstractions.
Looking at this code, you don't know what is actually checked by this function, but the assert text complains about some specific fields.
I am not sure if it needs to be an assert at all. If you want provide details, provide it in the exception text you throw from the validate_input_meta() function (so it becomes void not bool).
There was a problem hiding this comment.
It make sense, and "incorrect description of cv::*Mat" is enough
about exception i think it is a bad idea:
- void function with the only reason in throwing exception looks ugly and unsafe and inconvenient in usage and considered as bad practice
- GAPI_Assert here means that this place is performance critical in Release build, so exception is not good here
There was a problem hiding this comment.
It is not performance critical, in the performance-critical code we use DbgAssert.
modules/gapi/src/api/gproto.cpp
Outdated
| bool cv::validate_input_meta(const cv::GMatDesc& meta, std::ostream* tracer) | ||
| { | ||
| if (meta.dims.empty()) | ||
| { | ||
| if (!(meta.size.height > 0 && meta.size.width > 0)) | ||
| { | ||
| if (tracer) | ||
| { | ||
| *tracer << "Image format is invalid. Size must contain positive values, got width: " | ||
| << meta.size.width << ", height: " << meta.size.height; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| if (!(meta.chan > 0)) | ||
| { | ||
| if (tracer) | ||
| { | ||
| *tracer << "Image format is invalid. Channel mustn't be negative value, got channel: " | ||
| << meta.chan; | ||
| } | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| if (!(meta.depth >= 0)) | ||
| { | ||
| if (tracer) | ||
| { | ||
| *tracer << "Image format is invalid. Depth must be positive value, got depth: " | ||
| << meta.depth; | ||
| } | ||
| return false; | ||
| } | ||
| return true; | ||
| } |
There was a problem hiding this comment.
Why bool here again? I believe the code simplifies a lot if we drop this tracer thing at all and simply throw.
There was a problem hiding this comment.
yes, it simplifed here, but after it become more complicated in caller context. It is a bad idea, as for me, to wrap function around try-catch every time
if you dislike optional tracer, then it is possible in the following approach
std::tuple<bool, std::string> validate_();
...
auto res = validate_(...)
if(!res.first)
{
printf(res.second)
}
what do you think?
There was a problem hiding this comment.
Mainly we don't need try/catch in/with our own code.
modules/gapi/CMakeLists.txt
Outdated
| src/api/ginfer.cpp | ||
| src/api/media.cpp | ||
| src/api/rmat.cpp | ||
| src/api/gmeta_check.cpp |
There was a problem hiding this comment.
a separate file may be too much for this simple function, consider gproto.cpp & its _priv.hpp.
There was a problem hiding this comment.
yeah, i thought about _priv.hpp, but I was confused with comment // FIXME: why it is here?
And i realized that this include should be removed is in future
@dmatveev What do you think about that - do you still suggest to move it in _priv.hpp ?
There was a problem hiding this comment.
I believe in 2021 nobody remembers the answer to
// FIXME: why it is here?
:)
modules/gapi/src/api/gproto.cpp
Outdated
| { | ||
| if (!(meta.size.height > 0 && meta.size.width > 0)) | ||
| { | ||
| cv::util::throw_error(std::logic_error(std::string("Image format is invalid. Size must contain positive values, got width: ") + |
There was a problem hiding this comment.
This line is 139 characters long; I believe the OpenCV's coding style allows something up to 110 but we're trying to follow ~80. I believe the std::string() thing is not needed here as operator+(const char*, std::string) should work things out. throw_error itself is terrible (was done wrong initially and nobody has fixed it then), so we usually write this stuff like
cv::util::throw_error
(std::logic_error
(...);Also, I believe a simple assert could work fine here (except the failed value won't be printed).
| try | ||
| { | ||
| gimpl::proto::validate_input_meta_arg(meta); //may throw | ||
| } | ||
| catch(const std::exception& ex) | ||
| { | ||
| const auto index = ade::util::index(meta_arg_idx); | ||
| util::throw_error(std::logic_error | ||
| ("GComputation metadata incorrect value " | ||
| "(argument " + std::to_string(index) + "), error: " + | ||
| ex.what())); |
There was a problem hiding this comment.
I believe this try/catch is redundant - the code throws anyway, the only thing it adds is the error message - you can use the LOG() trick instead to provide the context.
| const auto &proto = std::get<1>(ade::util::value(meta_arg_idx)); | ||
|
|
||
| const auto index = ade::util::index(meta_arg_idx); | ||
| GAPI_LOG_DEBUG(nullptr, "Process index: " << index); |
There was a problem hiding this comment.
[DEBUG:0] global C:\Users\sivanov\github\opencv\modules\gapi\src\compiler\gcompiler.cpp (346) cv::gimpl::GCompiler::validateInputMeta Total count: 1
[DEBUG:0] global C:\Users\sivanov\github\opencv\modules\gapi\src\compiler\gcompiler.cpp (353) cv::gimpl::GCompiler::validateInputMeta Process index: 0
G-API: Add standalone fix for graph empty input * Add sandalone fix for graph empty input * Apply some review comments * Fix whitespace * Apply review comment: make Mat check more deeper * Apply some comments * Remove tracer apply exception throwing * Apply comments: move validatio into gproto_priv.hpp * Apply minor text correction * Fix alignment, remove try-catch
STANDALONE version of the fix
G-API graph invocation may fail in case of user passed empty cv::Mat object and this issue detected in core part of G-API on compute step.
The main idea is move pretty-check into compile phase and separate if from actual invocation (note: compile doesn't mean C++ compile but rather means phase of graph pipeline execution )
Added UTs:
Pull Request Readiness Checklist
See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request
Patch to opencv_extra has the same branch name.