Merge pull request #18711 from alalek:dnn_fix_model_public_api

pull/18842/head
Alexander Alekhin 4 years ago
commit 9acbfc6e05
  1. 43
      modules/dnn/include/opencv2/dnn/dnn.hpp
  2. 2
      modules/dnn/include/opencv2/dnn/version.hpp
  3. 188
      modules/dnn/src/model.cpp
  4. 2
      modules/dnn/test/test_caffe_importer.cpp

@ -1074,14 +1074,17 @@ CV__DNN_INLINE_NS_BEGIN
* Model creates net from file with trained weights and config,
* sets preprocessing input and runs forward pass.
*/
class CV_EXPORTS_W_SIMPLE Model : public Net
class CV_EXPORTS_W_SIMPLE Model
{
public:
/**
* @brief Default constructor.
*/
CV_DEPRECATED_EXTERNAL // avoid using in C++ code, will be moved to "protected" (need to fix bindings first)
Model();
Model(const Model&) = default;
Model(Model&&) = default;
Model& operator=(const Model&) = default;
Model& operator=(Model&&) = default;
/**
* @brief Create model from deep learning network represented in one of the supported formats.
* An order of @p model and @p config arguments does not matter.
@ -1102,13 +1105,12 @@ CV__DNN_INLINE_NS_BEGIN
*/
CV_WRAP Model& setInputSize(const Size& size);
/** @brief Set input size for frame.
/** @overload
* @param[in] width New input width.
* @param[in] height New input height.
* @note If shape of the new blob less than 0,
* then frame size not change.
*/
CV_WRAP Model& setInputSize(int width, int height);
CV_WRAP inline
Model& setInputSize(int width, int height) { return setInputSize(Size(width, height)); }
/** @brief Set mean value for frame.
* @param[in] mean Scalar with mean values which are subtracted from channels.
@ -1145,10 +1147,31 @@ CV__DNN_INLINE_NS_BEGIN
* @param[in] frame The input image.
* @param[out] outs Allocated output blobs, which will store results of the computation.
*/
CV_WRAP void predict(InputArray frame, OutputArrayOfArrays outs);
CV_WRAP void predict(InputArray frame, OutputArrayOfArrays outs) const;
// ============================== Net proxy methods ==============================
// Never expose methods with network implementation details, like:
// - addLayer, addLayerToPrev, connect, setInputsNames, setInputShape, setParam, getParam
// - getLayer*, getUnconnectedOutLayers, getUnconnectedOutLayersNames, getLayersShapes
// - forward* methods, setInput
/// @sa Net::setPreferableBackend
CV_WRAP Model& setPreferableBackend(dnn::Backend backendId);
/// @sa Net::setPreferableTarget
CV_WRAP Model& setPreferableTarget(dnn::Target targetId);
CV_DEPRECATED_EXTERNAL
operator Net&() const { return getNetwork_(); }
//protected: - internal/tests usage only
Net& getNetwork_() const;
inline Net& getNetwork_() { return const_cast<const Model*>(this)->getNetwork_(); }
protected:
struct Impl;
inline Impl* getImpl() const { return impl.get(); }
inline Impl& getImplRef() const { CV_DbgAssert(impl); return *impl.get(); }
protected:
Ptr<Impl> impl;
};

@ -6,7 +6,7 @@
#define OPENCV_DNN_VERSION_HPP
/// Use with major OpenCV version only.
#define OPENCV_DNN_API_VERSION 20200908
#define OPENCV_DNN_API_VERSION 20201117
#if !defined CV_DOXYGEN && !defined CV_STATIC_ANALYSIS && !defined CV_DNN_DONT_ADD_INLINE_NS
#define CV__DNN_INLINE_NS __CV_CAT(dnn4_v, OPENCV_DNN_API_VERSION)

@ -15,6 +15,9 @@ namespace dnn {
struct Model::Impl
{
//protected:
Net net;
Size size;
Scalar mean;
double scale = 1.0;
@ -23,7 +26,70 @@ struct Model::Impl
Mat blob;
std::vector<String> outNames;
void predict(Net& net, const Mat& frame, OutputArrayOfArrays outs)
public:
virtual ~Impl() {}
Impl() {}
Impl(const Impl&) = delete;
Impl(Impl&&) = delete;
virtual Net& getNetwork() const { return const_cast<Net&>(net); }
virtual void setPreferableBackend(Backend backendId) { net.setPreferableBackend(backendId); }
virtual void setPreferableTarget(Target targetId) { net.setPreferableTarget(targetId); }
/*virtual*/
void initNet(const Net& network)
{
net = network;
outNames = net.getUnconnectedOutLayersNames();
std::vector<MatShape> inLayerShapes;
std::vector<MatShape> outLayerShapes;
net.getLayerShapes(MatShape(), 0, inLayerShapes, outLayerShapes);
if (!inLayerShapes.empty() && inLayerShapes[0].size() == 4)
size = Size(inLayerShapes[0][3], inLayerShapes[0][2]);
else
size = Size();
}
/*virtual*/
void setInputParams(double scale_, const Size& size_, const Scalar& mean_,
bool swapRB_, bool crop_)
{
size = size_;
mean = mean_;
scale = scale_;
crop = crop_;
swapRB = swapRB_;
}
/*virtual*/
void setInputSize(const Size& size_)
{
size = size_;
}
/*virtual*/
void setInputMean(const Scalar& mean_)
{
mean = mean_;
}
/*virtual*/
void setInputScale(double scale_)
{
scale = scale_;
}
/*virtual*/
void setInputCrop(bool crop_)
{
crop = crop_;
}
/*virtual*/
void setInputSwapRB(bool swapRB_)
{
swapRB = swapRB_;
}
/*virtual*/
void processFrame(InputArray frame, OutputArrayOfArrays outs)
{
if (size.empty())
CV_Error(Error::StsBadSize, "Input size not specified");
@ -34,96 +100,115 @@ struct Model::Impl
// Faster-RCNN or R-FCN
if (net.getLayer(0)->outputNameToIndex("im_info") != -1)
{
Mat imInfo = (Mat_<float>(1, 3) << size.height, size.width, 1.6f);
Mat imInfo(Matx31f(size.height, size.width, 1.6f));
net.setInput(imInfo, "im_info");
}
net.forward(outs, outNames);
}
};
Model::Model() : impl(new Impl) {}
Model::Model()
: impl(makePtr<Impl>())
{
// nothing
}
Model::Model(const String& model, const String& config)
: Net(readNet(model, config)), impl(new Impl)
: Model()
{
impl->outNames = getUnconnectedOutLayersNames();
std::vector<MatShape> inLayerShapes;
std::vector<MatShape> outLayerShapes;
getLayerShapes(MatShape(), 0, inLayerShapes, outLayerShapes);
if (!inLayerShapes.empty() && inLayerShapes[0].size() == 4)
impl->size = Size(inLayerShapes[0][3], inLayerShapes[0][2]);
};
impl->initNet(readNet(model, config));
}
Model::Model(const Net& network) : Net(network), impl(new Impl)
Model::Model(const Net& network)
: Model()
{
impl->outNames = getUnconnectedOutLayersNames();
std::vector<MatShape> inLayerShapes;
std::vector<MatShape> outLayerShapes;
getLayerShapes(MatShape(), 0, inLayerShapes, outLayerShapes);
if (!inLayerShapes.empty() && inLayerShapes[0].size() == 4)
impl->size = Size(inLayerShapes[0][3], inLayerShapes[0][2]);
};
impl->initNet(network);
}
Model& Model::setInputSize(const Size& size)
Net& Model::getNetwork_() const
{
CV_DbgAssert(impl);
return impl->getNetwork();
}
Model& Model::setPreferableBackend(Backend backendId)
{
CV_DbgAssert(impl);
impl->setPreferableBackend(backendId);
return *this;
}
Model& Model::setPreferableTarget(Target targetId)
{
impl->size = size;
CV_DbgAssert(impl);
impl->setPreferableTarget(targetId);
return *this;
}
Model& Model::setInputSize(int width, int height)
Model& Model::setInputSize(const Size& size)
{
impl->size = Size(width, height);
CV_DbgAssert(impl);
impl->setInputSize(size);
return *this;
}
Model& Model::setInputMean(const Scalar& mean)
{
impl->mean = mean;
CV_DbgAssert(impl);
impl->setInputMean(mean);
return *this;
}
Model& Model::setInputScale(double scale)
{
impl->scale = scale;
CV_DbgAssert(impl);
impl->setInputScale(scale);
return *this;
}
Model& Model::setInputCrop(bool crop)
{
impl->crop = crop;
CV_DbgAssert(impl);
impl->setInputCrop(crop);
return *this;
}
Model& Model::setInputSwapRB(bool swapRB)
{
impl->swapRB = swapRB;
CV_DbgAssert(impl);
impl->setInputSwapRB(swapRB);
return *this;
}
void Model::setInputParams(double scale, const Size& size, const Scalar& mean,
bool swapRB, bool crop)
{
impl->size = size;
impl->mean = mean;
impl->scale = scale;
impl->crop = crop;
impl->swapRB = swapRB;
CV_DbgAssert(impl);
impl->setInputParams(scale, size, mean, swapRB, crop);
}
void Model::predict(InputArray frame, OutputArrayOfArrays outs)
void Model::predict(InputArray frame, OutputArrayOfArrays outs) const
{
impl->predict(*this, frame.getMat(), outs);
CV_DbgAssert(impl);
impl->processFrame(frame, outs);
}
ClassificationModel::ClassificationModel(const String& model, const String& config)
: Model(model, config) {};
: Model(model, config)
{
// nothing
}
ClassificationModel::ClassificationModel(const Net& network) : Model(network) {};
ClassificationModel::ClassificationModel(const Net& network)
: Model(network)
{
// nothing
}
std::pair<int, float> ClassificationModel::classify(InputArray frame)
{
std::vector<Mat> outs;
impl->predict(*this, frame.getMat(), outs);
impl->processFrame(frame, outs);
CV_Assert(outs.size() == 1);
double conf;
@ -145,11 +230,11 @@ KeypointsModel::KeypointsModel(const Net& network) : Model(network) {};
std::vector<Point2f> KeypointsModel::estimate(InputArray frame, float thresh)
{
int frameHeight = frame.getMat().size[0];
int frameWidth = frame.getMat().size[1];
int frameHeight = frame.rows();
int frameWidth = frame.cols();
std::vector<Mat> outs;
impl->predict(*this, frame.getMat(), outs);
impl->processFrame(frame, outs);
CV_Assert(outs.size() == 1);
Mat output = outs[0];
@ -202,9 +287,8 @@ SegmentationModel::SegmentationModel(const Net& network) : Model(network) {};
void SegmentationModel::segment(InputArray frame, OutputArray mask)
{
std::vector<Mat> outs;
impl->predict(*this, frame.getMat(), outs);
impl->processFrame(frame, outs);
CV_Assert(outs.size() == 1);
Mat score = outs[0];
@ -250,12 +334,14 @@ void disableRegionNMS(Net& net)
}
DetectionModel::DetectionModel(const String& model, const String& config)
: Model(model, config) {
disableRegionNMS(*this);
: Model(model, config)
{
disableRegionNMS(getNetwork_()); // FIXIT Move to DetectionModel::Impl::initNet()
}
DetectionModel::DetectionModel(const Net& network) : Model(network) {
disableRegionNMS(*this);
DetectionModel::DetectionModel(const Net& network) : Model(network)
{
disableRegionNMS(getNetwork_()); // FIXIT Move to DetectionModel::Impl::initNet()
}
void DetectionModel::detect(InputArray frame, CV_OUT std::vector<int>& classIds,
@ -263,7 +349,7 @@ void DetectionModel::detect(InputArray frame, CV_OUT std::vector<int>& classIds,
float confThreshold, float nmsThreshold)
{
std::vector<Mat> detections;
impl->predict(*this, frame.getMat(), detections);
impl->processFrame(frame, detections);
boxes.clear();
confidences.clear();
@ -271,15 +357,15 @@ void DetectionModel::detect(InputArray frame, CV_OUT std::vector<int>& classIds,
int frameWidth = frame.cols();
int frameHeight = frame.rows();
if (getLayer(0)->outputNameToIndex("im_info") != -1)
if (getNetwork_().getLayer(0)->outputNameToIndex("im_info") != -1)
{
frameWidth = impl->size.width;
frameHeight = impl->size.height;
}
std::vector<String> layerNames = getLayerNames();
int lastLayerId = getLayerId(layerNames.back());
Ptr<Layer> lastLayer = getLayer(lastLayerId);
std::vector<String> layerNames = getNetwork_().getLayerNames();
int lastLayerId = getNetwork_().getLayerId(layerNames.back());
Ptr<Layer> lastLayer = getNetwork_().getLayer(lastLayerId);
if (lastLayer->type == "DetectionOutput")
{

@ -563,7 +563,7 @@ TEST_P(Test_Caffe_nets, DenseNet_121)
}
normAssert(outs[0], ref, "", l1, lInf);
if (target != DNN_TARGET_MYRIAD || getInferenceEngineVPUType() != CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X)
expectNoFallbacksFromIE(model);
expectNoFallbacksFromIE(model.getNetwork_());
}
TEST(Test_Caffe, multiple_inputs)

Loading…
Cancel
Save