一、概述
将图像转换映射从一种表示转换为另一种表示。该函数将一对用于重映射的映射从一种表示转换为另一种表示。 支持以下选项( (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" );
}
}