nareshmlx/opencv-pr huggingface dataset:
**File:** samples/dnn/models.yml
**Change Type:** modified
**Context:** PR #24396: using cv2 dnn interface to run yolov8 model

**Code Changes:**
```diff
@@ -33,6 +33,7 @@ yolov4:
   height: 416
   rgb: true
   classes: "object_detection_classes_yolo.txt"
+  background_label_id: 0
   sample: "object_detection"
 
 yolov4-tiny:
@@ -47,6 +48,7 @@ yolov4-tiny:
   height: 416
```

Review comment:
Replaced to [URL from opencv_extra](https://github.com/opencv/opencv_extra/blob/0c9ec227253c60165b125c7bce313fc2bb4cb592/testdata/dnn/download_models.py#L1008)
**File:** modules/dnn/src/layers/einsum_layer.cpp
**Change Type:** modified
**Context:** PR #24509: Fast gemm for einsum

**Code Changes:**
```diff
@@ -6,6 +6,7 @@
 #include <opencv2/dnn/shape_utils.hpp>
 #include "../precomp.hpp"
 #include "layers_common.hpp"
+#include "cpu_kernels/fast_gemm.hpp"
 
 namespace cv
 {
@@ -32,111 +33,6 @@ static bool IsTransposeReshapeForEinsum(const std::vector<size_t>& perm,
     return true;
```

Review comment:
I propose to make it layer-wide, but not initialize each time.
**File:** modules/dnn/perf/perf_einsum.cpp
**Change Type:** modified
**Context:** PR #24509: Fast gemm for einsum

**Code Changes:**
```diff
@@ -11,19 +11,16 @@ struct EinsumParams {
     int outputSize;
     std::string equation;
     std::vector<MatShape> einsumInpShapes;
-    EinsumParams(std::string equation_, int inputSize_, int outputSize_,  std::vector<MatShape> einsumInpShapes_ = std::vector<MatShape>())
+    EinsumParams(std::string equation_, std::vector<MatShape> einsumInpShapes_ = std::vector<MatShape>())
     {
-        inputSize = inputSize_;
-        outputSize = outputSize_;
+        inputSize = einsumInpShapes_.size();
```

Review comment:
I think that number of inputs and output is not very informative. Shapes are enough
**File:** modules/dnn/perf/perf_einsum.cpp
**Change Type:** modified
**Context:** PR #24509: Fast gemm for einsum

**Code Changes:**
```diff
@@ -11,19 +11,16 @@ struct EinsumParams {
     int outputSize;
     std::string equation;
     std::vector<MatShape> einsumInpShapes;
-    EinsumParams(std::string equation_, int inputSize_, int outputSize_,  std::vector<MatShape> einsumInpShapes_ = std::vector<MatShape>())
+    EinsumParams(std::string equation_, std::vector<MatShape> einsumInpShapes_ = std::vector<MatShape>())
     {
-        inputSize = inputSize_;
-        outputSize = outputSize_;
+        inputSize = einsumInpShapes_.size();
```

Review comment:
I think that test case is too fast to get reliable perf data
**File:** modules/dnn/perf/perf_einsum.cpp
**Change Type:** modified
**Context:** PR #24509: Fast gemm for einsum
**Review Line:** 57

**Code Changes:**
```diff
 
-    {"...ij, ...jk -> ...ik", 2, 1, {{40, 50}, {50, 80}}},
-    {"...ij, ...jk -> ...ik", 2, 1, {{47, 51}, {51, 83}}},
+    {"...ij, ...jk -> ...ik",  {{40, 50}, {50, 80}}},
+    {"...ij, ...jk -> ...ik",  {{47, 51}, {51, 83}}},
 };
 
 class Layer_Einsum: public TestBaseWithParam<EinsumParams> {};
@@ -68,7 +65,7 @@ PERF_TEST_P_(Layer_Einsum, einsum) {
     lp.name = "testEinsum";
     lp.set("equation", params.equation);
```

Review comment:
inputSize seems redundant as there are input shapes
**File:** modules/dnn/perf/perf_einsum.cpp
**Change Type:** modified
**Context:** PR #24509: Fast gemm for einsum
**Review Line:** 90

**Code Changes:**
```diff
-
-        input_names.emplace_back("input1");
-        input_names.emplace_back("input2");
+        // create input names dynamically, assuming input naming follows a consistent pattern
+        input_names.emplace_back("input" + std::to_string(i + 1));
     }
 
     //warm up
+    std::vector<Mat> outputs;
     net.setInputsNames(input_names);
     for (int i = 0; i < input_names.size(); i++){
```

Review comment:
Can be simplified: ```cpp int id = net.addLayer(lp.name, lp.type, lp); for (int i = 0; i < params.inputSize; ++i) { inputs.emplace_back(Mat(params.einsumInpShapes[i].size(), params.einsumInpShapes[i].data(), CV_32FC1)); net.connect(0, i, id, i); } ```
**File:** modules/dnn/perf/perf_einsum.cpp
**Change Type:** modified
**Context:** PR #24509: Fast gemm for einsum

**Code Changes:**
```diff
@@ -11,19 +11,16 @@ struct EinsumParams {
     int outputSize;
     std::string equation;
     std::vector<MatShape> einsumInpShapes;
-    EinsumParams(std::string equation_, int inputSize_, int outputSize_,  std::vector<MatShape> einsumInpShapes_ = std::vector<MatShape>())
+    EinsumParams(std::string equation_, std::vector<MatShape> einsumInpShapes_ = std::vector<MatShape>())
     {
-        inputSize = inputSize_;
-        outputSize = outputSize_;
+        inputSize = einsumInpShapes_.size();
```

Review comment:
This warmup forward is different from `forward` in TEST_CYCLE
**File:** modules/dnn/perf/perf_einsum.cpp
**Change Type:** modified
**Context:** PR #24509: Fast gemm for einsum

**Code Changes:**
```diff
@@ -11,19 +11,16 @@ struct EinsumParams {
     int outputSize;
     std::string equation;
     std::vector<MatShape> einsumInpShapes;
-    EinsumParams(std::string equation_, int inputSize_, int outputSize_,  std::vector<MatShape> einsumInpShapes_ = std::vector<MatShape>())
+    EinsumParams(std::string equation_, std::vector<MatShape> einsumInpShapes_ = std::vector<MatShape>())
     {
-        inputSize = inputSize_;
-        outputSize = outputSize_;
+        inputSize = einsumInpShapes_.size();
```

Review comment:
Are you suggesting to remove the warm up? Sorry, did not catch it
**File:** modules/dnn/perf/perf_einsum.cpp
**Change Type:** modified
**Context:** PR #24509: Fast gemm for einsum

**Code Changes:**
```diff
@@ -11,19 +11,16 @@ struct EinsumParams {
     int outputSize;
     std::string equation;
     std::vector<MatShape> einsumInpShapes;
-    EinsumParams(std::string equation_, int inputSize_, int outputSize_,  std::vector<MatShape> einsumInpShapes_ = std::vector<MatShape>())
+    EinsumParams(std::string equation_, std::vector<MatShape> einsumInpShapes_ = std::vector<MatShape>())
     {
-        inputSize = inputSize_;
-        outputSize = outputSize_;
+        inputSize = einsumInpShapes_.size();
```

Review comment:
Warmup and test cycle should do the same job.
**File:** modules/dnn/perf/perf_einsum.cpp
**Change Type:** modified
**Context:** PR #24509: Fast gemm for einsum

**Code Changes:**
```diff
@@ -11,19 +11,16 @@ struct EinsumParams {
     int outputSize;
     std::string equation;
     std::vector<MatShape> einsumInpShapes;
-    EinsumParams(std::string equation_, int inputSize_, int outputSize_,  std::vector<MatShape> einsumInpShapes_ = std::vector<MatShape>())
+    EinsumParams(std::string equation_, std::vector<MatShape> einsumInpShapes_ = std::vector<MatShape>())
     {
-        inputSize = inputSize_;
-        outputSize = outputSize_;
+        inputSize = einsumInpShapes_.size();
```

Review comment:
It might depends. Please provide a raw output from performance test to see deviation.
**File:** modules/dnn/src/layers/einsum_layer.cpp
**Change Type:** modified
**Context:** PR #24509: Fast gemm for einsum
**Review Line:** 1

**Code Changes:**
```diff
@@ -6,6 +6,7 @@
 #include <opencv2/dnn/shape_utils.hpp>
 #include "../precomp.hpp"
 #include "layers_common.hpp"
+#include "cpu_kernels/fast_gemm.hpp"
 
 namespace cv
 {
@@ -32,111 +33,6 @@ static bool IsTransposeReshapeForEinsum(const std::vector<size_t>& perm,
     return true;
 }
 
-static Mat batchwiseMatMul(
-    const Mat& input1,
-    const MatShape& input1ShapeOverride,
```

Review comment:
Oh, I see, it was already merged in https://github.com/opencv/opencv/pull/24445
**File:** modules/dnn/src/layers/einsum_layer.cpp
**Change Type:** modified
**Context:** PR #24509: Fast gemm for einsum

**Code Changes:**
```diff
@@ -6,6 +6,7 @@
 #include <opencv2/dnn/shape_utils.hpp>
 #include "../precomp.hpp"
 #include "layers_common.hpp"
+#include "cpu_kernels/fast_gemm.hpp"
 
 namespace cv
 {
@@ -32,111 +33,6 @@ static bool IsTransposeReshapeForEinsum(const std::vector<size_t>& perm,
     return true;
```

Review comment:
You can do it in single line: ``` Mat tmp_output(M, N, reshapedInput1.type()); ```
**File:** modules/dnn/src/layers/einsum_layer.cpp
**Change Type:** modified
**Context:** PR #24509: Fast gemm for einsum

**Code Changes:**
```diff
@@ -6,6 +6,7 @@
 #include <opencv2/dnn/shape_utils.hpp>
 #include "../precomp.hpp"
 #include "layers_common.hpp"
+#include "cpu_kernels/fast_gemm.hpp"
 
 namespace cv
 {
@@ -32,111 +33,6 @@ static bool IsTransposeReshapeForEinsum(const std::vector<size_t>& perm,
     return true;
```

Review comment:
You can do it in single line: ``` Mat tmp_output(M, N, part1.type()); ```
**File:** modules/dnn/src/layers/einsum_layer.cpp
**Change Type:** modified
**Context:** PR #24509: Fast gemm for einsum
**Review Line:** 1296

**Code Changes:**
```diff
         inputSubscriptIndices.reserve(numInputs);
@@ -1389,6 +1293,112 @@ Mat LayerEinsumImpl::pairwiseOperandProcess(
     return output;
 };
 
+Mat LayerEinsumImpl::batchwiseMatMul(
+    const Mat& input1,
+    const MatShape& input1ShapeOverride,
+    const Mat& input2,
+    const MatShape& input2ShapeOverride)
+{
```

Review comment:
Are there any changes in this func? I propose to reduce number of changes and keep implementation in the top of the file (adding `LayerEinsumImpl::`)
**File:** modules/dnn/src/layers/einsum_layer.cpp
**Change Type:** modified
**Context:** PR #24509: Fast gemm for einsum
**Review Line:** 1296

**Code Changes:**
```diff
         inputSubscriptIndices.reserve(numInputs);
@@ -1389,6 +1293,112 @@ Mat LayerEinsumImpl::pairwiseOperandProcess(
     return output;
 };
 
+Mat LayerEinsumImpl::batchwiseMatMul(
+    const Mat& input1,
+    const MatShape& input1ShapeOverride,
+    const Mat& input2,
+    const MatShape& input2ShapeOverride)
+{
```

Review comment:
I checked difference. It's related to fastGemm only.
**File:** modules/dnn/src/layers/einsum_layer.cpp
**Change Type:** modified
**Context:** PR #24509: Fast gemm for einsum

**Code Changes:**
```diff
@@ -6,6 +6,7 @@
 #include <opencv2/dnn/shape_utils.hpp>
 #include "../precomp.hpp"
 #include "layers_common.hpp"
+#include "cpu_kernels/fast_gemm.hpp"
 
 namespace cv
 {
@@ -32,111 +33,6 @@ static bool IsTransposeReshapeForEinsum(const std::vector<size_t>& perm,
     return true;
```

Review comment:
All the entries with `M`, `K`, `N` use `static_cast`. Can they be initialized as `int`?
**File:** modules/dnn/src/layers/einsum_layer.cpp
**Change Type:** modified
**Context:** PR #24509: Fast gemm for einsum
**Review Line:** 1399

**Code Changes:**
```diff
+    Mat output_buffer = Mat::zeros(3, outputDim, CV_32F);
+
+    for (size_t i = 0; i < output.size(); i++) {
+        Mat output_slice = output_buffer.row(i);
+        output[i].copyTo(output_slice);
+    }
+    return output_buffer;
+};
 Ptr<EinsumLayer> EinsumLayer::create(const LayerParams& params)
 {
     return makePtr<LayerEinsumImpl>(params);
```

Review comment:
`hconcat`?
**File:** modules/dnn/src/layers/einsum_layer.cpp
**Change Type:** modified
**Context:** PR #24509: Fast gemm for einsum
**Review Line:** 1399

**Code Changes:**
```diff
+    Mat output_buffer = Mat::zeros(3, outputDim, CV_32F);
+
+    for (size_t i = 0; i < output.size(); i++) {
+        Mat output_slice = output_buffer.row(i);
+        output[i].copyTo(output_slice);
+    }
+    return output_buffer;
+};
 Ptr<EinsumLayer> EinsumLayer::create(const LayerParams& params)
 {
     return makePtr<LayerEinsumImpl>(params);
```

Review comment:
Tried using concat. For some reason it fails the inference. Can you suggest the showcase the usage you had in your mind?
**File:** modules/dnn/src/layers/einsum_layer.cpp
**Change Type:** modified
**Context:** PR #24509: Fast gemm for einsum
**Review Line:** 1399

**Code Changes:**
```diff
+    Mat output_buffer = Mat::zeros(3, outputDim, CV_32F);
+
+    for (size_t i = 0; i < output.size(); i++) {
+        Mat output_slice = output_buffer.row(i);
+        output[i].copyTo(output_slice);
+    }
+    return output_buffer;
+};
 Ptr<EinsumLayer> EinsumLayer::create(const LayerParams& params)
 {
     return makePtr<LayerEinsumImpl>(params);
```

Review comment:
What is error message?
**File:** modules/dnn/src/layers/einsum_layer.cpp
**Change Type:** modified
**Context:** PR #24509: Fast gemm for einsum
**Review Line:** 1399

**Code Changes:**
```diff
+    Mat output_buffer = Mat::zeros(3, outputDim, CV_32F);
+
+    for (size_t i = 0; i < output.size(); i++) {
+        Mat output_slice = output_buffer.row(i);
+        output[i].copyTo(output_slice);
+    }
+    return output_buffer;
+};
 Ptr<EinsumLayer> EinsumLayer::create(const LayerParams& params)
 {
     return makePtr<LayerEinsumImpl>(params);
```

Review comment:
Excuse me, `vconcat` for sure: ```cpp // ... output.emplace_back(tmp_output.reshape(1, 1)); // ... Mat output_buffer; cv::vconcat(output, output_buffer); int outputDim[] = {static_cast<int>(output.size()), M, N}; output_buffer = output_buffer.reshape(1, 3, &outputDim[0]); ```
**File:** modules/objdetect/src/aruco/aruco_detector.cpp
**Change Type:** modified
**Context:** PR #24479: Fix contour filtering in ArUco

**Code Changes:**
```diff
@@ -50,6 +50,7 @@ static inline bool readWrite(DetectorParameters &params, const FileNode* readNod
                                 readNode, writeStorage);
     check |= readWriteParameter("minOtsuStdDev", params.minOtsuStdDev, readNode, writeStorage);
     check |= readWriteParameter("errorCorrectionRate", params.errorCorrectionRate, readNode, writeStorage);
+    check |= readWriteParameter("minGroupDistance", params.minGroupDistance, readNode, writeStorage);
     // new aruco 3 functionality
     check |= readWriteParameter("useAruco3Detection", params.useAruco3Detection, readNode, writeStorage);
     check |= readWriteParameter("minSideLengthCanonicalImg", params.minSideLengthCanonicalImg, readNode, writeStorage);
@@ -212,149 +213,65 @@ static void _reorderCandidatesCorners(vector<vector<Point2f> > &candidates) {
     }
```

Review comment:
const vector<>&
**File:** modules/objdetect/src/aruco/aruco_detector.cpp
**Change Type:** modified
**Context:** PR #24479: Fix contour filtering in ArUco

**Code Changes:**
```diff
@@ -50,6 +50,7 @@ static inline bool readWrite(DetectorParameters &params, const FileNode* readNod
                                 readNode, writeStorage);
     check |= readWriteParameter("minOtsuStdDev", params.minOtsuStdDev, readNode, writeStorage);
     check |= readWriteParameter("errorCorrectionRate", params.errorCorrectionRate, readNode, writeStorage);
+    check |= readWriteParameter("minGroupDistance", params.minGroupDistance, readNode, writeStorage);
     // new aruco 3 functionality
     check |= readWriteParameter("useAruco3Detection", params.useAruco3Detection, readNode, writeStorage);
     check |= readWriteParameter("minSideLengthCanonicalImg", params.minSideLengthCanonicalImg, readNode, writeStorage);
@@ -212,149 +213,65 @@ static void _reorderCandidatesCorners(vector<vector<Point2f> > &candidates) {
     }
```

Review comment:
It's duplicate. Previous instance of the function may be reused.
**File:** modules/objdetect/src/aruco/aruco_detector.cpp
**Change Type:** modified
**Context:** PR #24479: Fix contour filtering in ArUco
**Review Line:** 233

**Code Changes:**
```diff
-                    if(candGroup[i]<0 && candGroup[j]<0){
-                        // mark candidates with their corresponding group number
-                        candGroup[i] = candGroup[j] = (int)groupedCandidates.size();
+struct MarkerCandidate {
+    vector<Point2f> corners;
+    vector<Point> contour;
+    float perimeter = 0.f;
+};
 
-                        // create group
-                        vector<unsigned int> grouped;
```

Review comment:
I propose to use const reference for contours. The candidates may just reference to existing contours candidates. As soon as it's internal function state and it's not exposed as API it's safe and saves a lot of memory. You need to use initializer list in constructor then.
**File:** modules/objdetect/src/aruco/aruco_detector.cpp
**Change Type:** modified
**Context:** PR #24479: Fix contour filtering in ArUco

**Code Changes:**
```diff
@@ -50,6 +50,7 @@ static inline bool readWrite(DetectorParameters &params, const FileNode* readNod
                                 readNode, writeStorage);
     check |= readWriteParameter("minOtsuStdDev", params.minOtsuStdDev, readNode, writeStorage);
     check |= readWriteParameter("errorCorrectionRate", params.errorCorrectionRate, readNode, writeStorage);
+    check |= readWriteParameter("minGroupDistance", params.minGroupDistance, readNode, writeStorage);
     // new aruco 3 functionality
     check |= readWriteParameter("useAruco3Detection", params.useAruco3Detection, readNode, writeStorage);
     check |= readWriteParameter("minSideLengthCanonicalImg", params.minSideLengthCanonicalImg, readNode, writeStorage);
@@ -212,149 +213,65 @@ static void _reorderCandidatesCorners(vector<vector<Point2f> > &candidates) {
     }
```

Review comment:
Not relevant new line.
**File:** modules/objdetect/src/aruco/aruco_detector.cpp
**Change Type:** modified
**Context:** PR #24479: Fix contour filtering in ArUco

**Code Changes:**
```diff
@@ -50,6 +50,7 @@ static inline bool readWrite(DetectorParameters &params, const FileNode* readNod
                                 readNode, writeStorage);
     check |= readWriteParameter("minOtsuStdDev", params.minOtsuStdDev, readNode, writeStorage);
     check |= readWriteParameter("errorCorrectionRate", params.errorCorrectionRate, readNode, writeStorage);
+    check |= readWriteParameter("minGroupDistance", params.minGroupDistance, readNode, writeStorage);
     // new aruco 3 functionality
     check |= readWriteParameter("useAruco3Detection", params.useAruco3Detection, readNode, writeStorage);
     check |= readWriteParameter("minSideLengthCanonicalImg", params.minSideLengthCanonicalImg, readNode, writeStorage);
@@ -212,149 +213,65 @@ static void _reorderCandidatesCorners(vector<vector<Point2f> > &candidates) {
     }
```

Review comment:
it makes sense to use size_t to prevent build warnings.
**File:** modules/objdetect/src/aruco/aruco_detector.cpp
**Change Type:** modified
**Context:** PR #24479: Fix contour filtering in ArUco

**Code Changes:**
```diff
@@ -50,6 +50,7 @@ static inline bool readWrite(DetectorParameters &params, const FileNode* readNod
                                 readNode, writeStorage);
     check |= readWriteParameter("minOtsuStdDev", params.minOtsuStdDev, readNode, writeStorage);
     check |= readWriteParameter("errorCorrectionRate", params.errorCorrectionRate, readNode, writeStorage);
+    check |= readWriteParameter("minGroupDistance", params.minGroupDistance, readNode, writeStorage);
     // new aruco 3 functionality
     check |= readWriteParameter("useAruco3Detection", params.useAruco3Detection, readNode, writeStorage);
     check |= readWriteParameter("minSideLengthCanonicalImg", params.minSideLengthCanonicalImg, readNode, writeStorage);
@@ -212,149 +213,65 @@ static void _reorderCandidatesCorners(vector<vector<Point2f> > &candidates) {
     }
```

Review comment:
`vector<unsigned int> grouped = {i, j}`;, then emplace_back?
**File:** modules/objdetect/src/aruco/aruco_detector.cpp
**Change Type:** modified
**Context:** PR #24479: Fix contour filtering in ArUco

**Code Changes:**
```diff
@@ -50,6 +50,7 @@ static inline bool readWrite(DetectorParameters &params, const FileNode* readNod
                                 readNode, writeStorage);
     check |= readWriteParameter("minOtsuStdDev", params.minOtsuStdDev, readNode, writeStorage);
     check |= readWriteParameter("errorCorrectionRate", params.errorCorrectionRate, readNode, writeStorage);
+    check |= readWriteParameter("minGroupDistance", params.minGroupDistance, readNode, writeStorage);
     // new aruco 3 functionality
     check |= readWriteParameter("useAruco3Detection", params.useAruco3Detection, readNode, writeStorage);
     check |= readWriteParameter("minSideLengthCanonicalImg", params.minSideLengthCanonicalImg, readNode, writeStorage);
@@ -212,149 +213,65 @@ static void _reorderCandidatesCorners(vector<vector<Point2f> > &candidates) {
     }
```

Review comment:
I propose to use different sort calls depending on `detectorParams.detectInvertedMarker`. It allows to get rif of std::revrese
**File:** modules/objdetect/src/aruco/aruco_detector.cpp
**Change Type:** modified
**Context:** PR #24479: Fix contour filtering in ArUco

**Code Changes:**
```diff
@@ -50,6 +50,7 @@ static inline bool readWrite(DetectorParameters &params, const FileNode* readNod
                                 readNode, writeStorage);
     check |= readWriteParameter("minOtsuStdDev", params.minOtsuStdDev, readNode, writeStorage);
     check |= readWriteParameter("errorCorrectionRate", params.errorCorrectionRate, readNode, writeStorage);
+    check |= readWriteParameter("minGroupDistance", params.minGroupDistance, readNode, writeStorage);
     // new aruco 3 functionality
     check |= readWriteParameter("useAruco3Detection", params.useAruco3Detection, readNode, writeStorage);
     check |= readWriteParameter("minSideLengthCanonicalImg", params.minSideLengthCanonicalImg, readNode, writeStorage);
@@ -212,149 +213,65 @@ static void _reorderCandidatesCorners(vector<vector<Point2f> > &candidates) {
     }
```

Review comment:
removed field
**File:** modules/objdetect/src/aruco/aruco_detector.cpp
**Change Type:** modified
**Context:** PR #24479: Fix contour filtering in ArUco

**Code Changes:**
```diff
@@ -50,6 +50,7 @@ static inline bool readWrite(DetectorParameters &params, const FileNode* readNod
                                 readNode, writeStorage);
     check |= readWriteParameter("minOtsuStdDev", params.minOtsuStdDev, readNode, writeStorage);
     check |= readWriteParameter("errorCorrectionRate", params.errorCorrectionRate, readNode, writeStorage);
+    check |= readWriteParameter("minGroupDistance", params.minGroupDistance, readNode, writeStorage);
     // new aruco 3 functionality
     check |= readWriteParameter("useAruco3Detection", params.useAruco3Detection, readNode, writeStorage);
     check |= readWriteParameter("minSideLengthCanonicalImg", params.minSideLengthCanonicalImg, readNode, writeStorage);
@@ -212,149 +213,65 @@ static void _reorderCandidatesCorners(vector<vector<Point2f> > &candidates) {
     }
```

Review comment:
removed duplicate
**File:** modules/objdetect/src/aruco/aruco_detector.cpp
**Change Type:** modified
**Context:** PR #24479: Fix contour filtering in ArUco

**Code Changes:**
```diff
@@ -50,6 +50,7 @@ static inline bool readWrite(DetectorParameters &params, const FileNode* readNod
                                 readNode, writeStorage);
     check |= readWriteParameter("minOtsuStdDev", params.minOtsuStdDev, readNode, writeStorage);
     check |= readWriteParameter("errorCorrectionRate", params.errorCorrectionRate, readNode, writeStorage);
+    check |= readWriteParameter("minGroupDistance", params.minGroupDistance, readNode, writeStorage);
     // new aruco 3 functionality
     check |= readWriteParameter("useAruco3Detection", params.useAruco3Detection, readNode, writeStorage);
     check |= readWriteParameter("minSideLengthCanonicalImg", params.minSideLengthCanonicalImg, readNode, writeStorage);
@@ -212,149 +213,65 @@ static void _reorderCandidatesCorners(vector<vector<Point2f> > &candidates) {
     }
```

Review comment:
added size_t