OpenCV每日函数 几何图像变换模块 (1) convertMaps函数

一、概述

        将图像转换映射从一种表示转换为另一种表示。该函数将一对用于重映射的映射从一种表示转换为另一种表示。 支持以下选项( (map1.type(), map2.type()) → (dstmap1.type(), dstmap2.type()) ):

        (CV_32FC1, CV_32FC1)→(CV_16SC2, CV_16UC1).

        这是最常用的转换操作,其中原始浮点映射(请参阅重映射)被转换为更紧凑和更快的定点表示。 第一个输出数组包含四舍五入的坐标,第二个数组(仅在 nninterpolation=false 时创建)包含插值表中的索引。

        (CV_32FC2)→(CV_16SC2, CV_16UC1).

        同上,但原始地图存储在一个 2 通道矩阵中。

        反向转换。 显然,重建的浮点映射不会与原始映射完全相同。定点格式将 (x,y) 坐标的整数和小数部分拆分为不同的map。CV_32FC2 或者 2x CV_32FC1,每个像素使用 8 个字节,而每个像素CV_16SC2 + CV_16UC1使用 6 个字节。也是仅整数,因此使用它可以释放浮点计算资源用于其他工作。

二、convertMaps函数

1、函数原型

cv::convertMaps (InputArray map1, InputArray map2, OutputArray dstmap1, OutputArray dstmap2, int dstmap1type, bool nninterpolation=false)

2、参数详解

map1 CV_16SC2、CV_32FC1 或 CV_32FC2 类型的第一个输入映射。
map2 分别为 CV_16UC1、CV_32FC1 或无(空矩阵)类型的第二个输入映射。
dstmap1 第一个具有 dstmap1type 类型且大小与 src 相同的输出映射。
dstmap2 第二个输出图。
dstmap1type 第一个输出映射的类型应该是 CV_16SC2、CV_32FC1 或 CV_32FC2。
nninterpolation 指示定点图是用于最近邻还是用于更复杂的插值的标志。

三、OpenCV源码

1、源码路径

opencv\modules\imgproc\src\imgwarp.cpp

2、源码代码

void cv::convertMaps( InputArray _map1, InputArray _map2,
                      OutputArray _dstmap1, OutputArray _dstmap2,
                      int dstm1type, bool nninterpolate )
{
    CV_INSTRUMENT_REGION();

    Mat map1 = _map1.getMat(), map2 = _map2.getMat(), dstmap1, dstmap2;
    Size size = map1.size();
    const Mat *m1 = &map1, *m2 = &map2;
    int m1type = m1->type(), m2type = m2->type();

    CV_Assert( (m1type == CV_16SC2 && (nninterpolate || m2type == CV_16UC1 || m2type == CV_16SC1)) ||
               (m2type == CV_16SC2 && (nninterpolate || m1type == CV_16UC1 || m1type == CV_16SC1)) ||
               (m1type == CV_32FC1 && m2type == CV_32FC1) ||
               (m1type == CV_32FC2 && m2->empty()) );

    if( m2type == CV_16SC2 )
    {
        std::swap( m1, m2 );
        std::swap( m1type, m2type );
    }

    if( dstm1type <= 0 )
        dstm1type = m1type == CV_16SC2 ? CV_32FC2 : CV_16SC2;
    CV_Assert( dstm1type == CV_16SC2 || dstm1type == CV_32FC1 || dstm1type == CV_32FC2 );
    _dstmap1.create( size, dstm1type );
    dstmap1 = _dstmap1.getMat();

    if( !nninterpolate && dstm1type != CV_32FC2 )
    {
        _dstmap2.create( size, dstm1type == CV_16SC2 ? CV_16UC1 : CV_32FC1 );
        dstmap2 = _dstmap2.getMat();
    }
    else
        _dstmap2.release();

    if( m1type == dstm1type || (nninterpolate &&
        ((m1type == CV_16SC2 && dstm1type == CV_32FC2) ||
        (m1type == CV_32FC2 && dstm1type == CV_16SC2))) )
    {
        m1->convertTo( dstmap1, dstmap1.type() );
        if( !dstmap2.empty() && dstmap2.type() == m2->type() )
            m2->copyTo( dstmap2 );
        return;
    }

    if( m1type == CV_32FC1 && dstm1type == CV_32FC2 )
    {
        Mat vdata[] = { *m1, *m2 };
        merge( vdata, 2, dstmap1 );
        return;
    }

    if( m1type == CV_32FC2 && dstm1type == CV_32FC1 )
    {
        Mat mv[] = { dstmap1, dstmap2 };
        split( *m1, mv );
        return;
    }

    if( m1->isContinuous() && (m2->empty() || m2->isContinuous()) &&
        dstmap1.isContinuous() && (dstmap2.empty() || dstmap2.isContinuous()) )
    {
        size.width *= size.height;
        size.height = 1;
    }

#if CV_TRY_SSE4_1
    bool useSSE4_1 = CV_CPU_HAS_SUPPORT_SSE4_1;
#endif

    const float scale = 1.f/INTER_TAB_SIZE;
    int x, y;
    for( y = 0; y < size.height; y++ )
    {
        const float* src1f = m1->ptr<float>(y);
        const float* src2f = m2->ptr<float>(y);
        const short* src1 = (const short*)src1f;
        const ushort* src2 = (const ushort*)src2f;

        float* dst1f = dstmap1.ptr<float>(y);
        float* dst2f = dstmap2.ptr<float>(y);
        short* dst1 = (short*)dst1f;
        ushort* dst2 = (ushort*)dst2f;
        x = 0;

        if( m1type == CV_32FC1 && dstm1type == CV_16SC2 )
        {
            if( nninterpolate )
            {
                #if CV_TRY_SSE4_1
                if (useSSE4_1)
                    opt_SSE4_1::convertMaps_nninterpolate32f1c16s_SSE41(src1f, src2f, dst1, size.width);
                else
                #endif
                {
                    #if CV_SIMD128
                    {
                        int span = v_int16x8::nlanes;
                        for( ; x <= size.width - span; x += span )
                        {
                            v_int16x8 v_dst[2];
                            #define CV_PACK_MAP(X) v_pack(v_round(v_load(X)), v_round(v_load((X)+4)))
                            v_dst[0] = CV_PACK_MAP(src1f + x);
                            v_dst[1] = CV_PACK_MAP(src2f + x);
                            #undef CV_PACK_MAP
                            v_store_interleave(dst1 + (x << 1), v_dst[0], v_dst[1]);
                        }
                    }
                    #endif
                    for( ; x < size.width; x++ )
                    {
                        dst1[x*2] = saturate_cast<short>(src1f[x]);
                        dst1[x*2+1] = saturate_cast<short>(src2f[x]);
                    }
                }
            }
            else
            {
                #if CV_TRY_SSE4_1
                if (useSSE4_1)
                    opt_SSE4_1::convertMaps_32f1c16s_SSE41(src1f, src2f, dst1, dst2, size.width);
                else
                #endif
                {
                    #if CV_SIMD128
                    {
                        v_float32x4 v_scale = v_setall_f32((float)INTER_TAB_SIZE);
                        v_int32x4 v_mask = v_setall_s32(INTER_TAB_SIZE - 1);
                        v_int32x4 v_scale3 = v_setall_s32(INTER_TAB_SIZE);
                        int span = v_float32x4::nlanes;
                        for( ; x <= size.width - span * 2; x += span * 2 )
                        {
                            v_int32x4 v_ix0 = v_round(v_scale * (v_load(src1f + x)));
                            v_int32x4 v_ix1 = v_round(v_scale * (v_load(src1f + x + span)));
                            v_int32x4 v_iy0 = v_round(v_scale * (v_load(src2f + x)));
                            v_int32x4 v_iy1 = v_round(v_scale * (v_load(src2f + x + span)));

                            v_int16x8 v_dst[2];
                            v_dst[0] = v_pack(v_shr<INTER_BITS>(v_ix0), v_shr<INTER_BITS>(v_ix1));
                            v_dst[1] = v_pack(v_shr<INTER_BITS>(v_iy0), v_shr<INTER_BITS>(v_iy1));
                            v_store_interleave(dst1 + (x << 1), v_dst[0], v_dst[1]);

                            v_int32x4 v_dst0 = v_muladd(v_scale3, (v_iy0 & v_mask), (v_ix0 & v_mask));
                            v_int32x4 v_dst1 = v_muladd(v_scale3, (v_iy1 & v_mask), (v_ix1 & v_mask));
                            v_store(dst2 + x, v_pack_u(v_dst0, v_dst1));
                        }
                    }
                    #endif
                    for( ; x < size.width; x++ )
                    {
                        int ix = saturate_cast<int>(src1f[x]*INTER_TAB_SIZE);
                        int iy = saturate_cast<int>(src2f[x]*INTER_TAB_SIZE);
                        dst1[x*2] = saturate_cast<short>(ix >> INTER_BITS);
                        dst1[x*2+1] = saturate_cast<short>(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 )
            {
                #if CV_SIMD128
                int span = v_float32x4::nlanes;
                {
                    for( ; x <= (size.width << 1) - span * 2; x += span * 2 )
                        v_store(dst1 + x, v_pack(v_round(v_load(src1f + x)),
                                                 v_round(v_load(src1f + x + span))));
                }
                #endif
                for( ; x < size.width; x++ )
                {
                    dst1[x*2] = saturate_cast<short>(src1f[x*2]);
                    dst1[x*2+1] = saturate_cast<short>(src1f[x*2+1]);
                }
            }
            else
            {
                #if CV_TRY_SSE4_1
                if( useSSE4_1 )
                    opt_SSE4_1::convertMaps_32f2c16s_SSE41(src1f, dst1, dst2, size.width);
                else
                #endif
                {
                    #if CV_SIMD128
                    {
                        v_float32x4 v_scale = v_setall_f32((float)INTER_TAB_SIZE);
                        v_int32x4 v_mask = v_setall_s32(INTER_TAB_SIZE - 1);
                        v_int32x4 v_scale3 = v_setall_s32(INTER_TAB_SIZE);
                        int span = v_uint16x8::nlanes;
                        for (; x <= size.width - span; x += span )
                        {
                            v_float32x4 v_src0[2], v_src1[2];
                            v_load_deinterleave(src1f + (x << 1), v_src0[0], v_src0[1]);
                            v_load_deinterleave(src1f + (x << 1) + span, v_src1[0], v_src1[1]);
                            v_int32x4 v_ix0 = v_round(v_src0[0] * v_scale);
                            v_int32x4 v_ix1 = v_round(v_src1[0] * v_scale);
                            v_int32x4 v_iy0 = v_round(v_src0[1] * v_scale);
                            v_int32x4 v_iy1 = v_round(v_src1[1] * v_scale);

                            v_int16x8 v_dst[2];
                            v_dst[0] = v_pack(v_shr<INTER_BITS>(v_ix0), v_shr<INTER_BITS>(v_ix1));
                            v_dst[1] = v_pack(v_shr<INTER_BITS>(v_iy0), v_shr<INTER_BITS>(v_iy1));
                            v_store_interleave(dst1 + (x << 1), v_dst[0], v_dst[1]);

                            v_store(dst2 + x, v_pack_u(
                                v_muladd(v_scale3, (v_iy0 & v_mask), (v_ix0 & v_mask)),
                                v_muladd(v_scale3, (v_iy1 & v_mask), (v_ix1 & v_mask))));
                        }
                    }
                    #endif
                    for( ; x < size.width; x++ )
                    {
                        int ix = saturate_cast<int>(src1f[x*2]*INTER_TAB_SIZE);
                        int iy = saturate_cast<int>(src1f[x*2+1]*INTER_TAB_SIZE);
                        dst1[x*2] = saturate_cast<short>(ix >> INTER_BITS);
                        dst1[x*2+1] = saturate_cast<short>(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 )
        {
            #if CV_SIMD128
            {
                v_uint16x8 v_mask2 =  v_setall_u16(INTER_TAB_SIZE2-1);
                v_uint32x4 v_zero =   v_setzero_u32(), v_mask = v_setall_u32(INTER_TAB_SIZE-1);
                v_float32x4 v_scale = v_setall_f32(scale);
                int span = v_float32x4::nlanes;
                for( ; x <= size.width - span * 2; x += span * 2 )
                {
                    v_uint32x4 v_fxy1, v_fxy2;
                    if ( src2 )
                    {
                        v_uint16x8 v_src2 = v_load(src2 + x) & v_mask2;
                        v_expand(v_src2, v_fxy1, v_fxy2);
                    }
                    else
                        v_fxy1 = v_fxy2 = v_zero;

                    v_int16x8 v_src[2];
                    v_int32x4 v_src0[2], v_src1[2];
                    v_load_deinterleave(src1 + (x << 1), v_src[0], v_src[1]);
                    v_expand(v_src[0], v_src0[0], v_src0[1]);
                    v_expand(v_src[1], v_src1[0], v_src1[1]);
                    #define CV_COMPUTE_MAP_X(X, FXY)  v_muladd(v_scale, v_cvt_f32(v_reinterpret_as_s32((FXY) & v_mask)),\
                                                                        v_cvt_f32(v_reinterpret_as_s32(X)))
                    #define CV_COMPUTE_MAP_Y(Y, FXY)  v_muladd(v_scale, v_cvt_f32(v_reinterpret_as_s32((FXY) >> INTER_BITS)),\
                                                                        v_cvt_f32(v_reinterpret_as_s32(Y)))
                    v_float32x4 v_dst1 = CV_COMPUTE_MAP_X(v_src0[0], v_fxy1);
                    v_float32x4 v_dst2 = CV_COMPUTE_MAP_Y(v_src1[0], v_fxy1);
                    v_store(dst1f + x, v_dst1);
                    v_store(dst2f + x, v_dst2);

                    v_dst1 = CV_COMPUTE_MAP_X(v_src0[1], v_fxy2);
                    v_dst2 = CV_COMPUTE_MAP_Y(v_src1[1], v_fxy2);
                    v_store(dst1f + x + span, v_dst1);
                    v_store(dst2f + x + span, v_dst2);
                    #undef CV_COMPUTE_MAP_X
                    #undef CV_COMPUTE_MAP_Y
                }
            }
            #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;
                dst2f[x] = src1[x*2+1] + (fxy >> INTER_BITS)*scale;
            }
        }
        else if( m1type == CV_16SC2 && dstm1type == CV_32FC2 )
        {
            #if CV_SIMD128
            {
                v_int16x8 v_mask2 = v_setall_s16(INTER_TAB_SIZE2-1);
                v_int32x4 v_zero = v_setzero_s32(), v_mask = v_setall_s32(INTER_TAB_SIZE-1);
                v_float32x4 v_scale = v_setall_f32(scale);
                int span = v_int16x8::nlanes;
                for( ; x <= size.width - span; x += span )
                {
                    v_int32x4 v_fxy1, v_fxy2;
                    if (src2)
                    {
                        v_int16x8 v_src2 = v_load((short *)src2 + x) & v_mask2;
                        v_expand(v_src2, v_fxy1, v_fxy2);
                    }
                    else
                        v_fxy1 = v_fxy2 = v_zero;

                    v_int16x8 v_src[2];
                    v_int32x4 v_src0[2], v_src1[2];
                    v_float32x4 v_dst[2];
                    v_load_deinterleave(src1 + (x << 1), v_src[0], v_src[1]);
                    v_expand(v_src[0], v_src0[0], v_src0[1]);
                    v_expand(v_src[1], v_src1[0], v_src1[1]);

                    #define CV_COMPUTE_MAP_X(X, FXY) v_muladd(v_scale, v_cvt_f32((FXY) & v_mask), v_cvt_f32(X))
                    #define CV_COMPUTE_MAP_Y(Y, FXY) v_muladd(v_scale, v_cvt_f32((FXY) >> INTER_BITS), v_cvt_f32(Y))
                    v_dst[0] = CV_COMPUTE_MAP_X(v_src0[0], v_fxy1);
                    v_dst[1] = CV_COMPUTE_MAP_Y(v_src1[0], v_fxy1);
                    v_store_interleave(dst1f + (x << 1), v_dst[0], v_dst[1]);

                    v_dst[0] = CV_COMPUTE_MAP_X(v_src0[1], v_fxy2);
                    v_dst[1] = CV_COMPUTE_MAP_Y(v_src1[1], v_fxy2);
                    v_store_interleave(dst1f + (x << 1) + span, v_dst[0], v_dst[1]);
                    #undef CV_COMPUTE_MAP_X
                    #undef CV_COMPUTE_MAP_Y
                }
            }
            #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;
                dst1f[x*2+1] = src1[x*2+1] + (fxy >> INTER_BITS)*scale;
            }
        }
        else
            CV_Error( CV_StsNotImplemented, "Unsupported combination of input/output matrices" );
    }
}

猜你喜欢

转载自blog.csdn.net/bashendixie5/article/details/125259291