mirror of
https://github.com/opencv/opencv.git
synced 2025-01-18 22:44:02 +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,
|
||||
* 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.
|
||||
@ -1100,13 +1103,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.
|
||||
@ -1143,10 +1145,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
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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…
Reference in New Issue
Block a user