mirror of
https://github.com/opencv/opencv.git
synced 2025-06-07 17:44:04 +08:00
dnn: fix High-Level public API (cv::dnn::Model class)
- proxy selected Net methods only (don't derive from Net directly) - default Model ctor is protected
This commit is contained in:
parent
691c3d1e3c
commit
23baf1a75e
@ -1072,14 +1072,17 @@ CV__DNN_INLINE_NS_BEGIN
|
|||||||
* Model creates net from file with trained weights and config,
|
* Model creates net from file with trained weights and config,
|
||||||
* sets preprocessing input and runs forward pass.
|
* sets preprocessing input and runs forward pass.
|
||||||
*/
|
*/
|
||||||
class CV_EXPORTS_W_SIMPLE Model : public Net
|
class CV_EXPORTS_W_SIMPLE Model
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
CV_DEPRECATED_EXTERNAL // avoid using in C++ code, will be moved to "protected" (need to fix bindings first)
|
||||||
* @brief Default constructor.
|
|
||||||
*/
|
|
||||||
Model();
|
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.
|
* @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.
|
* An order of @p model and @p config arguments does not matter.
|
||||||
@ -1100,13 +1103,12 @@ CV__DNN_INLINE_NS_BEGIN
|
|||||||
*/
|
*/
|
||||||
CV_WRAP Model& setInputSize(const Size& size);
|
CV_WRAP Model& setInputSize(const Size& size);
|
||||||
|
|
||||||
/** @brief Set input size for frame.
|
/** @overload
|
||||||
* @param[in] width New input width.
|
* @param[in] width New input width.
|
||||||
* @param[in] height New input height.
|
* @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.
|
/** @brief Set mean value for frame.
|
||||||
* @param[in] mean Scalar with mean values which are subtracted from channels.
|
* @param[in] mean Scalar with mean values which are subtracted from channels.
|
||||||
@ -1143,10 +1145,31 @@ CV__DNN_INLINE_NS_BEGIN
|
|||||||
* @param[in] frame The input image.
|
* @param[in] frame The input image.
|
||||||
* @param[out] outs Allocated output blobs, which will store results of the computation.
|
* @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;
|
struct Impl;
|
||||||
|
inline Impl* getImpl() const { return impl.get(); }
|
||||||
|
inline Impl& getImplRef() const { CV_DbgAssert(impl); return *impl.get(); }
|
||||||
|
protected:
|
||||||
Ptr<Impl> impl;
|
Ptr<Impl> impl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#define OPENCV_DNN_VERSION_HPP
|
#define OPENCV_DNN_VERSION_HPP
|
||||||
|
|
||||||
/// Use with major OpenCV version only.
|
/// 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
|
#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)
|
#define CV__DNN_INLINE_NS __CV_CAT(dnn4_v, OPENCV_DNN_API_VERSION)
|
||||||
|
@ -15,6 +15,9 @@ namespace dnn {
|
|||||||
|
|
||||||
struct Model::Impl
|
struct Model::Impl
|
||||||
{
|
{
|
||||||
|
//protected:
|
||||||
|
Net net;
|
||||||
|
|
||||||
Size size;
|
Size size;
|
||||||
Scalar mean;
|
Scalar mean;
|
||||||
double scale = 1.0;
|
double scale = 1.0;
|
||||||
@ -23,7 +26,70 @@ struct Model::Impl
|
|||||||
Mat blob;
|
Mat blob;
|
||||||
std::vector<String> outNames;
|
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())
|
if (size.empty())
|
||||||
CV_Error(Error::StsBadSize, "Input size not specified");
|
CV_Error(Error::StsBadSize, "Input size not specified");
|
||||||
@ -34,96 +100,115 @@ struct Model::Impl
|
|||||||
// Faster-RCNN or R-FCN
|
// Faster-RCNN or R-FCN
|
||||||
if (net.getLayer(0)->outputNameToIndex("im_info") != -1)
|
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.setInput(imInfo, "im_info");
|
||||||
}
|
}
|
||||||
net.forward(outs, outNames);
|
net.forward(outs, outNames);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Model::Model() : impl(new Impl) {}
|
Model::Model()
|
||||||
|
: impl(makePtr<Impl>())
|
||||||
|
{
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
|
||||||
Model::Model(const String& model, const String& config)
|
Model::Model(const String& model, const String& config)
|
||||||
: Net(readNet(model, config)), impl(new Impl)
|
: Model()
|
||||||
{
|
{
|
||||||
impl->outNames = getUnconnectedOutLayersNames();
|
impl->initNet(readNet(model, config));
|
||||||
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]);
|
|
||||||
};
|
|
||||||
|
|
||||||
Model::Model(const Net& network) : Net(network), impl(new Impl)
|
Model::Model(const Net& network)
|
||||||
|
: Model()
|
||||||
{
|
{
|
||||||
impl->outNames = getUnconnectedOutLayersNames();
|
impl->initNet(network);
|
||||||
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]);
|
|
||||||
};
|
|
||||||
|
|
||||||
Model& Model::setInputSize(const Size& size)
|
Net& Model::getNetwork_() const
|
||||||
{
|
{
|
||||||
impl->size = size;
|
CV_DbgAssert(impl);
|
||||||
|
return impl->getNetwork();
|
||||||
|
}
|
||||||
|
|
||||||
|
Model& Model::setPreferableBackend(Backend backendId)
|
||||||
|
{
|
||||||
|
CV_DbgAssert(impl);
|
||||||
|
impl->setPreferableBackend(backendId);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Model& Model::setPreferableTarget(Target targetId)
|
||||||
|
{
|
||||||
|
CV_DbgAssert(impl);
|
||||||
|
impl->setPreferableTarget(targetId);
|
||||||
return *this;
|
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;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Model& Model::setInputMean(const Scalar& mean)
|
Model& Model::setInputMean(const Scalar& mean)
|
||||||
{
|
{
|
||||||
impl->mean = mean;
|
CV_DbgAssert(impl);
|
||||||
|
impl->setInputMean(mean);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Model& Model::setInputScale(double scale)
|
Model& Model::setInputScale(double scale)
|
||||||
{
|
{
|
||||||
impl->scale = scale;
|
CV_DbgAssert(impl);
|
||||||
|
impl->setInputScale(scale);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Model& Model::setInputCrop(bool crop)
|
Model& Model::setInputCrop(bool crop)
|
||||||
{
|
{
|
||||||
impl->crop = crop;
|
CV_DbgAssert(impl);
|
||||||
|
impl->setInputCrop(crop);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Model& Model::setInputSwapRB(bool swapRB)
|
Model& Model::setInputSwapRB(bool swapRB)
|
||||||
{
|
{
|
||||||
impl->swapRB = swapRB;
|
CV_DbgAssert(impl);
|
||||||
|
impl->setInputSwapRB(swapRB);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::setInputParams(double scale, const Size& size, const Scalar& mean,
|
void Model::setInputParams(double scale, const Size& size, const Scalar& mean,
|
||||||
bool swapRB, bool crop)
|
bool swapRB, bool crop)
|
||||||
{
|
{
|
||||||
impl->size = size;
|
CV_DbgAssert(impl);
|
||||||
impl->mean = mean;
|
impl->setInputParams(scale, size, mean, swapRB, crop);
|
||||||
impl->scale = scale;
|
|
||||||
impl->crop = crop;
|
|
||||||
impl->swapRB = swapRB;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
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::pair<int, float> ClassificationModel::classify(InputArray frame)
|
||||||
{
|
{
|
||||||
std::vector<Mat> outs;
|
std::vector<Mat> outs;
|
||||||
impl->predict(*this, frame.getMat(), outs);
|
impl->processFrame(frame, outs);
|
||||||
CV_Assert(outs.size() == 1);
|
CV_Assert(outs.size() == 1);
|
||||||
|
|
||||||
double conf;
|
double conf;
|
||||||
@ -145,11 +230,11 @@ KeypointsModel::KeypointsModel(const Net& network) : Model(network) {};
|
|||||||
std::vector<Point2f> KeypointsModel::estimate(InputArray frame, float thresh)
|
std::vector<Point2f> KeypointsModel::estimate(InputArray frame, float thresh)
|
||||||
{
|
{
|
||||||
|
|
||||||
int frameHeight = frame.getMat().size[0];
|
int frameHeight = frame.rows();
|
||||||
int frameWidth = frame.getMat().size[1];
|
int frameWidth = frame.cols();
|
||||||
std::vector<Mat> outs;
|
std::vector<Mat> outs;
|
||||||
|
|
||||||
impl->predict(*this, frame.getMat(), outs);
|
impl->processFrame(frame, outs);
|
||||||
CV_Assert(outs.size() == 1);
|
CV_Assert(outs.size() == 1);
|
||||||
Mat output = outs[0];
|
Mat output = outs[0];
|
||||||
|
|
||||||
@ -202,9 +287,8 @@ SegmentationModel::SegmentationModel(const Net& network) : Model(network) {};
|
|||||||
|
|
||||||
void SegmentationModel::segment(InputArray frame, OutputArray mask)
|
void SegmentationModel::segment(InputArray frame, OutputArray mask)
|
||||||
{
|
{
|
||||||
|
|
||||||
std::vector<Mat> outs;
|
std::vector<Mat> outs;
|
||||||
impl->predict(*this, frame.getMat(), outs);
|
impl->processFrame(frame, outs);
|
||||||
CV_Assert(outs.size() == 1);
|
CV_Assert(outs.size() == 1);
|
||||||
Mat score = outs[0];
|
Mat score = outs[0];
|
||||||
|
|
||||||
@ -250,12 +334,14 @@ void disableRegionNMS(Net& net)
|
|||||||
}
|
}
|
||||||
|
|
||||||
DetectionModel::DetectionModel(const String& model, const String& config)
|
DetectionModel::DetectionModel(const String& model, const String& config)
|
||||||
: Model(model, config) {
|
: Model(model, config)
|
||||||
disableRegionNMS(*this);
|
{
|
||||||
|
disableRegionNMS(getNetwork_()); // FIXIT Move to DetectionModel::Impl::initNet()
|
||||||
}
|
}
|
||||||
|
|
||||||
DetectionModel::DetectionModel(const Net& network) : Model(network) {
|
DetectionModel::DetectionModel(const Net& network) : Model(network)
|
||||||
disableRegionNMS(*this);
|
{
|
||||||
|
disableRegionNMS(getNetwork_()); // FIXIT Move to DetectionModel::Impl::initNet()
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetectionModel::detect(InputArray frame, CV_OUT std::vector<int>& classIds,
|
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)
|
float confThreshold, float nmsThreshold)
|
||||||
{
|
{
|
||||||
std::vector<Mat> detections;
|
std::vector<Mat> detections;
|
||||||
impl->predict(*this, frame.getMat(), detections);
|
impl->processFrame(frame, detections);
|
||||||
|
|
||||||
boxes.clear();
|
boxes.clear();
|
||||||
confidences.clear();
|
confidences.clear();
|
||||||
@ -271,15 +357,15 @@ void DetectionModel::detect(InputArray frame, CV_OUT std::vector<int>& classIds,
|
|||||||
|
|
||||||
int frameWidth = frame.cols();
|
int frameWidth = frame.cols();
|
||||||
int frameHeight = frame.rows();
|
int frameHeight = frame.rows();
|
||||||
if (getLayer(0)->outputNameToIndex("im_info") != -1)
|
if (getNetwork_().getLayer(0)->outputNameToIndex("im_info") != -1)
|
||||||
{
|
{
|
||||||
frameWidth = impl->size.width;
|
frameWidth = impl->size.width;
|
||||||
frameHeight = impl->size.height;
|
frameHeight = impl->size.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<String> layerNames = getLayerNames();
|
std::vector<String> layerNames = getNetwork_().getLayerNames();
|
||||||
int lastLayerId = getLayerId(layerNames.back());
|
int lastLayerId = getNetwork_().getLayerId(layerNames.back());
|
||||||
Ptr<Layer> lastLayer = getLayer(lastLayerId);
|
Ptr<Layer> lastLayer = getNetwork_().getLayer(lastLayerId);
|
||||||
|
|
||||||
if (lastLayer->type == "DetectionOutput")
|
if (lastLayer->type == "DetectionOutput")
|
||||||
{
|
{
|
||||||
|
@ -563,7 +563,7 @@ TEST_P(Test_Caffe_nets, DenseNet_121)
|
|||||||
}
|
}
|
||||||
normAssert(outs[0], ref, "", l1, lInf);
|
normAssert(outs[0], ref, "", l1, lInf);
|
||||||
if (target != DNN_TARGET_MYRIAD || getInferenceEngineVPUType() != CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X)
|
if (target != DNN_TARGET_MYRIAD || getInferenceEngineVPUType() != CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X)
|
||||||
expectNoFallbacksFromIE(model);
|
expectNoFallbacksFromIE(model.getNetwork_());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Test_Caffe, multiple_inputs)
|
TEST(Test_Caffe, multiple_inputs)
|
||||||
|
Loading…
Reference in New Issue
Block a user