nareshmlx/opencv-pr huggingface dataset:
**File:** modules/core/src/matrix.cpp
**Change Type:** modified
**Context:** PR #25979: Set and check allocator pointer for all cv::Mat instances
**Review Line:** 701

**Code Changes:**
```diff
             a = a0;
         try
         {
             u = a->allocate(dims, size, _type, 0, step.p, ACCESS_RW /* ignored */, USAGE_DEFAULT);
             CV_Assert(u != 0);
+            allocator = a;
         }
         catch (...)
         {
             if (a == a0)
                 throw;
```

Review comment:
`umatrix.cpp` has the similar code related to Mat (besides of tons of code related to UMat): https://github.com/opencv/opencv/blob/4.10.0/modules/core/src/umatrix.cpp#L601
**File:** modules/core/src/matrix.cpp
**Change Type:** modified
**Context:** PR #25979: Set and check allocator pointer for all cv::Mat instances
**Review Line:** 701

**Code Changes:**
```diff
             a = a0;
         try
         {
             u = a->allocate(dims, size, _type, 0, step.p, ACCESS_RW /* ignored */, USAGE_DEFAULT);
             CV_Assert(u != 0);
+            allocator = a;
         }
         catch (...)
         {
             if (a == a0)
                 throw;
```

Review comment:
UMat handles allocators a bit different. I propose to handle it with dedicated PR. Need to discuss it first.
**File:** modules/dnn/src/onnx/onnx_importer.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support

**Code Changes:**
```diff
@@ -3239,6 +3239,17 @@ void ONNXImporter::parseQuantDequant(LayerParams& layerParams, const opencv_onnx
     // or 1-D tensor (per-channel quantized).
     bool is1D = false;
 
+    if (layerParams.type == "Quantize")
+        layerParams.set("depth", CV_8S);
+    else // Dequantize
+        layerParams.set("depth", CV_32F);
+
+    // If scale is not defined as a constant blob, it is considered an external input.
```

Review comment:
Attributes in a node_proto is parsed already (populateNet() -> handleNode() -> [getLayerParams()](https://github.com/opencv/opencv/blob/f1aef892bfe7b30255050275fdb80d2ec108a9a4/modules/dnn/src/onnx/onnx_importer.cpp#L505)) and is not necessary to do it manually if you are not making any modification to the value.
**File:** modules/dnn/test/test_onnx_conformance.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support

**Code Changes:**
```diff
@@ -224,6 +224,7 @@ static const TestCase testConformanceConfig[] = {
     {"test_depthtospace_example", 1, 1},
     {"test_dequantizelinear", 3, 1},
     {"test_dequantizelinear_axis", 3, 1},
+    {"test_dequantizelinear_blocked", 3, 1},
     {"test_det_2d", 1, 1},
     {"test_det_nd", 1, 1},
     {"test_div", 2, 1},
@@ -564,6 +565,7 @@ static const TestCase testConformanceConfig[] = {
     {"test_qlinearmatmul_3D", 8, 1},
```

Review comment:
The official model has 3 inputs, so it should be `3`. Please do not modify the model and just take it from the official onnx repo. --- You can modify onnx importer to take scale & zp as inputs if they cannot be found in constants. Then you need to modify the forward pass in the implemenetation as well.
**File:** modules/dnn/test/test_onnx_conformance.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support

**Code Changes:**
```diff
@@ -224,6 +224,7 @@ static const TestCase testConformanceConfig[] = {
     {"test_depthtospace_example", 1, 1},
     {"test_dequantizelinear", 3, 1},
     {"test_dequantizelinear_axis", 3, 1},
+    {"test_dequantizelinear_blocked", 3, 1},
     {"test_det_2d", 1, 1},
     {"test_det_nd", 1, 1},
     {"test_div", 2, 1},
@@ -564,6 +565,7 @@ static const TestCase testConformanceConfig[] = {
     {"test_qlinearmatmul_3D", 8, 1},
```

Review comment:
Done and updated the PR description as well as the test cases!
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support
**Review Line:** 115

**Code Changes:**
```diff
+    mat.create(subTargetShape.size(), subTargetShape.data(), CV_32FC1);
+
+    copyVecToMat(mat,data);
+
+    broadcast1D2TargetMat(mat, targetShape, axis);
+}
+
+
+static void broadcastScaleAndZeropoint(Mat& scalesMat, Mat& zeropointsMat, const std::vector<float>& scales,
+                                       const std::vector<int>& zeropoints, const MatShape& targetShape, int axis, int block_size)
+{
```

Review comment:
I propose to drop `template` as we are operating a `CV_32FC1` Mat either way. --- If you want to keep template, you will need to distinguish between types and use `char` along with elementwise to do the correct copy.
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support

**Code Changes:**
```diff
@@ -15,7 +15,10 @@ namespace dnn
 static void broadcast1D2TargetMat(Mat& data, const MatShape& targetShape, int axis)
 {
     // The data is the 1-D scales or zeropoints.
-    CV_Assert(axis >= 0 && targetShape.size() > axis && data.total() == targetShape[axis]);
+    CV_CheckGE(axis, 0, "Quantization axis must be non-negative.");
+    CV_CheckGT((int)targetShape.size(),axis,"Quantization axis must be within the valid range of target shape dimensions.");
+    CV_CheckEQ((int)data.total(), (int)targetShape[axis], "Data total size must match the size of the specified target dimension.");
+
     std::vector<int> broadcast_axes;
```

Review comment:
zero point is optional for both quantize linear and dequantize linear.
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support

**Code Changes:**
```diff
@@ -15,7 +15,10 @@ namespace dnn
 static void broadcast1D2TargetMat(Mat& data, const MatShape& targetShape, int axis)
 {
     // The data is the 1-D scales or zeropoints.
-    CV_Assert(axis >= 0 && targetShape.size() > axis && data.total() == targetShape[axis]);
+    CV_CheckGE(axis, 0, "Quantization axis must be non-negative.");
+    CV_CheckGT((int)targetShape.size(),axis,"Quantization axis must be within the valid range of target shape dimensions.");
+    CV_CheckEQ((int)data.total(), (int)targetShape[axis], "Data total size must match the size of the specified target dimension.");
+
     std::vector<int> broadcast_axes;
```

Review comment:
Scale and zero point are just needed to be broadcast once. After that, they should not be processed again.
**File:** modules/dnn/test/test_onnx_conformance_layer_parser_denylist.inl.hpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support

**Code Changes:**
```diff
@@ -89,8 +89,6 @@
 "test_convtranspose_pad",
 "test_convtranspose_pads",
 "test_convtranspose_with_kernel",
-"test_dequantizelinear",
-"test_dequantizelinear_axis",
 "test_det_2d",
 "test_det_nd",
 "test_dropout_default_mask",
@@ -287,8 +285,6 @@
```

Review comment:
drop the comment if not needed
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support

**Code Changes:**
```diff
@@ -15,7 +15,10 @@ namespace dnn
 static void broadcast1D2TargetMat(Mat& data, const MatShape& targetShape, int axis)
 {
     // The data is the 1-D scales or zeropoints.
-    CV_Assert(axis >= 0 && targetShape.size() > axis && data.total() == targetShape[axis]);
+    CV_CheckGE(axis, 0, "Quantization axis must be non-negative.");
+    CV_CheckGT((int)targetShape.size(),axis,"Quantization axis must be within the valid range of target shape dimensions.");
+    CV_CheckEQ((int)data.total(), (int)targetShape[axis], "Data total size must match the size of the specified target dimension.");
+
     std::vector<int> broadcast_axes;
```

Review comment:
The code block inside `if(inputs.size() > 1)` is executed only when scale and zero point are provided as inputs to the layer. In this case, the `broadcastScaleAndZeropoint` function in the `finalize` method is not called because the necessary data (scale and zero point) was not available at the time of the layer's creation. So the broadcast occurs just once in any case.
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support
**Review Line:** 115

**Code Changes:**
```diff
+    mat.create(subTargetShape.size(), subTargetShape.data(), CV_32FC1);
+
+    copyVecToMat(mat,data);
+
+    broadcast1D2TargetMat(mat, targetShape, axis);
+}
+
+
+static void broadcastScaleAndZeropoint(Mat& scalesMat, Mat& zeropointsMat, const std::vector<float>& scales,
+                                       const std::vector<int>& zeropoints, const MatShape& targetShape, int axis, int block_size)
+{
```

Review comment:
I decided to use `template` because `std::vector<T>& data` can be either `vector<float>` in the case of scale or `vector<int>` in the case of zero point. When copying the data into the matrix the vector is indexed and then cast to float. Does it make sense?
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support
**Review Line:** 115

**Code Changes:**
```diff
+    mat.create(subTargetShape.size(), subTargetShape.data(), CV_32FC1);
+
+    copyVecToMat(mat,data);
+
+    broadcast1D2TargetMat(mat, targetShape, axis);
+}
+
+
+static void broadcastScaleAndZeropoint(Mat& scalesMat, Mat& zeropointsMat, const std::vector<float>& scales,
+                                       const std::vector<int>& zeropoints, const MatShape& targetShape, int axis, int block_size)
+{
```

Review comment:
> then cast to float No, this is wrong assumption. ```cpp mat.create(subTargetShape.size(), subTargetShape.data(), CV_32FC1); ``` If you want to use template, you should create mat from the correct type.
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support

**Code Changes:**
```diff
@@ -15,7 +15,10 @@ namespace dnn
 static void broadcast1D2TargetMat(Mat& data, const MatShape& targetShape, int axis)
 {
     // The data is the 1-D scales or zeropoints.
-    CV_Assert(axis >= 0 && targetShape.size() > axis && data.total() == targetShape[axis]);
+    CV_CheckGE(axis, 0, "Quantization axis must be non-negative.");
+    CV_CheckGT((int)targetShape.size(),axis,"Quantization axis must be within the valid range of target shape dimensions.");
+    CV_CheckEQ((int)data.total(), (int)targetShape[axis], "Data total size must match the size of the specified target dimension.");
+
     std::vector<int> broadcast_axes;
```

Review comment:
Use `CV_Check(inputs.size(), inputs.size() >= 1 && inputs.size() <= 3, "your error message")` instead
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support

**Code Changes:**
```diff
@@ -15,7 +15,10 @@ namespace dnn
 static void broadcast1D2TargetMat(Mat& data, const MatShape& targetShape, int axis)
 {
     // The data is the 1-D scales or zeropoints.
-    CV_Assert(axis >= 0 && targetShape.size() > axis && data.total() == targetShape[axis]);
+    CV_CheckGE(axis, 0, "Quantization axis must be non-negative.");
+    CV_CheckGT((int)targetShape.size(),axis,"Quantization axis must be within the valid range of target shape dimensions.");
+    CV_CheckEQ((int)data.total(), (int)targetShape[axis], "Data total size must match the size of the specified target dimension.");
+
     std::vector<int> broadcast_axes;
```

Review comment:
Use `CV_CheckXX` instead.
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support

**Code Changes:**
```diff
@@ -15,7 +15,10 @@ namespace dnn
 static void broadcast1D2TargetMat(Mat& data, const MatShape& targetShape, int axis)
 {
     // The data is the 1-D scales or zeropoints.
-    CV_Assert(axis >= 0 && targetShape.size() > axis && data.total() == targetShape[axis]);
+    CV_CheckGE(axis, 0, "Quantization axis must be non-negative.");
+    CV_CheckGT((int)targetShape.size(),axis,"Quantization axis must be within the valid range of target shape dimensions.");
+    CV_CheckEQ((int)data.total(), (int)targetShape[axis], "Data total size must match the size of the specified target dimension.");
+
     std::vector<int> broadcast_axes;
```

Review comment:
`CV_CheckXX`
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support

**Code Changes:**
```diff
@@ -15,7 +15,10 @@ namespace dnn
 static void broadcast1D2TargetMat(Mat& data, const MatShape& targetShape, int axis)
 {
     // The data is the 1-D scales or zeropoints.
-    CV_Assert(axis >= 0 && targetShape.size() > axis && data.total() == targetShape[axis]);
+    CV_CheckGE(axis, 0, "Quantization axis must be non-negative.");
+    CV_CheckGT((int)targetShape.size(),axis,"Quantization axis must be within the valid range of target shape dimensions.");
+    CV_CheckEQ((int)data.total(), (int)targetShape[axis], "Data total size must match the size of the specified target dimension.");
+
     std::vector<int> broadcast_axes;
```

Review comment:
But the next inference still gets scale and zero point from inputs. The point is we avoid this from the second time.
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support

**Code Changes:**
```diff
@@ -15,7 +15,10 @@ namespace dnn
 static void broadcast1D2TargetMat(Mat& data, const MatShape& targetShape, int axis)
 {
     // The data is the 1-D scales or zeropoints.
-    CV_Assert(axis >= 0 && targetShape.size() > axis && data.total() == targetShape[axis]);
+    CV_CheckGE(axis, 0, "Quantization axis must be non-negative.");
+    CV_CheckGT((int)targetShape.size(),axis,"Quantization axis must be within the valid range of target shape dimensions.");
+    CV_CheckEQ((int)data.total(), (int)targetShape[axis], "Data total size must match the size of the specified target dimension.");
+
     std::vector<int> broadcast_axes;
```

Review comment:
Can we avoid creating a new Mat here? Repeating is like reusing a piece of memory multiple times. We can rewrite the forward implementation with a loop, each time it proceeds with a correct step. So we can save time and memory from creating new Mat. --- Also if this is implemented in the end, could you put the core function, e.g. `quantize(...)` in `modules/dnn/src/layers/cpu_kernels`? I think, when it comes to importing stage, we need to call quantize or dequantize functions in `modules/dnn/src/onnx/onnx_graph_simplifier.cpp`.
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support

**Code Changes:**
```diff
@@ -15,7 +15,10 @@ namespace dnn
 static void broadcast1D2TargetMat(Mat& data, const MatShape& targetShape, int axis)
 {
     // The data is the 1-D scales or zeropoints.
-    CV_Assert(axis >= 0 && targetShape.size() > axis && data.total() == targetShape[axis]);
+    CV_CheckGE(axis, 0, "Quantization axis must be non-negative.");
+    CV_CheckGT((int)targetShape.size(),axis,"Quantization axis must be within the valid range of target shape dimensions.");
+    CV_CheckEQ((int)data.total(), (int)targetShape[axis], "Data total size must match the size of the specified target dimension.");
+
     std::vector<int> broadcast_axes;
```

Review comment:
This can be done later when we need to fuse qdq.
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support
**Review Line:** 277

**Code Changes:**
```diff
         if (is1D)
         {
             Mat inputTmp;
             divide(inputs[0], scalesMat, inputTmp);
-            subtract(inputTmp, zeropointsMat, inputTmp);
+            add(inputTmp, zeropointsMat, inputTmp);
 
             inputTmp.convertTo(outputs[0], CV_8S);
         }
@@ -190,13 +298,16 @@ class DequantizeLayerImpl CV_FINAL : public DequantizeLayer
 {
```

Review comment:
The change looks strange. Please add test for the case.
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support

**Code Changes:**
```diff
@@ -15,7 +15,10 @@ namespace dnn
 static void broadcast1D2TargetMat(Mat& data, const MatShape& targetShape, int axis)
 {
     // The data is the 1-D scales or zeropoints.
-    CV_Assert(axis >= 0 && targetShape.size() > axis && data.total() == targetShape[axis]);
+    CV_CheckGE(axis, 0, "Quantization axis must be non-negative.");
+    CV_CheckGT((int)targetShape.size(),axis,"Quantization axis must be within the valid range of target shape dimensions.");
+    CV_CheckEQ((int)data.total(), (int)targetShape[axis], "Data total size must match the size of the specified target dimension.");
+
     std::vector<int> broadcast_axes;
```

Review comment:
please add brief description what the flag means.
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support

**Code Changes:**
```diff
@@ -15,7 +15,10 @@ namespace dnn
 static void broadcast1D2TargetMat(Mat& data, const MatShape& targetShape, int axis)
 {
     // The data is the 1-D scales or zeropoints.
-    CV_Assert(axis >= 0 && targetShape.size() > axis && data.total() == targetShape[axis]);
+    CV_CheckGE(axis, 0, "Quantization axis must be non-negative.");
+    CV_CheckGT((int)targetShape.size(),axis,"Quantization axis must be within the valid range of target shape dimensions.");
+    CV_CheckEQ((int)data.total(), (int)targetShape[axis], "Data total size must match the size of the specified target dimension.");
+
     std::vector<int> broadcast_axes;
```

Review comment:
There is cv::Mat::copyTo, if you really need a copy.
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support

**Code Changes:**
```diff
@@ -15,7 +15,10 @@ namespace dnn
 static void broadcast1D2TargetMat(Mat& data, const MatShape& targetShape, int axis)
 {
     // The data is the 1-D scales or zeropoints.
-    CV_Assert(axis >= 0 && targetShape.size() > axis && data.total() == targetShape[axis]);
+    CV_CheckGE(axis, 0, "Quantization axis must be non-negative.");
+    CV_CheckGT((int)targetShape.size(),axis,"Quantization axis must be within the valid range of target shape dimensions.");
+    CV_CheckEQ((int)data.total(), (int)targetShape[axis], "Data total size must match the size of the specified target dimension.");
+
     std::vector<int> broadcast_axes;
```

Review comment:
Why do you need a copy here? Also you can push std::vector<> as input to function with InputArray. It's handled automatically.
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support
**Review Line:** 15

**Code Changes:**
```diff
@@ -15,7 +15,10 @@ namespace dnn
 static void broadcast1D2TargetMat(Mat& data, const MatShape& targetShape, int axis)
 {
     // The data is the 1-D scales or zeropoints.
-    CV_Assert(axis >= 0 && targetShape.size() > axis && data.total() == targetShape[axis]);
+    CV_CheckGE(axis, 0, "Quantization axis must be non-negative.");
+    CV_CheckGT((int)targetShape.size(),axis,"Quantization axis must be within the valid range of target shape dimensions.");
```

Review comment:
You can use InputArray for data and get rid of copy before the call.
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support
**Review Line:** 277

**Code Changes:**
```diff
         if (is1D)
         {
             Mat inputTmp;
             divide(inputs[0], scalesMat, inputTmp);
-            subtract(inputTmp, zeropointsMat, inputTmp);
+            add(inputTmp, zeropointsMat, inputTmp);
 
             inputTmp.convertTo(outputs[0], CV_8S);
         }
@@ -190,13 +298,16 @@ class DequantizeLayerImpl CV_FINAL : public DequantizeLayer
 {
```

Review comment:
The quantization formula was changed to adhere to the [onnx quantization standard](https://github.com/onnx/onnx/blob/main/docs/Operators.md#QuantizeLinear). The test cases introduced in PR opencv/opencv_extra#1181 verify the correctness of the quantization operation
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support

**Code Changes:**
```diff
@@ -15,7 +15,10 @@ namespace dnn
 static void broadcast1D2TargetMat(Mat& data, const MatShape& targetShape, int axis)
 {
     // The data is the 1-D scales or zeropoints.
-    CV_Assert(axis >= 0 && targetShape.size() > axis && data.total() == targetShape[axis]);
+    CV_CheckGE(axis, 0, "Quantization axis must be non-negative.");
+    CV_CheckGT((int)targetShape.size(),axis,"Quantization axis must be within the valid range of target shape dimensions.");
+    CV_CheckEQ((int)data.total(), (int)targetShape[axis], "Data total size must match the size of the specified target dimension.");
+
     std::vector<int> broadcast_axes;
```

Review comment:
destination is OutputArray. You can pass vector there too.
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support
**Review Line:** 277

**Code Changes:**
```diff
         if (is1D)
         {
             Mat inputTmp;
             divide(inputs[0], scalesMat, inputTmp);
-            subtract(inputTmp, zeropointsMat, inputTmp);
+            add(inputTmp, zeropointsMat, inputTmp);
 
             inputTmp.convertTo(outputs[0], CV_8S);
         }
@@ -190,13 +298,16 @@ class DequantizeLayerImpl CV_FINAL : public DequantizeLayer
 {
```

Review comment:
> The change looks strange. Please add test for the case. We got conformance tests working ok already. See https://github.com/opencv/opencv/actions/runs/10096457129/job/27931214005?pr=25644#step:19:5202 for example, ``` [ RUN ] Test_ONNX_conformance.Layer_Test/test_quantizelinear_OCV_CPU, where GetParam() = (test_quantizelinear, OCV/CPU) Test passed! [ OK ] Test_ONNX_conformance.Layer_Test/test_quantizelinear_OCV_CPU (1 ms) [ RUN ] Test_ONNX_conformance.Layer_Test/test_quantizelinear_axis_OCV_CPU, where GetParam() = (test_quantizelinear_axis, OCV/CPU) Test passed! [ OK ] Test_ONNX_conformance.Layer_Test/test_quantizelinear_axis_OCV_CPU (0 ms) [ RUN ] Test_ONNX_conformance.Layer_Test/test_quantizelinear_blocked_OCV_CPU, where GetParam() = (test_quantizelinear_blocked, OCV/CPU) Test passed! [ OK ] Test_ONNX_conformance.Layer_Test/test_quantizelinear_blocked_OCV_CPU (1 ms) ```
**File:** modules/dnn/src/int8layers/quantization_utils.cpp
**Change Type:** modified
**Context:** PR #25644: [GSoC] dnn: Blockwise quantization support
**Review Line:** 15

**Code Changes:**
```diff
@@ -15,7 +15,10 @@ namespace dnn
 static void broadcast1D2TargetMat(Mat& data, const MatShape& targetShape, int axis)
 {
     // The data is the 1-D scales or zeropoints.
-    CV_Assert(axis >= 0 && targetShape.size() > axis && data.total() == targetShape[axis]);
+    CV_CheckGE(axis, 0, "Quantization axis must be non-negative.");
+    CV_CheckGT((int)targetShape.size(),axis,"Quantization axis must be within the valid range of target shape dimensions.");
```

Review comment:
In this case, I do need a copy. The input `std::vector` must be copied into the matrices `scalesMat` and `zeropointsMat` that will be used to compute the quantization in the `forward` function.