opencv dnn模块 DNN中Layer的动态创建、Net自定义网络搭建示例

文章目录

      • 一、介绍
      • 二、Net的定义
      • 三、DictValue、Dict、LayerParams
      • 四、网络Net搭建和测试

一、介绍

opencv的dnn模块整体设计与现有的框架如caffe、tensorflow基本类似。
Net用有向无环图(DAG)表示,每一个节点是一个Layer示例,每条有向边都是一个Blob(一个NCWH的Mat)。

使用opencv的dnn功能,多数为直接加载第三方模型,同其他框架类似,opencv的dnn模块也是可以如同搭积木一样,拼装自己的网络结构(官方支持的层、自己注册的层),只是比其他的略复杂而已。后面给出多个例子说明,讲解如何利用opencv dnn模块搭建自己的网络。(仅前向计算)

理论上,只要知道其他网络模型的 网络结构、权重数据,就完全可以在opencv中自定义实现,注意,这里实现指的不是修改opencv的源代码。

二、Net的定义

class CV_EXPORTS_W_SIMPLE Net
{
   
public:

    CV_WRAP Net();  //!< 默认构造函数
    CV_WRAP ~Net(); //!< 默认析构函数;引用计数为0则析构
    //使用Inter model优化器的中间表示来创建网络;
    //xml是网络拓扑结构的XML配置文件
    //bin是model的model的二进制文件
    //使用Inter model优化器创建网络,OpenCV会使用inter的推理引擎后端进行推理;    
    CV_WRAP static Net readFromModelOptimizer(const String& xml, const String& bin);

    //测试网络中是否有layer,是否为空;若没有layer则返回true
    CV_WRAP bool empty() const;

    //向网络中添加新的layer;
    //name是layer的名字,是唯一的;
    //type是网络的类型,卷积层还是relu等;但是必须是OpenCV支持的层,或者自己实现的,在层注册器中注册过的类型;
    //params是层的参数,用于初始化该层;
    //返回值为该层唯一的整数ID;若返回-1表示添加失败
    int addLayer(const String &name, const String &type, LayerParams &params);

    //添加新层,将其第一个输入与上一层第一个输出相连接;
    //参数与addLayer函数相同;
    int addLayerToPrev(const String &name, const String &type, LayerParams &params);

    //转换layer的string name ;返回整数ID;若为-1,则layer不存在
    CV_WRAP int getLayerId(const String &layer);

	//获取所有layer的string name
    CV_WRAP std::vector<String> getLayerNames() const;

    //字符串和整数及他们的数组的容器
    typedef DictValue LayerId;

	//返回指向网络中指定ID的层的指针,layerId为整数ID或者层名字符串
    CV_WRAP Ptr<Layer> getLayer(LayerId layerId);

    //返回指向特定层的所有输入层的指针
    std::vector<Ptr<Layer> > getLayerInputs(LayerId layerId); // FIXIT: CV_WRAP

    //连接第一个layer的输出到第二个layer的输入
    //outPin 第一个layer输出的描述.
    //inpPin 第二个layer输入的描述.
    //输入的模板为:.[input_num]
    //模板层名称的第一部分是添加层的sting名称。如果该部分为空,则使用网络输入伪层;
    //模板输入编号的第二个可选部分是层输入编号,或者是标签编号。如果省略此部分,则将使 用第一层输入。
    CV_WRAP void connect(String outPin, String inpPin);

    //第一层的输出与第二层输入相连接
    //outLayerId 第一层的标识符
    //outNum 第一层输出的编号(一个层可能会有多个输出)
    //inpLayerId 第二层的标识符
    //inpNum 第二层输入的编号(一个层可能会有多个输入)
    void connect(int outLayerId, int outNum, int inpLayerId, int inpNum);

    //设置网络输入伪层的输出名称
    //每个网络都有自己的输入伪层,id=0
    //该层仅仅存储user的blobs,不进行任何计算
    //这一层提供了用户数据传递到网络中的唯一方法
    //与任何其他层一样,此层可以标记其输出,而此函数提供了一种简单的方法来实现这一点。
	CV_WRAP void setInputsNames(const std::vector<String> &inputBlobNames);

	//根据指定的层进行网路前向计算,并返回指定层名的输出
	// outputName 需要获取指定层输出的名字
	// 返回指定层首次出现的时输出
	// 默认对整个网络进行前向计算
    CV_WRAP Mat forward(const String& outputName = String());
	
	// 同上,outputBlobs为指定层名的所有输出
	CV_WRAP void forward(OutputArrayOfArrays outputBlobs, const String& outputName = String());

	// 根据给定的多个输出层名进行前向运算,并计算所有给定层名首次出现的输出
	CV_WRAP void forward(OutputArrayOfArrays outputBlobs,
                             const std::vector<String>& outBlobNames);
                             
	// 根据给定的多个输出层名进行前向运算,并计算所有给定层名的所有输出
    CV_WRAP_AS(forwardAndRetrieve) void forward(CV_OUT std::vector<std::vector<Mat> >& outputBlobs,
                                                    const std::vector<String>& outBlobNames);

    //编译Halide layers.
    //scheduler : 带有scheduler指令的yaml文件的路径
    //@see setPreferableBackend
    //调度Halide后端支持的层,然后编译
    //对于scheduler中不支持的层,或者完全不使用手动调度的层,会采用自动调度
	CV_WRAP void setHalideScheduler(const String& scheduler);

    //指定使用特定的计算平台运行网络
    //输入是backend的标识符
    //如果使用Intel的推理引擎库编译opencv,则DNN_BACKEND_DEFAULT默认表示
    //DNN_BACKEND_INFERENCE_ENGINE 否则是DNN_BACKEND_OPENCV.
    CV_WRAP void setPreferableBackend(int backendId);

    //指定特定的计算设备
    //输入是目标设备的标识符
    /**
     * List of supported combinations backend / target:
     * |                        | DNN_BACKEND_OPENCV | DNN_BACKEND_INFERENCE_ENGINE | DNN_BACKEND_HALIDE |
     * |------------------------|--------------------|------------------------------|--------------------|
     * | DNN_TARGET_CPU         |                  + |                            + |                  + |
     * | DNN_TARGET_OPENCL      |                  + |                            + |                  + |
     * | DNN_TARGET_OPENCL_FP16 |                  + |                            + |                    |
     * | DNN_TARGET_MYRIAD      |                    |                            + |                    |
    */
    CV_WRAP void setPreferableTarget(int targetId);

	// 设置网络的输入数据
	// blob 数据深度必须是 CV_32F 或 CV_8U 
	// name 设置输入数据的名字,可对应setInputsNames的参数(默认是仅一个输入)
	// scalefactor 可选缩放参数
    // mean        可选均值参数
    // input(n,c,h,w) = scalefactor*input(n,c,h,w) + mean
    // 注意: 
    //     net默认有一个"_input"层, 这里设置是input实际是"_input"层的输出
    CV_WRAP void setInput(InputArray blob, const String& name = "",
                              double scalefactor = 1.0, const Scalar& mean = Scalar());

    //为layer设置新的参数
	// layer     层的name或id
	// numParam  在 Layer::blobs 数组中的索引
	// blob      学习参数数据
    //如果新blob的形状与前一个形状不同,则以下正向传递可能失败
    CV_WRAP void setParam(LayerId layer, int numParam, const Mat &blob);

	//返回指定层参数的blob
	// 参数同setParam
    CV_WRAP Mat getParam(LayerId layer, int numParam = 0);

	//返回所有无输出的层的索引
    CV_WRAP std::vector<int> getUnconnectedOutLayers() const;

	//返回所有无输出的层的name
    CV_WRAP std::vector<String> getUnconnectedOutLayersNames() const;

    //输出网络中所有layer的input和output的shapes
    //netInputShapes 网络输入层中所有输入块的形状
    // layersIds 返回层的ID
    //inLayersShapes 返回输入层形状 顺序与layersIds的顺序相同
    //outLayersShapes 返回输出层形状 顺序与layersIds的顺序相同
    CV_WRAP void getLayersShapes(const std::vector<MatShape>& netInputShapes,
                     CV_OUT std::vector<int>& layersIds,
                     CV_OUT std::vector<std::vector<MatShape> >& inLayersShapes,
                     CV_OUT std::vector<std::vector<MatShape> >& outLayersShapes) const;

    /** @重载 */
    // 给定输入尺寸,计算网络所有layer的输入和输出形状
    CV_WRAP void getLayersShapes(const MatShape& netInputShape,
     				CV_OUT std::vector<int>& layersIds,
                    CV_OUT std::vector<std::vector<MatShape> >& inLayersShapes,
                    CV_OUT std::vector<std::vector<MatShape> >& outLayersShapes) const;

    //输出网络中指定layer的input和output的shapes
    //netInputShape 网络输入的shapes
    //指定layer的ID
    //inLayerShapes返回指定层input的shapes
    //outLayerShapes返回指定层output的shapes
    void getLayerShapes(const MatShape& netInputShape,
             const int layerId,
             CV_OUT std::vector<MatShape>& inLayerShapes,
             CV_OUT std::vector<MatShape>& outLayerShapes) const; // FIXIT: CV_WRAP

     /** @重载 */
     // 给定输入尺寸,计算指定layer的输入和输出形状
     void getLayerShapes(const std::vector<MatShape>& netInputShapes,
             const int layerId,
             CV_OUT std::vector<MatShape>& inLayerShapes,
             CV_OUT std::vector<MatShape>& outLayerShapes) const; // FIXIT: CV_WRAP

    //计算指定input,运行整个网络的FLOPS
    //netInputShapes 所有输入的shapes
    CV_WRAP int64 getFLOPS(const std::vector<MatShape>& netInputShapes) const;
    /** 重载 */
    CV_WRAP int64 getFLOPS(const MatShape& netInputShape) const;
    //计算指定layer的FLOPS
    CV_WRAP int64 getFLOPS(const int layerId,
                      const std::vector<MatShape>& netInputShapes) const;
    /** 重载 */
    CV_WRAP int64 getFLOPS(const int layerId, const MatShape& netInputShape) const;

    

你可能感兴趣的:(opencv实例源码演示,c/c++,opencv,dnn,自定义网络,Net)