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

Merge pull request #28855 from omrope79:wechat-fix-layers

Add Prior Box Layer to support the WeChat QR model #28855

OpenCV extra: https://github.com/opencv/opencv_extra/pull/1349

### Pull Request Readiness Checklist

This PR is part 1 of the split from the original PR: WeChatQR-fix conversion Caffe to ONNX #28746.
It focuses on adding the PriorBox layer and its related unit tests. The WeChatQR specific changes will be submitted in a separate PR.
See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [x] There is a reference to the original bug report and related work
- [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [x] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
omrope79
2026-04-27 20:42:58 +05:30
committed by GitHub
parent 0ba385abe4
commit 237be03b7e
3 changed files with 59 additions and 1 deletions
+16 -1
View File
@@ -192,8 +192,23 @@ public:
}
}
PriorBoxLayerImpl(const LayerParams &params)
static LayerParams normalizeONNXParams(const LayerParams& params)
{
LayerParams p = params;
auto remap = [&](const std::string& from, const std::string& to) {
if (p.has(from) && !p.has(to))
p.set(to, p.get(from));
};
remap("variances", "variance");
remap("min_sizes", "min_size");
remap("max_sizes", "max_size");
remap("aspect_ratios", "aspect_ratio");
return p;
}
PriorBoxLayerImpl(const LayerParams &params_)
{
const LayerParams params = normalizeONNXParams(params_);
setParamsFrom(params);
_flip = getParameter<bool>(params, "flip", 0, false, true);
_clip = getParameter<bool>(params, "clip", 0, false, true);
+13
View File
@@ -189,6 +189,7 @@ protected:
void parseCumSum (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseDepthSpaceOps (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseDetectionOutput (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parsePriorBox (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseEinsum (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseElementWise (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseElu (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
@@ -1913,6 +1914,17 @@ void ONNXImporter2::parseSoftMax(LayerParams& layerParams, const opencv_onnx::No
void ONNXImporter2::parseDetectionOutput(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto)
{
CV_CheckEQ(node_proto.input_size(), 3, "");
if (layerParams.has("code_type"))
{
int ct = layerParams.get<int>("code_type");
layerParams.set("code_type", ct == 2 ? "CENTER_SIZE" : "CORNER");
}
addLayer(layerParams, node_proto);
}
void ONNXImporter2::parsePriorBox(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto)
{
layerParams.type = "PriorBox";
addLayer(layerParams, node_proto);
}
@@ -2759,6 +2771,7 @@ void ONNXImporter2::buildDispatchMap_ONNX_AI()
dispatch["NonMaxSuprression"] = &ONNXImporter2::parseNonMaxSuprression;
dispatch["SoftMax"] = dispatch["Softmax"] = dispatch["LogSoftmax"] = &ONNXImporter2::parseSoftMax;
dispatch["DetectionOutput"] = &ONNXImporter2::parseDetectionOutput;
dispatch["PriorBox"] = &ONNXImporter2::parsePriorBox;
dispatch["CumSum"] = &ONNXImporter2::parseCumSum;
dispatch["SpaceToDepth"] = dispatch["DepthToSpace"] = &ONNXImporter2::parseDepthSpaceOps;
dispatch["ScatterElements"] = dispatch["Scatter"] = dispatch["ScatterND"] = &ONNXImporter2::parseScatter;
+30
View File
@@ -1179,6 +1179,11 @@ TEST_P(Test_ONNX_layers, Resize_HumanSeg)
testONNXModels("resize_humanseg");
}
TEST_P(Test_ONNX_layers, Resample)
{
testONNXModels("nearest", npy, 0, 0, false, false);
}
TEST_P(Test_ONNX_layers, Div)
{
const String model = _tf("models/div.onnx");
@@ -2293,6 +2298,31 @@ TEST_P(Test_ONNX_layers, QLinearSoftmax)
testONNXModels("qlinearsoftmax_v13", npy, 0.002, 0.002);
}
TEST_P(Test_ONNX_layers, PriorBox_ONNX)
{
Net net = readNetFromONNX(_tf("models/prior_box.onnx"));
ASSERT_FALSE(net.empty());
int inp_size[] = {1, 3, 10, 10};
int shape_size[] = {1, 2, 3, 4};
Mat inp(4, inp_size, CV_32F, Scalar(0));
Mat shape(4, shape_size, CV_32F, Scalar(0));
net.setInput(inp, "input_0");
net.setInput(shape, "input_1");
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat out = net.forward();
Mat ref = blobFromNPY(_tf("data/output_prior_box.npy"));
double l1 = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 1e-3 : 1e-5;
double lInf = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 1e-3 : 1e-4;
if (target == DNN_TARGET_CUDA_FP16)
{
l1 = 7e-5;
lInf = 0.0005;
}
normAssert(out, ref, "", l1, lInf);
}
INSTANTIATE_TEST_CASE_P(/*nothing*/, Test_ONNX_layers, dnnBackendsAndTargets());
class Test_ONNX_nets : public Test_ONNX_layers