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:
@@ -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
@@ -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. */
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user