From 1fe5441185632cd9f6099ae629b5c67b28fdcc38 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Sun, 12 Oct 2014 13:37:59 -0700 Subject: [PATCH] cv::convertMaps --- modules/imgproc/src/imgwarp.cpp | 156 ++++++++++++++++++++++- modules/imgproc/src/pyramids.cpp | 2 +- modules/imgproc/test/test_histograms.cpp | 2 +- modules/imgproc/test/test_imgwarp.cpp | 2 +- 4 files changed, 153 insertions(+), 9 deletions(-) diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp index a43b194f62..d952b60ea8 100644 --- a/modules/imgproc/src/imgwarp.cpp +++ b/modules/imgproc/src/imgwarp.cpp @@ -4557,17 +4557,59 @@ void cv::convertMaps( InputArray _map1, InputArray _map2, float* dst2f = dstmap2.ptr(y); short* dst1 = (short*)dst1f; ushort* dst2 = (ushort*)dst2f; + x = 0; if( m1type == CV_32FC1 && dstm1type == CV_16SC2 ) { if( nninterpolate ) - for( x = 0; x < size.width; x++ ) + { + #if CV_NEON + for( ; x <= size.width - 8; x += 8 ) + { + int16x8x2_t v_dst; + v_dst.val[0] = vcombine_s16(vqmovn_s32(cv_vrndq_s32_f32(vld1q_f32(src1f + x))), + vqmovn_s32(cv_vrndq_s32_f32(vld1q_f32(src1f + x + 4)))); + v_dst.val[1] = vcombine_s16(vqmovn_s32(cv_vrndq_s32_f32(vld1q_f32(src2f + x))), + vqmovn_s32(cv_vrndq_s32_f32(vld1q_f32(src2f + x + 4)))); + + vst2q_s16(dst1 + (x << 1), v_dst); + } + #endif + for( ; x < size.width; x++ ) { dst1[x*2] = saturate_cast(src1f[x]); dst1[x*2+1] = saturate_cast(src2f[x]); } + } else - for( x = 0; x < size.width; x++ ) + { + #if CV_NEON + float32x4_t v_scale = vdupq_n_f32((float)INTER_TAB_SIZE); + int32x4_t v_mask = vdupq_n_s32(INTER_TAB_SIZE - 1); + + for( ; x <= size.width - 8; x += 8 ) + { + int32x4_t v_ix0 = cv_vrndq_s32_f32(vmulq_f32(vld1q_f32(src1f + x), v_scale)); + int32x4_t v_ix1 = cv_vrndq_s32_f32(vmulq_f32(vld1q_f32(src1f + x + 4), v_scale)); + int32x4_t v_iy0 = cv_vrndq_s32_f32(vmulq_f32(vld1q_f32(src2f + x), v_scale)); + int32x4_t v_iy1 = cv_vrndq_s32_f32(vmulq_f32(vld1q_f32(src2f + x + 4), v_scale)); + + int16x8x2_t v_dst; + v_dst.val[0] = vcombine_s16(vqmovn_s32(vshrq_n_s32(v_ix0, INTER_BITS)), + vqmovn_s32(vshrq_n_s32(v_ix1, INTER_BITS))); + v_dst.val[1] = vcombine_s16(vqmovn_s32(vshrq_n_s32(v_iy0, INTER_BITS)), + vqmovn_s32(vshrq_n_s32(v_iy1, INTER_BITS))); + + vst2q_s16(dst1 + (x << 1), v_dst); + + uint16x4_t v_dst0 = vqmovun_s32(vaddq_s32(vshlq_n_s32(vandq_s32(v_iy0, v_mask), INTER_BITS), + vandq_s32(v_ix0, v_mask))); + uint16x4_t v_dst1 = vqmovun_s32(vaddq_s32(vshlq_n_s32(vandq_s32(v_iy1, v_mask), INTER_BITS), + vandq_s32(v_ix1, v_mask))); + vst1q_u16(dst2 + x, vcombine_u16(v_dst0, v_dst1)); + } + #endif + for( ; x < size.width; x++ ) { int ix = saturate_cast(src1f[x]*INTER_TAB_SIZE); int iy = saturate_cast(src2f[x]*INTER_TAB_SIZE); @@ -4575,17 +4617,53 @@ void cv::convertMaps( InputArray _map1, InputArray _map2, dst1[x*2+1] = saturate_cast(iy >> INTER_BITS); dst2[x] = (ushort)((iy & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + (ix & (INTER_TAB_SIZE-1))); } + } } else if( m1type == CV_32FC2 && dstm1type == CV_16SC2 ) { if( nninterpolate ) - for( x = 0; x < size.width; x++ ) + { + #if CV_NEON + for( ; x <= (size.width << 1) - 8; x += 8 ) + vst1q_s16(dst1 + x, vcombine_s16(vqmovn_s32(cv_vrndq_s32_f32(vld1q_f32(src1f + x))), + vqmovn_s32(cv_vrndq_s32_f32(vld1q_f32(src1f + x + 4))))); + #endif + for( ; x < size.width; x++ ) { dst1[x*2] = saturate_cast(src1f[x*2]); dst1[x*2+1] = saturate_cast(src1f[x*2+1]); } + } else - for( x = 0; x < size.width; x++ ) + { + #if CV_NEON + float32x4_t v_scale = vdupq_n_f32((float)INTER_TAB_SIZE); + int32x4_t v_mask = vdupq_n_s32(INTER_TAB_SIZE - 1); + + for( ; x <= size.width - 8; x += 8 ) + { + float32x4x2_t v_src0 = vld2q_f32(src1f + (x << 1)), v_src1 = vld2q_f32(src1f + (x << 1) + 8); + int32x4_t v_ix0 = cv_vrndq_s32_f32(vmulq_f32(v_src0.val[0], v_scale)); + int32x4_t v_ix1 = cv_vrndq_s32_f32(vmulq_f32(v_src1.val[0], v_scale)); + int32x4_t v_iy0 = cv_vrndq_s32_f32(vmulq_f32(v_src0.val[1], v_scale)); + int32x4_t v_iy1 = cv_vrndq_s32_f32(vmulq_f32(v_src1.val[1], v_scale)); + + int16x8x2_t v_dst; + v_dst.val[0] = vcombine_s16(vqmovn_s32(vshrq_n_s32(v_ix0, INTER_BITS)), + vqmovn_s32(vshrq_n_s32(v_ix1, INTER_BITS))); + v_dst.val[1] = vcombine_s16(vqmovn_s32(vshrq_n_s32(v_iy0, INTER_BITS)), + vqmovn_s32(vshrq_n_s32(v_iy1, INTER_BITS))); + + vst2q_s16(dst1 + (x << 1), v_dst); + + uint16x4_t v_dst0 = vqmovun_s32(vaddq_s32(vshlq_n_s32(vandq_s32(v_iy0, v_mask), INTER_BITS), + vandq_s32(v_ix0, v_mask))); + uint16x4_t v_dst1 = vqmovun_s32(vaddq_s32(vshlq_n_s32(vandq_s32(v_iy1, v_mask), INTER_BITS), + vandq_s32(v_ix1, v_mask))); + vst1q_u16(dst2 + x, vcombine_u16(v_dst0, v_dst1)); + } + #endif + for( ; x < size.width; x++ ) { int ix = saturate_cast(src1f[x*2]*INTER_TAB_SIZE); int iy = saturate_cast(src1f[x*2+1]*INTER_TAB_SIZE); @@ -4593,10 +4671,44 @@ void cv::convertMaps( InputArray _map1, InputArray _map2, dst1[x*2+1] = saturate_cast(iy >> INTER_BITS); dst2[x] = (ushort)((iy & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + (ix & (INTER_TAB_SIZE-1))); } + } } else if( m1type == CV_16SC2 && dstm1type == CV_32FC1 ) { - for( x = 0; x < size.width; x++ ) + #if CV_NEON + uint16x8_t v_mask2 = vdupq_n_u16(INTER_TAB_SIZE2-1); + uint32x4_t v_zero = vdupq_n_u32(0u), v_mask = vdupq_n_u32(INTER_TAB_SIZE-1); + float32x4_t v_scale = vdupq_n_f32(scale); + + for( ; x <= size.width - 8; x += 8) + { + uint32x4_t v_fxy1, v_fxy2; + if (src2) + { + uint16x8_t v_src2 = vandq_u16(vld1q_u16(src2 + x), v_mask2); + v_fxy1 = vmovl_u16(vget_low_u16(v_src2)); + v_fxy2 = vmovl_u16(vget_high_u16(v_src2)); + } + else + v_fxy1 = v_fxy2 = v_zero; + + int16x8x2_t v_src = vld2q_s16(src1 + (x << 1)); + float32x4_t v_dst1 = vmlaq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(v_src.val[0]))), + v_scale, vcvtq_f32_u32(vandq_u32(v_fxy1, v_mask))); + float32x4_t v_dst2 = vmlaq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(v_src.val[1]))), + v_scale, vcvtq_f32_u32(vshrq_n_u32(v_fxy1, INTER_BITS))); + vst1q_f32(dst1f + x, v_dst1); + vst1q_f32(dst2f + x, v_dst2); + + v_dst1 = vmlaq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(v_src.val[0]))), + v_scale, vcvtq_f32_u32(vandq_u32(v_fxy2, v_mask))); + v_dst2 = vmlaq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(v_src.val[1]))), + v_scale, vcvtq_f32_u32(vshrq_n_u32(v_fxy2, INTER_BITS))); + vst1q_f32(dst1f + x + 4, v_dst1); + vst1q_f32(dst2f + x + 4, v_dst2); + } + #endif + for( ; x < size.width; x++ ) { int fxy = src2 ? src2[x] & (INTER_TAB_SIZE2-1) : 0; dst1f[x] = src1[x*2] + (fxy & (INTER_TAB_SIZE-1))*scale; @@ -4605,7 +4717,39 @@ void cv::convertMaps( InputArray _map1, InputArray _map2, } else if( m1type == CV_16SC2 && dstm1type == CV_32FC2 ) { - for( x = 0; x < size.width; x++ ) + #if CV_NEON + int16x8_t v_mask2 = vdupq_n_s16(INTER_TAB_SIZE2-1); + int32x4_t v_zero = vdupq_n_s32(0), v_mask = vdupq_n_s32(INTER_TAB_SIZE-1); + float32x4_t v_scale = vdupq_n_f32(scale); + + for( ; x <= size.width - 8; x += 8) + { + int32x4_t v_fxy1, v_fxy2; + if (src2) + { + int16x8_t v_src2 = vandq_s16(vld1q_s16((short *)src2 + x), v_mask2); + v_fxy1 = vmovl_s16(vget_low_s16(v_src2)); + v_fxy2 = vmovl_s16(vget_high_s16(v_src2)); + } + else + v_fxy1 = v_fxy2 = v_zero; + + int16x8x2_t v_src = vld2q_s16(src1 + (x << 1)); + float32x4x2_t v_dst; + v_dst.val[0] = vmlaq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(v_src.val[0]))), + v_scale, vcvtq_f32_s32(vandq_s32(v_fxy1, v_mask))); + v_dst.val[1] = vmlaq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(v_src.val[1]))), + v_scale, vcvtq_f32_s32(vshrq_n_s32(v_fxy1, INTER_BITS))); + vst2q_f32(dst1f + (x << 1), v_dst); + + v_dst.val[0] = vmlaq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(v_src.val[0]))), + v_scale, vcvtq_f32_s32(vandq_s32(v_fxy2, v_mask))); + v_dst.val[1] = vmlaq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(v_src.val[1]))), + v_scale, vcvtq_f32_s32(vshrq_n_s32(v_fxy2, INTER_BITS))); + vst2q_f32(dst1f + (x << 1) + 8, v_dst); + } + #endif + for( ; x < size.width; x++ ) { int fxy = src2 ? src2[x] & (INTER_TAB_SIZE2-1): 0; dst1f[x*2] = src1[x*2] + (fxy & (INTER_TAB_SIZE-1))*scale; diff --git a/modules/imgproc/src/pyramids.cpp b/modules/imgproc/src/pyramids.cpp index 3a8e876aa3..e510530afd 100644 --- a/modules/imgproc/src/pyramids.cpp +++ b/modules/imgproc/src/pyramids.cpp @@ -286,7 +286,7 @@ struct PyrDownVec_32s16s v_r00 = vaddq_s32(vaddq_s32(v_r00, v_r40), vaddq_s32(v_r20, v_r20)); v_r10 = vaddq_s32(vaddq_s32(v_r10, v_r20), v_r30); v_r10 = vshlq_n_s32(v_r10, 2); - int32x4_t v_dst0 = vshrq_n_s32(vaddq_s32(vaddq_s32(v_r00, shifted), v_delta), 8); + int32x4_t v_dst0 = vshrq_n_s32(vaddq_s32(vaddq_s32(v_r00, v_r10), v_delta), 8); v_r01 = vaddq_s32(vaddq_s32(v_r01, v_r41), vaddq_s32(v_r21, v_r21)); v_r11 = vaddq_s32(vaddq_s32(v_r11, v_r21), v_r31); diff --git a/modules/imgproc/test/test_histograms.cpp b/modules/imgproc/test/test_histograms.cpp index e9db6fcde0..095b2c1fd9 100644 --- a/modules/imgproc/test/test_histograms.cpp +++ b/modules/imgproc/test/test_histograms.cpp @@ -1100,7 +1100,7 @@ int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ ) code = cvtest::TS::FAIL_INVALID_OUTPUT; break; } - else if( fabs(v0 - v) > FLT_EPSILON*10*MAX(fabs(v0),0.1) ) + else if( fabs(v0 - v) > FLT_EPSILON*14*MAX(fabs(v0),0.1) ) { ts->printf( cvtest::TS::LOG, "The comparison result using the method #%d (%s)\n\tis inaccurate (=%g, should be =%g)\n", i, method_name, v, v0 ); diff --git a/modules/imgproc/test/test_imgwarp.cpp b/modules/imgproc/test/test_imgwarp.cpp index 71c932ae16..34505c4ca4 100644 --- a/modules/imgproc/test/test_imgwarp.cpp +++ b/modules/imgproc/test/test_imgwarp.cpp @@ -1602,7 +1602,7 @@ TEST(Resize, Area_half) for (int i = 0, _size = sizeof(types) / sizeof(types[0]); i < _size; ++i) { int type = types[i], depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); - const float eps = depth <= CV_32S ? 0 : 5e-5; + const float eps = depth <= CV_32S ? 0 : 7e-5f; SCOPED_TRACE(depth); SCOPED_TRACE(cn);