1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 15:53:03 +04:00

Merge branch 4.x

This commit is contained in:
Alexander Smorkalov
2026-06-01 13:21:19 +03:00
30 changed files with 1245 additions and 152 deletions
+6
View File
@@ -45,6 +45,12 @@ PERF_TEST_P_ACCUMULATE(Accumulate, MAT_TYPES_ACCUMLATE,
PERF_TEST_P_ACCUMULATE(AccumulateMask, MAT_TYPES_ACCUMLATE_C,
PERF_ACCUMULATE_MASK_INIT(CV_32FC), accumulate(src1, dst, mask))
PERF_TEST_P_ACCUMULATE(AccumulateMask32FC4, CV_32FC4,
PERF_ACCUMULATE_MASK_INIT(CV_32FC), accumulate(src1, dst, mask))
PERF_TEST_P_ACCUMULATE(AccumulateMask8UC4To32FC4, CV_8UC4,
PERF_ACCUMULATE_MASK_INIT(CV_32FC), accumulate(src1, dst, mask))
PERF_TEST_P_ACCUMULATE(AccumulateDouble, MAT_TYPES_ACCUMLATE_D,
PERF_ACCUMULATE_INIT(CV_64FC), accumulate(src1, dst))
+265 -101
View File
@@ -317,79 +317,183 @@ void acc_simd_(const uchar* src, float* dst, const uchar* mask, int len, int cn)
}
else
{
v_uint8 v_0 = vx_setall_u8(0);
if (cn == 1)
if (x <= len - cVectorWidth)
{
for ( ; x <= len - cVectorWidth; x += cVectorWidth)
v_uint8 v_0 = vx_setall_u8(0);
if (cn == 1)
{
v_uint8 v_mask = vx_load(mask + x);
v_mask = v_not(v_eq(v_0, v_mask));
v_uint8 v_src = vx_load(src + x);
v_src = v_and(v_src, v_mask);
v_uint16 v_src0, v_src1;
v_expand(v_src, v_src0, v_src1);
for ( ; x <= len - cVectorWidth; x += cVectorWidth)
{
v_uint8 v_mask = vx_load(mask + x);
v_mask = v_ne(v_0, v_mask);
v_uint8 v_src = vx_load(src + x);
v_src = v_and(v_src, v_mask);
v_uint16 v_src0, v_src1;
v_expand(v_src, v_src0, v_src1);
v_uint32 v_src00, v_src01, v_src10, v_src11;
v_expand(v_src0, v_src00, v_src01);
v_expand(v_src1, v_src10, v_src11);
v_uint32 v_src00, v_src01, v_src10, v_src11;
v_expand(v_src0, v_src00, v_src01);
v_expand(v_src1, v_src10, v_src11);
v_store(dst + x, v_add(vx_load(dst + x), v_cvt_f32(v_reinterpret_as_s32(v_src00))));
v_store(dst + x + step, v_add(vx_load(dst + x + step), v_cvt_f32(v_reinterpret_as_s32(v_src01))));
v_store(dst + x + step * 2, v_add(vx_load(dst + x + step * 2), v_cvt_f32(v_reinterpret_as_s32(v_src10))));
v_store(dst + x + step * 3, v_add(vx_load(dst + x + step * 3), v_cvt_f32(v_reinterpret_as_s32(v_src11))));
v_store(dst + x, v_add(vx_load(dst + x), v_cvt_f32(v_reinterpret_as_s32(v_src00))));
v_store(dst + x + step, v_add(vx_load(dst + x + step), v_cvt_f32(v_reinterpret_as_s32(v_src01))));
v_store(dst + x + step * 2, v_add(vx_load(dst + x + step * 2), v_cvt_f32(v_reinterpret_as_s32(v_src10))));
v_store(dst + x + step * 3, v_add(vx_load(dst + x + step * 3), v_cvt_f32(v_reinterpret_as_s32(v_src11))));
}
}
}
else if (cn == 3)
{
for ( ; x <= len - cVectorWidth; x += cVectorWidth)
else if (cn == 3)
{
v_uint8 v_mask = vx_load(mask + x);
v_mask = v_not(v_eq(v_0, v_mask));
v_uint8 v_src0, v_src1, v_src2;
v_load_deinterleave(src + (x * cn), v_src0, v_src1, v_src2);
v_src0 = v_and(v_src0, v_mask);
v_src1 = v_and(v_src1, v_mask);
v_src2 = v_and(v_src2, v_mask);
v_uint16 v_src00, v_src01, v_src10, v_src11, v_src20, v_src21;
v_expand(v_src0, v_src00, v_src01);
v_expand(v_src1, v_src10, v_src11);
v_expand(v_src2, v_src20, v_src21);
for ( ; x <= len - cVectorWidth; x += cVectorWidth)
{
v_uint8 v_mask = vx_load(mask + x);
v_mask = v_ne(v_0, v_mask);
v_uint8 v_src0, v_src1, v_src2;
v_load_deinterleave(src + (x * cn), v_src0, v_src1, v_src2);
v_src0 = v_and(v_src0, v_mask);
v_src1 = v_and(v_src1, v_mask);
v_src2 = v_and(v_src2, v_mask);
v_uint16 v_src00, v_src01, v_src10, v_src11, v_src20, v_src21;
v_expand(v_src0, v_src00, v_src01);
v_expand(v_src1, v_src10, v_src11);
v_expand(v_src2, v_src20, v_src21);
v_uint32 v_src000, v_src001, v_src010, v_src011;
v_uint32 v_src100, v_src101, v_src110, v_src111;
v_uint32 v_src200, v_src201, v_src210, v_src211;
v_expand(v_src00, v_src000, v_src001);
v_expand(v_src01, v_src010, v_src011);
v_expand(v_src10, v_src100, v_src101);
v_expand(v_src11, v_src110, v_src111);
v_expand(v_src20, v_src200, v_src201);
v_expand(v_src21, v_src210, v_src211);
v_uint32 v_src000, v_src001, v_src010, v_src011;
v_uint32 v_src100, v_src101, v_src110, v_src111;
v_uint32 v_src200, v_src201, v_src210, v_src211;
v_expand(v_src00, v_src000, v_src001);
v_expand(v_src01, v_src010, v_src011);
v_expand(v_src10, v_src100, v_src101);
v_expand(v_src11, v_src110, v_src111);
v_expand(v_src20, v_src200, v_src201);
v_expand(v_src21, v_src210, v_src211);
v_float32 v_dst000, v_dst001, v_dst010, v_dst011;
v_float32 v_dst100, v_dst101, v_dst110, v_dst111;
v_float32 v_dst200, v_dst201, v_dst210, v_dst211;
v_load_deinterleave(dst + (x * cn), v_dst000, v_dst100, v_dst200);
v_load_deinterleave(dst + ((x + step) * cn), v_dst001, v_dst101, v_dst201);
v_load_deinterleave(dst + ((x + step * 2) * cn), v_dst010, v_dst110, v_dst210);
v_load_deinterleave(dst + ((x + step * 3) * cn), v_dst011, v_dst111, v_dst211);
v_float32 v_dst000, v_dst001, v_dst010, v_dst011;
v_float32 v_dst100, v_dst101, v_dst110, v_dst111;
v_float32 v_dst200, v_dst201, v_dst210, v_dst211;
v_load_deinterleave(dst + (x * cn), v_dst000, v_dst100, v_dst200);
v_load_deinterleave(dst + ((x + step) * cn), v_dst001, v_dst101, v_dst201);
v_load_deinterleave(dst + ((x + step * 2) * cn), v_dst010, v_dst110, v_dst210);
v_load_deinterleave(dst + ((x + step * 3) * cn), v_dst011, v_dst111, v_dst211);
v_dst000 = v_add(v_dst000, v_cvt_f32(v_reinterpret_as_s32(v_src000)));
v_dst100 = v_add(v_dst100, v_cvt_f32(v_reinterpret_as_s32(v_src100)));
v_dst200 = v_add(v_dst200, v_cvt_f32(v_reinterpret_as_s32(v_src200)));
v_dst001 = v_add(v_dst001, v_cvt_f32(v_reinterpret_as_s32(v_src001)));
v_dst101 = v_add(v_dst101, v_cvt_f32(v_reinterpret_as_s32(v_src101)));
v_dst201 = v_add(v_dst201, v_cvt_f32(v_reinterpret_as_s32(v_src201)));
v_dst010 = v_add(v_dst010, v_cvt_f32(v_reinterpret_as_s32(v_src010)));
v_dst110 = v_add(v_dst110, v_cvt_f32(v_reinterpret_as_s32(v_src110)));
v_dst210 = v_add(v_dst210, v_cvt_f32(v_reinterpret_as_s32(v_src210)));
v_dst011 = v_add(v_dst011, v_cvt_f32(v_reinterpret_as_s32(v_src011)));
v_dst111 = v_add(v_dst111, v_cvt_f32(v_reinterpret_as_s32(v_src111)));
v_dst211 = v_add(v_dst211, v_cvt_f32(v_reinterpret_as_s32(v_src211)));
v_dst000 = v_add(v_dst000, v_cvt_f32(v_reinterpret_as_s32(v_src000)));
v_dst100 = v_add(v_dst100, v_cvt_f32(v_reinterpret_as_s32(v_src100)));
v_dst200 = v_add(v_dst200, v_cvt_f32(v_reinterpret_as_s32(v_src200)));
v_dst001 = v_add(v_dst001, v_cvt_f32(v_reinterpret_as_s32(v_src001)));
v_dst101 = v_add(v_dst101, v_cvt_f32(v_reinterpret_as_s32(v_src101)));
v_dst201 = v_add(v_dst201, v_cvt_f32(v_reinterpret_as_s32(v_src201)));
v_dst010 = v_add(v_dst010, v_cvt_f32(v_reinterpret_as_s32(v_src010)));
v_dst110 = v_add(v_dst110, v_cvt_f32(v_reinterpret_as_s32(v_src110)));
v_dst210 = v_add(v_dst210, v_cvt_f32(v_reinterpret_as_s32(v_src210)));
v_dst011 = v_add(v_dst011, v_cvt_f32(v_reinterpret_as_s32(v_src011)));
v_dst111 = v_add(v_dst111, v_cvt_f32(v_reinterpret_as_s32(v_src111)));
v_dst211 = v_add(v_dst211, v_cvt_f32(v_reinterpret_as_s32(v_src211)));
v_store_interleave(dst + (x * cn), v_dst000, v_dst100, v_dst200);
v_store_interleave(dst + ((x + step) * cn), v_dst001, v_dst101, v_dst201);
v_store_interleave(dst + ((x + step * 2) * cn), v_dst010, v_dst110, v_dst210);
v_store_interleave(dst + ((x + step * 3) * cn), v_dst011, v_dst111, v_dst211);
v_store_interleave(dst + (x * cn), v_dst000, v_dst100, v_dst200);
v_store_interleave(dst + ((x + step) * cn), v_dst001, v_dst101, v_dst201);
v_store_interleave(dst + ((x + step * 2) * cn), v_dst010, v_dst110, v_dst210);
v_store_interleave(dst + ((x + step * 3) * cn), v_dst011, v_dst111, v_dst211);
}
}
else if (cn == 4)
{
v_uint8 v_zero = vx_setzero_u8();
for (; x <= len - cVectorWidth; x += cVectorWidth)
{
v_uint8 v_mask = vx_load(mask + x);
v_mask = v_ne(v_mask, v_zero);
v_uint8 v_src0, v_src1, v_src2, v_src3;
v_load_deinterleave(src + x * cn,
v_src0, v_src1, v_src2, v_src3);
v_src0 = v_and(v_src0, v_mask);
v_src1 = v_and(v_src1, v_mask);
v_src2 = v_and(v_src2, v_mask);
v_src3 = v_and(v_src3, v_mask);
v_uint16 v_src0_u16_0, v_src0_u16_1;
v_uint16 v_src1_u16_0, v_src1_u16_1;
v_uint16 v_src2_u16_0, v_src2_u16_1;
v_uint16 v_src3_u16_0, v_src3_u16_1;
v_expand(v_src0, v_src0_u16_0, v_src0_u16_1);
v_expand(v_src1, v_src1_u16_0, v_src1_u16_1);
v_expand(v_src2, v_src2_u16_0, v_src2_u16_1);
v_expand(v_src3, v_src3_u16_0, v_src3_u16_1);
v_uint32 v_src0_u32_0, v_src0_u32_1, v_src0_u32_2, v_src0_u32_3;
v_uint32 v_src1_u32_0, v_src1_u32_1, v_src1_u32_2, v_src1_u32_3;
v_uint32 v_src2_u32_0, v_src2_u32_1, v_src2_u32_2, v_src2_u32_3;
v_uint32 v_src3_u32_0, v_src3_u32_1, v_src3_u32_2, v_src3_u32_3;
v_expand(v_src0_u16_0, v_src0_u32_0, v_src0_u32_1);
v_expand(v_src0_u16_1, v_src0_u32_2, v_src0_u32_3);
v_expand(v_src1_u16_0, v_src1_u32_0, v_src1_u32_1);
v_expand(v_src1_u16_1, v_src1_u32_2, v_src1_u32_3);
v_expand(v_src2_u16_0, v_src2_u32_0, v_src2_u32_1);
v_expand(v_src2_u16_1, v_src2_u32_2, v_src2_u32_3);
v_expand(v_src3_u16_0, v_src3_u32_0, v_src3_u32_1);
v_expand(v_src3_u16_1, v_src3_u32_2, v_src3_u32_3);
v_float32 v_src0_f0 = v_cvt_f32(v_reinterpret_as_s32(v_src0_u32_0));
v_float32 v_src0_f1 = v_cvt_f32(v_reinterpret_as_s32(v_src0_u32_1));
v_float32 v_src0_f2 = v_cvt_f32(v_reinterpret_as_s32(v_src0_u32_2));
v_float32 v_src0_f3 = v_cvt_f32(v_reinterpret_as_s32(v_src0_u32_3));
v_float32 v_src1_f0 = v_cvt_f32(v_reinterpret_as_s32(v_src1_u32_0));
v_float32 v_src1_f1 = v_cvt_f32(v_reinterpret_as_s32(v_src1_u32_1));
v_float32 v_src1_f2 = v_cvt_f32(v_reinterpret_as_s32(v_src1_u32_2));
v_float32 v_src1_f3 = v_cvt_f32(v_reinterpret_as_s32(v_src1_u32_3));
v_float32 v_src2_f0 = v_cvt_f32(v_reinterpret_as_s32(v_src2_u32_0));
v_float32 v_src2_f1 = v_cvt_f32(v_reinterpret_as_s32(v_src2_u32_1));
v_float32 v_src2_f2 = v_cvt_f32(v_reinterpret_as_s32(v_src2_u32_2));
v_float32 v_src2_f3 = v_cvt_f32(v_reinterpret_as_s32(v_src2_u32_3));
v_float32 v_src3_f0 = v_cvt_f32(v_reinterpret_as_s32(v_src3_u32_0));
v_float32 v_src3_f1 = v_cvt_f32(v_reinterpret_as_s32(v_src3_u32_1));
v_float32 v_src3_f2 = v_cvt_f32(v_reinterpret_as_s32(v_src3_u32_2));
v_float32 v_src3_f3 = v_cvt_f32(v_reinterpret_as_s32(v_src3_u32_3));
v_float32 v_dst0, v_dst1, v_dst2, v_dst3;
v_load_deinterleave(dst + x * cn, v_dst0, v_dst1, v_dst2, v_dst3);
v_store_interleave(dst + x * cn,
v_add(v_dst0, v_src0_f0),
v_add(v_dst1, v_src1_f0),
v_add(v_dst2, v_src2_f0),
v_add(v_dst3, v_src3_f0));
v_load_deinterleave(dst + (x + step) * cn, v_dst0, v_dst1, v_dst2, v_dst3);
v_store_interleave(dst + (x + step) * cn,
v_add(v_dst0, v_src0_f1),
v_add(v_dst1, v_src1_f1),
v_add(v_dst2, v_src2_f1),
v_add(v_dst3, v_src3_f1));
v_load_deinterleave(dst + (x + 2 * step) * cn, v_dst0, v_dst1, v_dst2, v_dst3);
v_store_interleave(dst + (x + 2 * step) * cn,
v_add(v_dst0, v_src0_f2),
v_add(v_dst1, v_src1_f2),
v_add(v_dst2, v_src2_f2),
v_add(v_dst3, v_src3_f2));
v_load_deinterleave(dst + (x + 3 * step) * cn, v_dst0, v_dst1, v_dst2, v_dst3);
v_store_interleave(dst + (x + 3 * step) * cn,
v_add(v_dst0, v_src0_f3),
v_add(v_dst1, v_src1_f3),
v_add(v_dst2, v_src2_f3),
v_add(v_dst3, v_src3_f3));
}
}
}
}
@@ -500,49 +604,109 @@ void acc_simd_(const float* src, float* dst, const uchar* mask, int len, int cn)
}
else
{
v_float32 v_0 = vx_setzero_f32();
if (cn == 1)
if (x <= len - cVectorWidth)
{
for ( ; x <= len - cVectorWidth ; x += cVectorWidth)
v_float32 v_0 = vx_setzero_f32();
if (cn == 1)
{
v_uint16 v_masku16 = vx_load_expand(mask + x);
v_uint32 v_masku320, v_masku321;
v_expand(v_masku16, v_masku320, v_masku321);
v_float32 v_mask0 = v_reinterpret_as_f32(v_not(v_eq(v_masku320, v_reinterpret_as_u32(v_0))));
v_float32 v_mask1 = v_reinterpret_as_f32(v_not(v_eq(v_masku321, v_reinterpret_as_u32(v_0))));
for ( ; x <= len - cVectorWidth ; x += cVectorWidth)
{
v_uint16 v_masku16 = vx_load_expand(mask + x);
v_uint32 v_masku320, v_masku321;
v_expand(v_masku16, v_masku320, v_masku321);
v_float32 v_mask0 = v_reinterpret_as_f32(v_not(v_eq(v_masku320, v_reinterpret_as_u32(v_0))));
v_float32 v_mask1 = v_reinterpret_as_f32(v_not(v_eq(v_masku321, v_reinterpret_as_u32(v_0))));
v_store(dst + x, v_add(vx_load(dst + x), v_and(vx_load(src + x), v_mask0)));
v_store(dst + x + step, v_add(vx_load(dst + x + step), v_and(vx_load(src + x + step), v_mask1)));
v_store(dst + x, v_add(vx_load(dst + x), v_and(vx_load(src + x), v_mask0)));
v_store(dst + x + step, v_add(vx_load(dst + x + step), v_and(vx_load(src + x + step), v_mask1)));
}
}
else if (cn == 3)
{
for ( ; x <= len - cVectorWidth ; x += cVectorWidth)
{
v_uint16 v_masku16 = vx_load_expand(mask + x);
v_uint32 v_masku320, v_masku321;
v_expand(v_masku16, v_masku320, v_masku321);
v_float32 v_mask0 = v_reinterpret_as_f32(v_not(v_eq(v_masku320, v_reinterpret_as_u32(v_0))));
v_float32 v_mask1 = v_reinterpret_as_f32(v_not(v_eq(v_masku321, v_reinterpret_as_u32(v_0))));
v_float32 v_src00, v_src01, v_src10, v_src11, v_src20, v_src21;
v_load_deinterleave(src + x * cn, v_src00, v_src10, v_src20);
v_load_deinterleave(src + (x + step) * cn, v_src01, v_src11, v_src21);
v_src00 = v_and(v_src00, v_mask0);
v_src01 = v_and(v_src01, v_mask1);
v_src10 = v_and(v_src10, v_mask0);
v_src11 = v_and(v_src11, v_mask1);
v_src20 = v_and(v_src20, v_mask0);
v_src21 = v_and(v_src21, v_mask1);
v_float32 v_dst00, v_dst01, v_dst10, v_dst11, v_dst20, v_dst21;
v_load_deinterleave(dst + x * cn, v_dst00, v_dst10, v_dst20);
v_load_deinterleave(dst + (x + step) * cn, v_dst01, v_dst11, v_dst21);
v_store_interleave(dst + x * cn, v_add(v_dst00, v_src00), v_add(v_dst10, v_src10), v_add(v_dst20, v_src20));
v_store_interleave(dst + (x + step) * cn, v_add(v_dst01, v_src01), v_add(v_dst11, v_src11), v_add(v_dst21, v_src21));
}
}
else if (cn == 4)
{
for (; x <= len - cVectorWidth; x += cVectorWidth)
{
v_uint16 v_masku16 = vx_load_expand(mask + x);
v_uint32 v_masku320, v_masku321;
v_expand(v_masku16, v_masku320, v_masku321);
v_float32 v_mask0 = v_reinterpret_as_f32(v_ne(v_masku320, v_reinterpret_as_u32(v_0)));
v_float32 v_mask1 = v_reinterpret_as_f32(v_ne(v_masku321, v_reinterpret_as_u32(v_0)));
v_float32 v_src00, v_src01;
v_float32 v_src10, v_src11;
v_float32 v_src20, v_src21;
v_float32 v_src30, v_src31;
v_load_deinterleave(src + x * cn,
v_src00, v_src10, v_src20, v_src30);
v_load_deinterleave(src + (x + step) * cn,
v_src01, v_src11, v_src21, v_src31);
v_src00 = v_and(v_src00, v_mask0);
v_src10 = v_and(v_src10, v_mask0);
v_src20 = v_and(v_src20, v_mask0);
v_src30 = v_and(v_src30, v_mask0);
v_src01 = v_and(v_src01, v_mask1);
v_src11 = v_and(v_src11, v_mask1);
v_src21 = v_and(v_src21, v_mask1);
v_src31 = v_and(v_src31, v_mask1);
v_float32 v_dst00, v_dst01;
v_float32 v_dst10, v_dst11;
v_float32 v_dst20, v_dst21;
v_float32 v_dst30, v_dst31;
v_load_deinterleave(dst + x * cn, v_dst00, v_dst10, v_dst20, v_dst30);
v_load_deinterleave(dst + (x + step) * cn, v_dst01, v_dst11, v_dst21, v_dst31);
v_store_interleave(dst + x * cn,
v_add(v_dst00, v_src00),
v_add(v_dst10, v_src10),
v_add(v_dst20, v_src20),
v_add(v_dst30, v_src30));
v_store_interleave(dst + (x + step) * cn,
v_add(v_dst01, v_src01),
v_add(v_dst11, v_src11),
v_add(v_dst21, v_src21),
v_add(v_dst31, v_src31));
}
}
}
else if (cn == 3)
{
for ( ; x <= len - cVectorWidth ; x += cVectorWidth)
{
v_uint16 v_masku16 = vx_load_expand(mask + x);
v_uint32 v_masku320, v_masku321;
v_expand(v_masku16, v_masku320, v_masku321);
v_float32 v_mask0 = v_reinterpret_as_f32(v_not(v_eq(v_masku320, v_reinterpret_as_u32(v_0))));
v_float32 v_mask1 = v_reinterpret_as_f32(v_not(v_eq(v_masku321, v_reinterpret_as_u32(v_0))));
v_float32 v_src00, v_src01, v_src10, v_src11, v_src20, v_src21;
v_load_deinterleave(src + x * cn, v_src00, v_src10, v_src20);
v_load_deinterleave(src + (x + step) * cn, v_src01, v_src11, v_src21);
v_src00 = v_and(v_src00, v_mask0);
v_src01 = v_and(v_src01, v_mask1);
v_src10 = v_and(v_src10, v_mask0);
v_src11 = v_and(v_src11, v_mask1);
v_src20 = v_and(v_src20, v_mask0);
v_src21 = v_and(v_src21, v_mask1);
v_float32 v_dst00, v_dst01, v_dst10, v_dst11, v_dst20, v_dst21;
v_load_deinterleave(dst + x * cn, v_dst00, v_dst10, v_dst20);
v_load_deinterleave(dst + (x + step) * cn, v_dst01, v_dst11, v_dst21);
v_store_interleave(dst + x * cn, v_add(v_dst00, v_src00), v_add(v_dst10, v_src10), v_add(v_dst20, v_src20));
v_store_interleave(dst + (x + step) * cn, v_add(v_dst01, v_src01), v_add(v_dst11, v_src11), v_add(v_dst21, v_src21));
}
}
}
#endif // CV_SIMD
acc_general_(src, dst, mask, len, cn, x);
@@ -3106,4 +3270,4 @@ CV_CPU_OPTIMIZATION_NAMESPACE_END
} // namespace cv
///* End of file. */
///* End of file. */
+1 -1
View File
@@ -649,7 +649,7 @@ void cv::findContours(InputArray _image,
}
// Fast path: RETR_LIST without hierarchy → findTRUContours (parallel contour extraction)
if (mode == RETR_LIST && !_hierarchy.needed())
if (mode == RETR_LIST && !_hierarchy.needed() && _image.type() == CV_8UC1)
{
// findTRUContours requires FOREGROUND=255; binarize=true thresholds the padded
// image in-place, avoiding an extra allocation (findContours accepts any non-zero value)
+1 -1
View File
@@ -618,7 +618,7 @@ void findTRUContours(InputArray _src, OutputArrayOfArrays _contours, int minSize
{
CV_INSTRUMENT_REGION();
Mat src = _src.getMat();
CV_Assert(!src.empty() && src.type() == CV_8UC1);
CV_Assert(src.type() == CV_8UC1);
// Buffer handling
cv::Mat padded;
+46 -15
View File
@@ -415,22 +415,21 @@ public:
int w = std::min(tileSize, dst.cols - dst_x);
int h = std::min(tileSize, dst.rows - dst_y);
int src_x1 = dst_x - dx1, src_y1 = dst_y - dy1;
int src_x2 = dst_x + w + dx2, src_y2 = dst_y + h + dy2;
Size wholeSize;
Point ofs;
src.locateROI(wholeSize, ofs);
// Parent coordinates.
int src_x1 = ofs.x + dst_x - dx1, src_y1 = ofs.y + dst_y - dy1;
int src_x2 = ofs.x + dst_x + w + dx2,
src_y2 = ofs.y + dst_y + h + dy2;
int pad_top = std::max(0, -src_y1);
int pad_bottom = std::max(0, src_y2 - src.rows);
int pad_bottom = std::max(0, src_y2 - wholeSize.height);
int pad_left = std::max(0, -src_x1);
int pad_right = std::max(0, src_x2 - src.cols);
int pad_right = std::max(0, src_x2 - wholeSize.width);
int clamped_x1 = std::max(0, src_x1);
int clamped_y1 = std::max(0, src_y1);
int clamped_x2 = std::min(src.cols, src_x2);
int clamped_y2 = std::min(src.rows, src_y2);
Mat src_region = src(Rect(clamped_x1, clamped_y1,
clamped_x2 - clamped_x1,
clamped_y2 - clamped_y1));
Mat src_region = src(Rect(dst_x, dst_y, w, h)).adjustROI(dy1, dy2, dx1, dx2);
Mat tile_mat;
if (pad_top == 0 && pad_bottom == 0 && pad_left == 0 && pad_right == 0)
@@ -542,9 +541,41 @@ void FilterEngine__apply(FilterEngine& this_, const Mat& src, Mat& dst, const Si
(size_t)src.total() >= std::max((size_t)1024 * 1024, (size_t)nthreads * 64 * 1024) &&
this_.rowBorderType == this_.columnBorderType)
{
// For in-place operations (e.g. morphologyEx MORPH_OPEN), clone src so that
// concurrent tiles read from an immutable snapshot rather than racing on writes.
Mat src_copy = (src.data == dst.data) ? src.clone() : src;
// Robust cloning for in-place/overlapping operations with ROI support.
Size resolved_wsz = wsz;
Point resolved_ofs = ofs;
if (resolved_wsz.width < 0) {
src.locateROI(resolved_wsz, resolved_ofs);
}
bool overlap = (src.data <= dst.dataend && dst.data <= src.dataend);
Mat src_copy;
if (resolved_wsz == src.size()) {
src_copy = overlap ? src.clone() : src;
} else {
// In case of ROI.
Mat parent(resolved_wsz, src.type(),
(void*)(src.data - resolved_ofs.y * src.step -
resolved_ofs.x * src.elemSize()),
src.step);
if (overlap) {
int dx1 = this_.anchor.x, dx2 = this_.ksize.width - dx1 - 1;
int dy1 = this_.anchor.y, dy2 = this_.ksize.height - dy1 - 1;
int p_x1 = std::max(0, resolved_ofs.x - dx1);
int p_y1 = std::max(0, resolved_ofs.y - dy1);
// Clone the required region only.
Mat required_region = parent(Rect(resolved_ofs, src.size())).adjustROI(dy1, dy2, dx1, dx2).clone();
src_copy = required_region(Rect(resolved_ofs - Point(p_x1, p_y1), src.size()));
} else {
// Actually src_copy = src but makes sure src_copy is seen as a sub-matrix
// because sepFilter2D creates a submatrix on the fly without having it be
// an official sub-matrix (which would make locateROI fail in TiledFilterInvoker)
src_copy = parent(Rect(resolved_ofs, src.size()));
}
}
// Heuristic: Balance L2 cache locality (128) vs parallel load balancing (64).
int tileSize = (src.total() < (size_t)nthreads * 128 * 128 * 4) ? 64 : 128;
+24
View File
@@ -1409,6 +1409,30 @@ inline int hal_ni_laplacian(const uchar* src_data, size_t src_step, uchar* dst_d
#define cv_hal_laplacian hal_ni_laplacian
//! @endcond
/**
@brief Compute spatial gradient (Sobel X and Y simultaneously).
@param src_data Source image data (8-bit single channel)
@param src_step Source image step
@param dx_data Destination X-gradient data (16-bit signed)
@param dx_step Destination X-gradient step
@param dy_data Destination Y-gradient data (16-bit signed)
@param dy_step Destination Y-gradient step
@param width Image width
@param height Image height
@param ksize Kernel size (must be 3)
@param border_type Border type (BORDER_DEFAULT or BORDER_REPLICATE)
*/
inline int hal_ni_spatialGradient(const uchar* src_data, size_t src_step,
short* dx_data, size_t dx_step,
short* dy_data, size_t dy_step,
int width, int height,
int ksize, int border_type)
{ return CV_HAL_ERROR_NOT_IMPLEMENTED; }
//! @cond IGNORED
#define cv_hal_spatialGradient hal_ni_spatialGradient
//! @endcond
/**
@brief Perform Gaussian Blur and downsampling for input tile.
@param depth Depths of source and destination image
+7
View File
@@ -113,6 +113,13 @@ void spatialGradient( InputArray _src, OutputArray _dx, OutputArray _dy,
// TODO: Allow for other kernel sizes
CV_Assert(ksize == 3);
CALL_HAL(spatialGradient, cv_hal_spatialGradient,
src.data, src.step,
dx.ptr<short>(), dx.step,
dy.ptr<short>(), dy.step,
src.cols, src.rows,
ksize, borderType);
// Get dimensions
const int H = src.rows,
W = src.cols;
+57
View File
@@ -1450,4 +1450,61 @@ TEST(Imgproc_Filter2D, padding_bounds_roi_isolated)
}
}
class FastFilterEngineTest : public ::testing::Test {
protected:
void SetUp() override {
// Prepare separable kernels (3x3 averaging filter [1, 1, 1]).
kX = cv::Mat::ones(1, 3, CV_32F) / 3.0f;
kY = cv::Mat::ones(3, 1, CV_32F) / 3.0f;
}
cv::Mat kX, kY;
};
TEST_F(FastFilterEngineTest, Submatrix) {
// num_threads == 2 triggers the fast path.
for(int num_threads : {1, 2}) {
setNumThreads(num_threads);
Mat1b parent(1200, 1200, 255);
Mat roi = parent(Rect(100, 100, 1024, 1024));
roi.setTo(Scalar(0));
Mat dst;
sepFilter2D(roi, dst, -1, kX, kY, Point(-1, -1), 0, BORDER_REPLICATE);
// Before fix in fast path: dst.at<uchar>(0,0) == 0 (treated as isolated).
// With fix in fast path: dst.at<uchar>(0,0) > 0 (correctly reads 255 padding from parent).
EXPECT_GT(dst.at<uchar>(0, 0), 0);
// Filter in-place directly into 'roi' (dst == roi).
sepFilter2D(roi, roi, -1, kX, kY, Point(-1, -1), 0, BORDER_REPLICATE);
// Before fix in fast path: roi.at<uchar>(0,0) == 0 (cloned only ROI, lost parent padding).
// With fix in fast path: roi.at<uchar>(0,0) > 0 (clones required_region including padding).
EXPECT_GT(roi.at<uchar>(0, 0), 0);
}
}
TEST_F(FastFilterEngineTest, FullImage) {
// num_threads == 2 triggers the fast path.
for(int num_threads : {1, 2}) {
setNumThreads(num_threads);
Mat1b img(1024, 1024, 100);
Mat dst;
sepFilter2D(img, dst, -1, kX, kY, Point(-1, -1), 0, BORDER_REPLICATE);
// Verifies direct pass-through (src_copy = src) executes correctly.
EXPECT_EQ(dst.at<uchar>(0, 0), 100);
// Filter in-place directly into 'img' (dst == img).
sepFilter2D(img, img, -1, kX, kY, Point(-1, -1), 0, BORDER_REPLICATE);
// Verifies that full-image cloning (src.clone()) executes correctly without memory corruption.
EXPECT_EQ(img.at<uchar>(0, 0), 100);
}
}
}} // namespace