1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 07:43:03 +04:00

Merge remote-tracking branch 'upstream/3.4' into merge-3.4

This commit is contained in:
Alexander Alekhin
2020-03-04 20:49:09 +00:00
47 changed files with 750 additions and 353 deletions
@@ -104,14 +104,16 @@ struct LogTagAuto
// non-null. Do not re-define.
#define CV_LOGTAG_GLOBAL cv::utils::logging::internal::getGlobalLogTag()
#define CV_LOG_WITH_TAG(tag, msgLevel, ...) \
#define CV_LOG_WITH_TAG(tag, msgLevel, extra_check0, extra_check1, ...) \
for(;;) { \
extra_check0; \
const auto cv_temp_msglevel = (cv::utils::logging::LogLevel)(msgLevel); \
if (cv_temp_msglevel >= (CV_LOG_STRIP_LEVEL)) break; \
auto cv_temp_logtagptr = CV_LOGTAG_PTR_CAST(CV_LOGTAG_EXPAND_NAME(tag)); \
if (!cv_temp_logtagptr) cv_temp_logtagptr = CV_LOGTAG_PTR_CAST(CV_LOGTAG_FALLBACK); \
if (!cv_temp_logtagptr) cv_temp_logtagptr = CV_LOGTAG_PTR_CAST(CV_LOGTAG_GLOBAL); \
if (cv_temp_logtagptr && (cv_temp_msglevel > cv_temp_logtagptr->level)) break; \
extra_check1; \
std::stringstream cv_temp_logstream; \
cv_temp_logstream << __VA_ARGS__; \
cv::utils::logging::internal::writeLogMessageEx( \
@@ -124,28 +126,91 @@ struct LogTagAuto
break; \
}
#define CV_LOG_FATAL(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_FATAL, __VA_ARGS__)
#define CV_LOG_ERROR(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_ERROR, __VA_ARGS__)
#define CV_LOG_WARNING(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_WARNING, __VA_ARGS__)
#define CV_LOG_INFO(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_INFO, __VA_ARGS__)
#define CV_LOG_DEBUG(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_DEBUG, __VA_ARGS__)
#define CV_LOG_VERBOSE(tag, v, ...) CV_LOG_WITH_TAG(tag, (cv::utils::logging::LOG_LEVEL_VERBOSE + (int)(v)), __VA_ARGS__)
#define CV_LOG_FATAL(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_FATAL, , , __VA_ARGS__)
#define CV_LOG_ERROR(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_ERROR, , , __VA_ARGS__)
#define CV_LOG_WARNING(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_WARNING, , , __VA_ARGS__)
#define CV_LOG_INFO(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_INFO, , , __VA_ARGS__)
#define CV_LOG_DEBUG(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_DEBUG, , , __VA_ARGS__)
#define CV_LOG_VERBOSE(tag, v, ...) CV_LOG_WITH_TAG(tag, (cv::utils::logging::LOG_LEVEL_VERBOSE + (int)(v)), , , __VA_ARGS__)
#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_INFO
# undef CV_LOG_INFO
# define CV_LOG_INFO(tag, ...)
#undef CV_LOG_INFO
#define CV_LOG_INFO(tag, ...)
#endif
#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_DEBUG
# undef CV_LOG_DEBUG
# define CV_LOG_DEBUG(tag, ...)
#undef CV_LOG_DEBUG
#define CV_LOG_DEBUG(tag, ...)
#endif
#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_VERBOSE
# undef CV_LOG_VERBOSE
# define CV_LOG_VERBOSE(tag, v, ...)
#undef CV_LOG_VERBOSE
#define CV_LOG_VERBOSE(tag, v, ...)
#endif
//! @cond IGNORED
#define CV__LOG_ONCE_CHECK_PRE \
static bool _cv_log_once_ ## __LINE__ = false; \
if (_cv_log_once_ ## __LINE__) break;
#define CV__LOG_ONCE_CHECK_POST \
_cv_log_once_ ## __LINE__ = true;
#define CV__LOG_IF_CHECK(logging_cond) \
if (!(logging_cond)) break;
//! @endcond
// CV_LOG_ONCE_XXX macros
#define CV_LOG_ONCE_ERROR(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_ERROR, CV__LOG_ONCE_CHECK_PRE, CV__LOG_ONCE_CHECK_POST, __VA_ARGS__)
#define CV_LOG_ONCE_WARNING(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_WARNING, CV__LOG_ONCE_CHECK_PRE, CV__LOG_ONCE_CHECK_POST, __VA_ARGS__)
#define CV_LOG_ONCE_INFO(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_INFO, CV__LOG_ONCE_CHECK_PRE, CV__LOG_ONCE_CHECK_POST, __VA_ARGS__)
#define CV_LOG_ONCE_DEBUG(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_DEBUG, CV__LOG_ONCE_CHECK_PRE, CV__LOG_ONCE_CHECK_POST, __VA_ARGS__)
#define CV_LOG_ONCE_VERBOSE(tag, v, ...) CV_LOG_WITH_TAG(tag, (cv::utils::logging::LOG_LEVEL_VERBOSE + (int)(v)), CV__LOG_ONCE_CHECK_PRE, CV__LOG_ONCE_CHECK_POST, __VA_ARGS__)
#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_INFO
#undef CV_LOG_ONCE_INFO
#define CV_LOG_ONCE_INFO(tag, ...)
#endif
#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_DEBUG
#undef CV_LOG_ONCE_DEBUG
#define CV_LOG_ONCE_DEBUG(tag, ...)
#endif
#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_VERBOSE
#undef CV_LOG_ONCE_VERBOSE
#define CV_LOG_ONCE_VERBOSE(tag, v, ...)
#endif
// CV_LOG_IF_XXX macros
#define CV_LOG_IF_FATAL(tag, logging_cond, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_FATAL, , CV__LOG_IF_CHECK(logging_cond), __VA_ARGS__)
#define CV_LOG_IF_ERROR(tag, logging_cond, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_ERROR, , CV__LOG_IF_CHECK(logging_cond), __VA_ARGS__)
#define CV_LOG_IF_WARNING(tag, logging_cond, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_WARNING, , CV__LOG_IF_CHECK(logging_cond), __VA_ARGS__)
#define CV_LOG_IF_INFO(tag, logging_cond, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_INFO, , CV__LOG_IF_CHECK(logging_cond), __VA_ARGS__)
#define CV_LOG_IF_DEBUG(tag, logging_cond, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_DEBUG, , CV__LOG_IF_CHECK(logging_cond), __VA_ARGS__)
#define CV_LOG_IF_VERBOSE(tag, v, logging_cond, ...) CV_LOG_WITH_TAG(tag, (cv::utils::logging::LOG_LEVEL_VERBOSE + (int)(v)), , CV__LOG_IF_CHECK(logging_cond), __VA_ARGS__)
#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_INFO
#undef CV_LOG_IF_INFO
#define CV_LOG_IF_INFO(tag, logging_cond, ...)
#endif
#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_DEBUG
#undef CV_LOG_IF_DEBUG
#define CV_LOG_IF_DEBUG(tag, logging_cond, ...)
#endif
#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_VERBOSE
#undef CV_LOG_IF_VERBOSE
#define CV_LOG_IF_VERBOSE(tag, v, logging_cond, ...)
#endif
//! @}
}}} // namespace
+2 -2
View File
@@ -193,8 +193,8 @@ void writeLogMessage(LogLevel logLevel, const char* message)
case LOG_LEVEL_INFO: ss << "[ INFO:" << threadID << "] " << message << std::endl; break;
case LOG_LEVEL_DEBUG: ss << "[DEBUG:" << threadID << "] " << message << std::endl; break;
case LOG_LEVEL_VERBOSE: ss << message << std::endl; break;
default:
return;
case LOG_LEVEL_SILENT: return; // avoid compiler warning about incomplete switch
case ENUM_LOG_LEVEL_FORCE_INT: return; // avoid compiler warning about incomplete switch
}
#ifdef __ANDROID__
int android_logLevel = ANDROID_LOG_INFO;
+10 -3
View File
@@ -117,8 +117,17 @@ public:
void transpose(const MatExpr& expr, MatExpr& res) const CV_OVERRIDE;
Size size(const MatExpr& expr) const CV_OVERRIDE
{
return Size(
(expr.flags & GEMM_2_T) ? expr.b.rows : expr.b.cols,
(expr.flags & GEMM_1_T) ? expr.a.cols : expr.a.rows
);
}
static void makeExpr(MatExpr& res, int flags, const Mat& a, const Mat& b,
double alpha=1, const Mat& c=Mat(), double beta=1);
};
static MatOp_GEMM g_MatOp_GEMM;
@@ -199,7 +208,7 @@ static inline bool isReciprocal(const MatExpr& e) { return isBin(e,'/') && (!e.b
static inline bool isT(const MatExpr& e) { return e.op == &g_MatOp_T; }
static inline bool isInv(const MatExpr& e) { return e.op == &g_MatOp_Invert; }
static inline bool isSolve(const MatExpr& e) { return e.op == &g_MatOp_Solve; }
static inline bool isGEMM(const MatExpr& e) { return e.op == &g_MatOp_GEMM; }
//static inline bool isGEMM(const MatExpr& e) { return e.op == &g_MatOp_GEMM; }
static inline bool isMatProd(const MatExpr& e) { return e.op == &g_MatOp_GEMM && (!e.c.data || e.beta == 0); }
static inline bool isInitializer(const MatExpr& e) { return e.op == getGlobalMatOpInitializer(); }
@@ -1240,8 +1249,6 @@ Size MatExpr::size() const
{
if( isT(*this) || isInv(*this) )
return Size(a.rows, a.cols);
if( isGEMM(*this) )
return Size(b.cols, a.rows);
if( isSolve(*this) )
return Size(b.cols, a.cols);
if( isInitializer(*this) )
+23
View File
@@ -2019,6 +2019,29 @@ TEST(Core_MatExpr, issue_16655)
<< "Mat: CV_8UC3 != " << typeToString(ab_mat.type());
}
TEST(Core_MatExpr, issue_16689)
{
Mat a(Size(10, 5), CV_32FC1, 5);
Mat b(Size(10, 5), CV_32FC1, 2);
Mat bt(Size(5, 10), CV_32FC1, 3);
{
MatExpr r = a * bt; // gemm
EXPECT_EQ(Mat(r).size(), r.size()) << "[10x5] x [5x10] => [5x5]";
}
{
MatExpr r = a * b.t(); // gemm
EXPECT_EQ(Mat(r).size(), r.size()) << "[10x5] x [10x5].t() => [5x5]";
}
{
MatExpr r = a.t() * b; // gemm
EXPECT_EQ(Mat(r).size(), r.size()) << "[10x5].t() x [10x5] => [10x10]";
}
{
MatExpr r = a.t() * bt.t(); // gemm
EXPECT_EQ(Mat(r).size(), r.size()) << "[10x5].t() x [5x10].t() => [10x10]";
}
}
#ifdef HAVE_EIGEN
TEST(Core_Eigen, eigen2cv_check_Mat_type)
{
+50
View File
@@ -2,6 +2,9 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
#include "opencv2/core/utils/logger.defines.hpp"
#undef CV_LOG_STRIP_LEVEL
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_VERBOSE + 1
#include "opencv2/core/utils/logger.hpp"
#include "opencv2/core/utils/buffer_area.private.hpp"
@@ -287,6 +290,53 @@ TEST(CommandLineParser, testScalar)
EXPECT_EQ(parser.get<Scalar>("s5"), Scalar(5, -4, 3, 2));
}
TEST(Logger, DISABLED_message)
{
int id = 42;
CV_LOG_VERBOSE(NULL, 0, "Verbose message: " << id);
CV_LOG_VERBOSE(NULL, 1, "Verbose message: " << id);
CV_LOG_DEBUG(NULL, "Debug message: " << id);
CV_LOG_INFO(NULL, "Info message: " << id);
CV_LOG_WARNING(NULL, "Warning message: " << id);
CV_LOG_ERROR(NULL, "Error message: " << id);
CV_LOG_FATAL(NULL, "Fatal message: " << id);
}
static int testLoggerMessageOnce(int id)
{
CV_LOG_ONCE_VERBOSE(NULL, 0, "Verbose message: " << id++);
CV_LOG_ONCE_VERBOSE(NULL, 1, "Verbose message: " << id++);
CV_LOG_ONCE_DEBUG(NULL, "Debug message: " << id++);
CV_LOG_ONCE_INFO(NULL, "Info message: " << id++);
CV_LOG_ONCE_WARNING(NULL, "Warning message: " << id++);
CV_LOG_ONCE_ERROR(NULL, "Error message: " << id++);
// doesn't make sense: CV_LOG_ONCE_FATAL
return id;
}
TEST(Logger, DISABLED_message_once)
{
int check_id_first = testLoggerMessageOnce(42);
EXPECT_GT(check_id_first, 42);
int check_id_second = testLoggerMessageOnce(0);
EXPECT_EQ(0, check_id_second);
}
TEST(Logger, DISABLED_message_if)
{
for (int i = 0; i < 100; i++)
{
CV_LOG_IF_VERBOSE(NULL, 0, i == 0 || i == 42, "Verbose message: " << i);
CV_LOG_IF_VERBOSE(NULL, 1, i == 0 || i == 42, "Verbose message: " << i);
CV_LOG_IF_DEBUG(NULL, i == 0 || i == 42, "Debug message: " << i);
CV_LOG_IF_INFO(NULL, i == 0 || i == 42, "Info message: " << i);
CV_LOG_IF_WARNING(NULL, i == 0 || i == 42, "Warning message: " << i);
CV_LOG_IF_ERROR(NULL, i == 0 || i == 42, "Error message: " << i);
CV_LOG_IF_FATAL(NULL, i == 0 || i == 42, "Fatal message: " << i);
}
}
TEST(Samples, findFile)
{
cv::utils::logging::LogLevel prev = cv::utils::logging::setLogLevel(cv::utils::logging::LOG_LEVEL_VERBOSE);
+10 -7
View File
@@ -69,8 +69,12 @@ int Subgraph::getInputNodeId(const Ptr<ImportGraphWrapper>& net,
const int numNodes = net->getNumNodes();
for (int i = 0; i < numNodes; ++i)
{
if (net->getNodeName(i) == name)
return i;
const int numOutputs = net->getNumOutputs(i);
for (int j = 0; j < numOutputs; j++)
{
if (net->getOutputName(i, j) == name)
return i;
}
}
CV_Error(Error::StsParseError, "Input node with name " + name + " not found");
}
@@ -111,12 +115,12 @@ bool Subgraph::match(const Ptr<ImportGraphWrapper>& net, int nodeId,
continue;
nodeId = getInputNodeId(net, node, j);
const Ptr<ImportNodeWrapper> inpNode = net->getNode(nodeId);
if (inpNode->getType() != "Const")
if (inpNode->getType() != "Const" && inpNode->getType() != "Constant")
{
nodesToMatch.push(nodeId);
targetNodes.push(inputNodes[j]);
}
else if (nodes[inputNodes[j]] != "Const")
else if (nodes[inputNodes[j]] != "Const" && nodes[inputNodes[j]] != "Constant")
return false;
}
matchedNodesIds.push_back(nodeToMatch);
@@ -190,15 +194,14 @@ void simplifySubgraphs(const Ptr<ImportGraphWrapper>& net,
{
int numNodes = net->getNumNodes();
std::vector<int> matchedNodesIds, targetNodesIds;
for (int i = 0; i < numNodes; ++i)
for (int j = 0; j < patterns.size(); ++j)
{
for (int j = 0; j < patterns.size(); ++j)
for (int i = 0; i < numNodes; ++i)
{
if (patterns[j]->match(net, i, matchedNodesIds, targetNodesIds))
{
patterns[j]->replace(net, matchedNodesIds, targetNodesIds);
numNodes -= matchedNodesIds.size() - 1; // #matchedNodes removed and one added.
break;
}
}
}
+3 -1
View File
@@ -39,7 +39,9 @@ public:
virtual int getNumNodes() const = 0;
virtual std::string getNodeName(int idx) const = 0;
virtual int getNumOutputs(int nodeId) const = 0;
virtual std::string getOutputName(int nodeId, int outId) const = 0;
virtual void removeNode(int idx) = 0;
};
+221 -4
View File
@@ -76,12 +76,21 @@ public:
return numInputs + net.node_size();
}
virtual std::string getNodeName(int idx) const CV_OVERRIDE
virtual int getNumOutputs(int nodeId) const CV_OVERRIDE
{
if (idx < numInputs)
return net.input(idx).name();
if (nodeId < numInputs)
return 1;
else
return net.node(idx - numInputs).output(0);
return net.node(nodeId - numInputs).output_size();
}
virtual std::string getOutputName(int nodeId, int outId) const CV_OVERRIDE
{
CV_Assert(outId < getNumOutputs(nodeId));
if (nodeId < numInputs)
return net.input(nodeId).name();
else
return net.node(nodeId - numInputs).output(outId);
}
virtual void removeNode(int idx) CV_OVERRIDE
@@ -145,13 +154,221 @@ private:
int axis;
};
class GatherCastSubgraph : public Subgraph
{
public:
GatherCastSubgraph()
{
int input = addNodeToMatch("");
int index = addNodeToMatch("Constant");
int gather = addNodeToMatch("Gather", input, index);
addNodeToMatch("Cast", gather);
setFusedNode("Gather", input, index);
}
};
class MulCastSubgraph : public Subgraph
{
public:
MulCastSubgraph()
{
int input = addNodeToMatch("");
int scaleNode = addNodeToMatch("Constant");
int mul = addNodeToMatch("Mul", input, scaleNode);
addNodeToMatch("Cast", mul);
setFusedNode("Mul", input, scaleNode);
}
};
class ExtractScalesSubgraph : public Subgraph
{
public:
ExtractScalesSubgraph()
{
input = addNodeToMatch("");
int indexH = addNodeToMatch("Constant");
int shape1 = addNodeToMatch("Shape", input);
int gather1 = addNodeToMatch("Gather", shape1, indexH);
scaleHNode = addNodeToMatch("Constant");
int mul1 = addNodeToMatch("Mul", gather1, scaleHNode);
int floor1 = addNodeToMatch("Floor", mul1);
int indexW = addNodeToMatch("Constant");
int shape2 = addNodeToMatch("Shape", input);
int gather2 = addNodeToMatch("Gather", shape2, indexW);
scaleWNode = addNodeToMatch("Constant");
int mul2 = addNodeToMatch("Mul", gather2, scaleWNode);
int floor2 = addNodeToMatch("Floor", mul2);
int unsqueeze1 = addNodeToMatch("Unsqueeze", floor1);
int unsqueeze2 = addNodeToMatch("Unsqueeze", floor2);
concatId = addNodeToMatch("Concat", unsqueeze1, unsqueeze2);
}
void finalize(const Ptr<ImportGraphWrapper>& net,
const Ptr<ImportNodeWrapper>& fusedNode,
std::vector<Ptr<ImportNodeWrapper> >& inputs) CV_OVERRIDE
{
opencv_onnx::NodeProto* constant_node = inputs[1].dynamicCast<ONNXNodeWrapper>()->node;
opencv_onnx::TensorProto tensor_proto = constant_node->attribute(0).t();
Mat scaleW = getMatFromTensor(tensor_proto);
CV_Assert(scaleW.total() == 1);
scaleW.convertTo(scaleW, CV_32F);
constant_node = inputs[2].dynamicCast<ONNXNodeWrapper>()->node;
tensor_proto = constant_node->attribute(0).t();
Mat scaleH = getMatFromTensor(tensor_proto);
CV_Assert(scaleH.total() == 1);
scaleH.convertTo(scaleH, CV_32F);
opencv_onnx::NodeProto* node = fusedNode.dynamicCast<ONNXNodeWrapper>()->node;
opencv_onnx::AttributeProto* attrH = node->add_attribute();
attrH->set_name("height_scale");
attrH->set_i(scaleH.at<float>(0));
opencv_onnx::AttributeProto* attrW = node->add_attribute();
attrW->set_name("width_scale");
attrW->set_i(scaleW.at<float>(0));
node->mutable_input()->DeleteSubrange(1, 2); // Remove two last inputs
}
protected:
int input, concatId;
int scaleHNode, scaleWNode;
};
class UpsampleSubgraph : public ExtractScalesSubgraph
{
public:
UpsampleSubgraph() : ExtractScalesSubgraph()
{
int shape = addNodeToMatch("Shape", input);
int slice = addNodeToMatch("Slice", shape);
int castConcat = addNodeToMatch("Cast", concatId);
int castSlice = addNodeToMatch("Cast", slice);
int divide = addNodeToMatch("Div", castConcat, castSlice);
int constant = addNodeToMatch("Constant");
int concat = addNodeToMatch("Concat", constant, divide);
addNodeToMatch("Upsample", input, concat);
setFusedNode("Upsample", input, scaleWNode, scaleHNode);
}
};
class ResizeSubgraph1 : public ExtractScalesSubgraph
{
public:
ResizeSubgraph1() : ExtractScalesSubgraph()
{
int shape = addNodeToMatch("Shape", input);
int slice = addNodeToMatch("Slice", shape, addNodeToMatch("Constant"), addNodeToMatch("Constant"), addNodeToMatch("Constant"));
int castConcat = addNodeToMatch("Cast", concatId);
int concat = addNodeToMatch("Concat", slice, castConcat);
int constant = addNodeToMatch("Constant");
addNodeToMatch("Resize", input, constant, constant, concat);
setFusedNode("Upsample", input, scaleWNode, scaleHNode);
}
};
class ResizeSubgraph2 : public ExtractScalesSubgraph
{
public:
ResizeSubgraph2() : ExtractScalesSubgraph()
{
int constantConcat = addNodeToMatch("Constant");
int castConcat = addNodeToMatch("Cast", concatId);
int concat = addNodeToMatch("Concat", constantConcat, castConcat);
int constant = addNodeToMatch("Constant");
addNodeToMatch("Resize", input, constant, constant, concat);
setFusedNode("Upsample", input, scaleWNode, scaleHNode);
}
};
void simplifySubgraphs(opencv_onnx::GraphProto& net)
{
std::vector<Ptr<Subgraph> > subgraphs;
subgraphs.push_back(makePtr<GatherCastSubgraph>());
subgraphs.push_back(makePtr<MulCastSubgraph>());
subgraphs.push_back(makePtr<UpsampleSubgraph>());
subgraphs.push_back(makePtr<ResizeSubgraph1>());
subgraphs.push_back(makePtr<ResizeSubgraph2>());
subgraphs.push_back(makePtr<SoftMaxSubgraph>());
simplifySubgraphs(Ptr<ImportGraphWrapper>(new ONNXGraphWrapper(net)), subgraphs);
}
Mat getMatFromTensor(opencv_onnx::TensorProto& tensor_proto)
{
if (tensor_proto.raw_data().empty() && tensor_proto.float_data().empty() &&
tensor_proto.double_data().empty() && tensor_proto.int64_data().empty())
return Mat();
opencv_onnx::TensorProto_DataType datatype = tensor_proto.data_type();
Mat blob;
std::vector<int> sizes;
for (int i = 0; i < tensor_proto.dims_size(); i++) {
sizes.push_back(tensor_proto.dims(i));
}
if (sizes.empty())
sizes.assign(1, 1);
if (datatype == opencv_onnx::TensorProto_DataType_FLOAT) {
if (!tensor_proto.float_data().empty()) {
const ::google::protobuf::RepeatedField<float> field = tensor_proto.float_data();
Mat(sizes, CV_32FC1, (void*)field.data()).copyTo(blob);
}
else {
char* val = const_cast<char*>(tensor_proto.raw_data().c_str());
Mat(sizes, CV_32FC1, val).copyTo(blob);
}
}
else if (datatype == opencv_onnx::TensorProto_DataType_DOUBLE)
{
const ::google::protobuf::RepeatedField<double> field = tensor_proto.double_data();
CV_Assert(!field.empty());
Mat(sizes, CV_64FC1, (void*)field.data()).convertTo(blob, CV_32FC1);
}
else if (datatype == opencv_onnx::TensorProto_DataType_INT64)
{
blob.create(sizes, CV_32SC1);
int32_t* dst = reinterpret_cast<int32_t*>(blob.data);
if (!tensor_proto.int64_data().empty()) {
::google::protobuf::RepeatedField< ::google::protobuf::int64> src = tensor_proto.int64_data();
convertInt64ToInt32(src, dst, blob.total());
}
else
{
const char* val = tensor_proto.raw_data().c_str();
#if CV_STRONG_ALIGNMENT
// Aligned pointer is required: https://github.com/opencv/opencv/issues/16373
// this doesn't work: typedef int64_t CV_DECL_ALIGNED(1) unaligned_int64_t;
AutoBuffer<int64_t, 16> aligned_val;
if (!isAligned<sizeof(int64_t)>(val))
{
size_t sz = tensor_proto.raw_data().size();
aligned_val.allocate(divUp(sz, sizeof(int64_t)));
memcpy(aligned_val.data(), val, sz);
val = (const char*)aligned_val.data();
}
#endif
const int64_t* src = reinterpret_cast<const int64_t*>(val);
convertInt64ToInt32(src, dst, blob.total());
}
}
else
CV_Error(Error::StsUnsupportedFormat, "Unsupported data type: " +
opencv_onnx::TensorProto_DataType_Name(datatype));
if (tensor_proto.dims_size() == 0)
blob.dims = 1; // To force 1-dimensional cv::Mat for scalars.
return blob;
}
CV__DNN_INLINE_NS_END
}} // namespace cv::dnn
@@ -24,6 +24,19 @@ CV__DNN_INLINE_NS_BEGIN
void simplifySubgraphs(opencv_onnx::GraphProto& net);
template<typename T1, typename T2>
void convertInt64ToInt32(const T1& src, T2& dst, int size)
{
for (int i = 0; i < size; i++) {
if (src[i] < std::numeric_limits<int32_t>::min() || src[i] > std::numeric_limits<int32_t>::max()) {
CV_Error(Error::StsOutOfRange, "Input is out of OpenCV 32S range");
}
dst[i] = saturate_cast<int32_t>(src[i]);
}
}
Mat getMatFromTensor(opencv_onnx::TensorProto& tensor_proto);
CV__DNN_INLINE_NS_END
}} // namespace dnn, namespace cv
+39 -107
View File
@@ -95,83 +95,6 @@ void releaseONNXTensor(opencv_onnx::TensorProto& tensor_proto)
}
}
template<typename T1, typename T2>
void convertInt64ToInt32(const T1& src, T2& dst, int size)
{
for (int i = 0; i < size; i++) {
if (src[i] < std::numeric_limits<int32_t>::min() || src[i] > std::numeric_limits<int32_t>::max()) {
CV_Error(Error::StsOutOfRange, "Input is out of OpenCV 32S range");
}
dst[i] = saturate_cast<int32_t>(src[i]);
}
}
Mat getMatFromTensor(opencv_onnx::TensorProto& tensor_proto)
{
CV_Assert(!tensor_proto.raw_data().empty() || !tensor_proto.float_data().empty()
|| !tensor_proto.double_data().empty() || !tensor_proto.int64_data().empty());
opencv_onnx::TensorProto_DataType datatype = tensor_proto.data_type();
Mat blob;
std::vector<int> sizes;
for (int i = 0; i < tensor_proto.dims_size(); i++) {
sizes.push_back(tensor_proto.dims(i));
}
if (sizes.empty())
sizes.assign(1, 1);
if (datatype == opencv_onnx::TensorProto_DataType_FLOAT) {
if (!tensor_proto.float_data().empty()) {
const ::google::protobuf::RepeatedField<float> field = tensor_proto.float_data();
Mat(sizes, CV_32FC1, (void*)field.data()).copyTo(blob);
}
else {
char* val = const_cast<char*>(tensor_proto.raw_data().c_str());
Mat(sizes, CV_32FC1, val).copyTo(blob);
}
}
else if (datatype == opencv_onnx::TensorProto_DataType_DOUBLE)
{
const ::google::protobuf::RepeatedField<double> field = tensor_proto.double_data();
CV_Assert(!field.empty());
Mat(sizes, CV_64FC1, (void*)field.data()).convertTo(blob, CV_32FC1);
}
else if (datatype == opencv_onnx::TensorProto_DataType_INT64)
{
blob.create(sizes, CV_32SC1);
int32_t* dst = reinterpret_cast<int32_t*>(blob.data);
if (!tensor_proto.int64_data().empty()) {
::google::protobuf::RepeatedField< ::google::protobuf::int64> src = tensor_proto.int64_data();
convertInt64ToInt32(src, dst, blob.total());
}
else
{
const char* val = tensor_proto.raw_data().c_str();
#if CV_STRONG_ALIGNMENT
// Aligned pointer is required: https://github.com/opencv/opencv/issues/16373
// this doesn't work: typedef int64_t CV_DECL_ALIGNED(1) unaligned_int64_t;
AutoBuffer<int64_t, 16> aligned_val;
if (!isAligned<sizeof(int64_t)>(val))
{
size_t sz = tensor_proto.raw_data().size();
aligned_val.allocate(divUp(sz, sizeof(int64_t)));
memcpy(aligned_val.data(), val, sz);
val = (const char*)aligned_val.data();
}
#endif
const int64_t* src = reinterpret_cast<const int64_t*>(val);
convertInt64ToInt32(src, dst, blob.total());
}
}
else
CV_Error(Error::StsUnsupportedFormat, "Unsupported data type: " +
opencv_onnx::TensorProto_DataType_Name(datatype));
if (tensor_proto.dims_size() == 0)
blob.dims = 1; // To force 1-dimensional cv::Mat for scalars.
return blob;
}
void runLayer(LayerParams& params, const std::vector<Mat>& inputs,
std::vector<Mat>& outputs)
{
@@ -542,31 +465,6 @@ void ONNXImporter::populateNet(Net dstNet)
layerParams.blobs.push_back(-1.0f * blob.reshape(1, 1));
}
}
else if (layer_type == "Div")
{
if (constBlobs.find(node_proto.input(1)) == constBlobs.end())
{
layerParams.type = "Eltwise";
layerParams.set("operation", "div");
}
else
{
Mat blob = getBlob(node_proto, constBlobs, 1);
CV_Assert_N(blob.type() == CV_32F, blob.total());
if (blob.total() == 1)
{
layerParams.set("scale", 1.0f / blob.at<float>(0));
layerParams.type = "Power";
}
else
{
layerParams.type = "Scale";
divide(1.0, blob, blob);
layerParams.blobs.push_back(blob);
layerParams.set("bias_term", false);
}
}
}
else if (layer_type == "Neg")
{
layerParams.type = "Power";
@@ -715,24 +613,58 @@ void ONNXImporter::populateNet(Net dstNet)
layerParams.set("bias_term", false);
layerParams.set("num_output", layerParams.blobs[0].size[0]);
}
else if (layer_type == "Mul")
else if (layer_type == "Mul" || layer_type == "Div")
{
CV_Assert(node_proto.input_size() == 2);
if (layer_id.find(node_proto.input(1)) == layer_id.end()) {
Mat blob = getBlob(node_proto, constBlobs, 1);
bool isDiv = layer_type == "Div";
int constId = -1;
bool haveVariables = false;
for (int i = 0; i < 2; ++i)
{
if (constBlobs.find(node_proto.input(i)) != constBlobs.end())
constId = i;
else
haveVariables = true;
}
if (constId != -1 && haveVariables)
{
Mat blob = getBlob(node_proto, constBlobs, constId);
blob = blob.reshape(1, 1);
if (blob.total() == 1) {
layerParams.set("scale", blob.at<float>(0));
float coeff = isDiv ? 1.0 / blob.at<float>(0) : blob.at<float>(0);
layerParams.set("scale", coeff);
layerParams.type = "Power";
}
else {
if (isDiv)
divide(1.0, blob, blob);
layerParams.blobs.push_back(blob);
layerParams.type = "Scale";
}
}
else {
layerParams.type = "Eltwise";
layerParams.set("operation", "prod");
layerParams.set("operation", isDiv ? "div" : "prod");
}
if (!haveVariables)
{
Mat inp0 = getBlob(node_proto, constBlobs, 0);
Mat inp1 = getBlob(node_proto, constBlobs, 1);
if (inp0.size != inp1.size)
CV_Error(Error::StsNotImplemented, "Constant multiply with different shapes");
Mat out;
if (isDiv)
divide(inp0, inp1, out);
else
multiply(inp0, inp1, out);
out = out.reshape(1, inp0.dims, inp0.size);
out.dims = inp0.dims; // to workaround dims == 1
constBlobs.insert(std::make_pair(layerParams.name, out));
continue;
}
}
else if (layer_type == "Conv")
@@ -69,9 +69,15 @@ public:
return net.node_size();
}
virtual std::string getNodeName(int idx) const CV_OVERRIDE
virtual int getNumOutputs(int nodeId) const CV_OVERRIDE
{
return net.node(idx).name();
return 1;
}
virtual std::string getOutputName(int nodeId, int outId) const CV_OVERRIDE
{
CV_Assert(outId == 0);
return net.node(nodeId).name();
}
virtual void removeNode(int idx) CV_OVERRIDE
+12
View File
@@ -340,6 +340,16 @@ TEST_P(Test_ONNX_layers, Resize)
testONNXModels("resize_bilinear");
}
TEST_P(Test_ONNX_layers, ResizeUnfused)
{
if (backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_NN_BUILDER);
testONNXModels("upsample_unfused_torch1.2");
testONNXModels("upsample_unfused_opset9_torch1.4");
testONNXModels("resize_nearest_unfused_opset11_torch1.4");
testONNXModels("resize_nearest_unfused_opset11_torch1.3");
}
TEST_P(Test_ONNX_layers, MultyInputs)
{
const String model = _tf("models/multy_inputs.onnx");
@@ -397,6 +407,8 @@ TEST_P(Test_ONNX_layers, DynamicReshape)
if (target == DNN_TARGET_OPENCL) applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL, CV_TEST_TAG_DNN_SKIP_IE_NN_BUILDER);
}
testONNXModels("dynamic_reshape");
testONNXModels("dynamic_reshape_opset_11");
testONNXModels("flatten_by_prod");
}
TEST_P(Test_ONNX_layers, Reshape)
+14 -1
View File
@@ -39,10 +39,23 @@ PERF_TEST_P(Size_MatType_OutMatDepth, integral,
Mat sum(sz, sdepth);
declare.in(src, WARMUP_RNG).out(sum);
if (sdepth == CV_32F)
src *= (1 << 23) / (double)(sz.area() * 256); // FP32 calculations are not accurate (mantissa is 23-bit)
TEST_CYCLE() integral(src, sum, sdepth);
SANITY_CHECK(sum, 1e-6);
Mat src_roi; src(Rect(src.cols - 4, src.rows - 4, 4, 4)).convertTo(src_roi, sdepth);
Mat restored_src_roi =
sum(Rect(sum.cols - 4, sum.rows - 4, 4, 4)) + sum(Rect(sum.cols - 5, sum.rows - 5, 4, 4)) -
sum(Rect(sum.cols - 4, sum.rows - 5, 4, 4)) - sum(Rect(sum.cols - 5, sum.rows - 4, 4, 4));
EXPECT_EQ(0, cvtest::norm(restored_src_roi, src_roi, NORM_INF))
<< src_roi << endl << restored_src_roi << endl
<< sum(Rect(sum.cols - 4, sum.rows - 4, 4, 4));
if (sdepth == CV_32F)
SANITY_CHECK_NOTHING();
else
SANITY_CHECK(sum, 1e-6);
}
PERF_TEST_P(Size_MatType_OutMatDepth, integral_sqsum,
+15 -3
View File
@@ -237,7 +237,11 @@ struct Integral_SIMD<uchar, int, double>
v_int32 prev_1 = vx_setzero_s32(), prev_2 = vx_setzero_s32(),
prev_3 = vx_setzero_s32();
int j = 0;
for ( ; j + v_uint16::nlanes * cn <= width; j += v_uint16::nlanes * cn)
const int j_max =
((_srcstep * i + (width - v_uint16::nlanes * cn + v_uint8::nlanes * cn)) >= _srcstep * height)
? width - v_uint8::nlanes * cn // uint8 in v_load_deinterleave()
: width - v_uint16::nlanes * cn; // v_expand_low
for ( ; j <= j_max; j += v_uint16::nlanes * cn)
{
v_uint8 v_src_row_1, v_src_row_2, v_src_row_3;
v_load_deinterleave(src_row + j, v_src_row_1, v_src_row_2, v_src_row_3);
@@ -546,7 +550,11 @@ struct Integral_SIMD<uchar, float, double>
v_float32 prev_1 = vx_setzero_f32(), prev_2 = vx_setzero_f32(),
prev_3 = vx_setzero_f32();
int j = 0;
for (; j + v_uint16::nlanes * cn <= width; j += v_uint16::nlanes * cn)
const int j_max =
((_srcstep * i + (width - v_uint16::nlanes * cn + v_uint8::nlanes * cn)) >= _srcstep * height)
? width - v_uint8::nlanes * cn // uint8 in v_load_deinterleave()
: width - v_uint16::nlanes * cn; // v_expand_low
for ( ; j <= j_max; j += v_uint16::nlanes * cn)
{
v_uint8 v_src_row_1, v_src_row_2, v_src_row_3;
v_load_deinterleave(src_row + j, v_src_row_1, v_src_row_2, v_src_row_3);
@@ -896,7 +904,11 @@ struct Integral_SIMD<uchar, double, double>
v_float64 prev_1 = vx_setzero_f64(), prev_2 = vx_setzero_f64(),
prev_3 = vx_setzero_f64();
int j = 0;
for (; j + v_uint16::nlanes * cn <= width; j += v_uint16::nlanes * cn)
const int j_max =
((_srcstep * i + (width - v_uint16::nlanes * cn + v_uint8::nlanes * cn)) >= _srcstep * height)
? width - v_uint8::nlanes * cn // uint8 in v_load_deinterleave()
: width - v_uint16::nlanes * cn; // v_expand_low
for ( ; j <= j_max; j += v_uint16::nlanes * cn)
{
v_uint8 v_src_row_1, v_src_row_2, v_src_row_3;
v_load_deinterleave(src_row + j, v_src_row_1, v_src_row_2, v_src_row_3);
+2 -2
View File
@@ -571,8 +571,8 @@ class CppHeaderParser(object):
arg_type, arg_name, modlist, argno = self.parse_arg(a, argno)
if self.wrap_mode:
# TODO: Vectors should contain UMat, but this is not very easy to support and not very needed
vector_mat = "vector_{}".format("Mat")
vector_mat_template = "vector<{}>".format("Mat")
vector_mat = "vector_{}".format(mat)
vector_mat_template = "vector<{}>".format(mat)
if arg_type == "InputArray":
arg_type = mat
+31
View File
@@ -4,8 +4,22 @@ from __future__ import print_function
import numpy as np
import cv2 as cv
import os
from tests_common import NewOpenCVTests
def load_exposure_seq(path):
images = []
times = []
with open(os.path.join(path, 'list.txt'), 'r') as list_file:
for line in list_file.readlines():
name, time = line.split()
images.append(cv.imread(os.path.join(path, name)))
times.append(1. / float(time))
return images, times
class UMat(NewOpenCVTests):
def test_umat_construct(self):
@@ -85,5 +99,22 @@ class UMat(NewOpenCVTests):
for data_umat0, data_umat in zip(_p1_mask_err_umat0[:2], _p1_mask_err_umat[:2]):
self.assertTrue(np.allclose(data_umat0, data_umat))
def test_umat_merge_mertens(self):
if self.extraTestDataPath is None:
self.fail('Test data is not available')
test_data_path = os.path.join(self.extraTestDataPath, 'cv', 'hdr')
images, _ = load_exposure_seq(os.path.join(test_data_path, 'exposures'))
merge = cv.createMergeMertens()
mat_result = merge.process(images)
umat_images = [cv.UMat(img) for img in images]
umat_result = merge.process(umat_images)
self.assertTrue(np.allclose(umat_result.get(), mat_result))
if __name__ == '__main__':
NewOpenCVTests.bootstrap()
+1 -1
View File
@@ -504,7 +504,7 @@ public:
best = *i;
break;
}
if (i->second.isBetterThan(best.second, newType))
if (best.second.isEmpty() || i->second.isBetterThan(best.second, newType))
{
best = *i;
}