OpenCV代码提取 remap函数的实现

图像重映射是像素从源图像到目标图像位置转换的过程,常涉及插值。OpenCV的remap函数用于此操作,支持uchar和float类型。文章介绍了向前映射和向后映射的概念,并提供了remap函数的实现代码。
摘要由CSDN通过智能技术生成
               

 图像重映射:即是把一个图像中一个位置的像素放置到另一个图像指定位置的过程。因为有时候源图像和目标图像并不总是一一对应的关系(目标图像的像素可能映射到源图像的非整数坐标上),所以有时候会需要做插值。

         描述映射过程:通过重映射来表达每个像素的位置(x,y):g(x,y) = f(h(x,y))

         其中:g()是目标图像,即重映射的结果;f()是源图像;h(x,y)是作用于(x,y)的映射方法函数。如h(x,y)=(I.cols-x,y),得到的目标图像将是按照x轴方向发生翻转。

         映射分为向前映射和向后映射。将输入映射到输出的向前映射,反正就是向后映射。即如果已知源图像到目标图像的坐标变换,即可以知道源图像的一点在变换后在目标图像的位置,称为向前映射。如果知道目标图像的一点在变换前在源图像上的位置,称为向后映射。向后映射比较直观,计算量小,OpenCV中经常使用的图像变换都是采用向后映射的方法来处理。但向后映射需要知道变换的反变换公式,但在有些变换比较复杂的场合,这个反变换是很难得到的。此时就需要采用前向映射的方法进行变换了。

 这里对OpenCV中remap函数进行了提取,目前支持uchar和float两种类型,经测试,与OpenCV3.1结果完全一致。

 实现代码remap.hpp:

// fbc_cv is free software and uses the same licence as OpenCV// Email: fengbingchun@163.com#ifndef FBC_CV_REMAP_HPP_#define FBC_CV_REMAP_HPP_/* reference: include/opencv2/imgproc.hpp              modules/imgproc/src/imgwarp.cpp*/#include <typeinfo>#include "core/mat.hpp"#include "core/base.hpp"#include "core/core.hpp"#include "imgproc.hpp"#include "resize.hpp"namespace fbc {
   const int INTER_REMAP_COEF_BITS = 15;const int INTER_REMAP_COEF_SCALE = 1 << INTER_REMAP_COEF_BITS;static uchar NNDeltaTab_i[INTER_TAB_SIZE2][2];static float BilinearTab_f[INTER_TAB_SIZE2][2][2];static short BilinearTab_i[INTER_TAB_SIZE2][2][2];static float BicubicTab_f[INTER_TAB_SIZE2][4][4];static short BicubicTab_i[INTER_TAB_SIZE2][4][4];static float Lanczos4Tab_f[INTER_TAB_SIZE2][8][8];static short Lanczos4Tab_i[INTER_TAB_SIZE2][8][8];template<typename _Tp1, typename _Tp2, int chs1, int chs2> static int remap_nearest(const Mat_<_Tp1, chs1>& src, Mat_<_Tp1, chs1>& dst, const Mat_<_Tp2, chs2>& map1, const Mat_<_Tp2, chs2>& map2, int borderMode, const Scalar& borderValue);template<typename _Tp1, typename _Tp2, int chs1, int chs2> static int remap_linear(const Mat_<_Tp1, chs1>& src, Mat_<_Tp1, chs1>& dst, const Mat_<_Tp2, chs2>& map1, const Mat_<_Tp2, chs2>& map2, int borderMode, const Scalar& borderValue);template<typename _Tp1, typename _Tp2, int chs1, int chs2> static int remap_cubic(const Mat_<_Tp1, chs1>& src, Mat_<_Tp1, chs1>& dst, const Mat_<_Tp2, chs2>& map1, const Mat_<_Tp2, chs2>& map2, int borderMode, const Scalar& borderValue);template<typename _Tp1, typename _Tp2, int chs1, int chs2> static int remap_lanczos4(const Mat_<_Tp1, chs1>& src, Mat_<_Tp1, chs1>& dst, const Mat_<_Tp2, chs2>& map1, const Mat_<_Tp2, chs2>& map2, int borderMode, const Scalar& borderValue);// Applies a generic geometrical transformation to an image// transforms the source image using the specified map, this function cannot operate in-place// support type: uchar/floattemplate<typename _Tp1, typename _Tp2, int chs1, int chs2>int remap(const Mat_<_Tp1, chs1>& src, Mat_<_Tp1, chs1>& dst, const Mat_<_Tp2, chs2>& map1, const Mat_<_Tp2, chs2>& map2, int interpolation, int borderMode = BORDER_CONSTANT, const Scalar& borderValue = Scalar()){ FBC_Assert(map1.size().area() > 0 && map1.size() == map2.size()); FBC_Assert(map1.data != NULL && map2.data != NULL); FBC_Assert(src.size() == map1.size() && src.size() == dst.size()); FBC_Assert(src.data != dst.data); FBC_Assert(typeid(uchar).name() == typeid(_Tp1).name() || typeid(float).name() == typeid(_Tp1).name()); // uchar || float FBC_Assert(typeid(float).name() == typeid(_Tp2).name()); FBC_Assert(chs2 == 1); switch (interpolation) {  case 0: {   remap_nearest(src, dst, map1, map2, borderMode, borderValue);   break;  }  case 1:  case 3: {   remap_linear(src, dst, map1, map2, borderMode, borderValue);   break;  }  case 2: {   remap_cubic(src, dst, map1, map2, borderMode, borderValue);   break;  }  case 4: {   remap_lanczos4(src, dst, map1, map2, borderMode, borderValue);   break;  }  default:   return -1; } return 0;}template<typename _Tp>static inline void interpolateLinear(_Tp x, _Tp* coeffs){ coeffs[0] = 1.f - x; coeffs[1] = x;}template<typename _Tp>static void initInterTab1D(int method, float* tab, int tabsz)float scale = 1.f / tabsz; if (method == INTER_LINEAR) {  for (int i = 0; i < tabsz; i++, tab += 2)   interpolateLinear<float>(i*scale, tab); } else if (method == INTER_CUBIC) {  for (int i = 0; i < tabsz; i++, tab += 4)   interpolateCubic<float>(i*scale, tab); } else if (method == INTER_LANCZOS4) {  for (int i = 0; i < tabsz; i++, tab += 8)   interpolateLanczos4<float>(i*scale, tab); } else {  FBC_Error("Unknown interpolation method"); }}template<typename _Tp>static const void* initInterTab2D(int method, bool fixpt)static bool inittab[INTER_MAX + 1] = { false }; float* tab = 0short* itab = 0int ksize = 0if (method == INTER_LINEAR) {  tab = BilinearTab_f[0][0], itab = BilinearTab_i[0][0], ksize = 2; } else if (method == INTER_CUBIC) {  tab = BicubicTab_f[0][0], itab = BicubicTab_i[0][0], ksize = 4; } else if (method == INTER_LANCZOS4) {  tab = Lanczos4Tab_f[0][0], itab = Lanczos4Tab_i[0][0], ksize = 8; } else {  FBC_Error("Unknown/unsupported interpolation type"); } if (!inittab[method]) {  AutoBuffer<float> _tab(8 * INTER_TAB_SIZE);  int i, j, k1, k2;  initInterTab1D<float>(method, _tab, INTER_TAB_SIZE);  for (i = 0; i < INTER_TAB_SIZE; i++) {   for (j = 0; j < INTER_TAB_SIZE; j++, tab += ksize*ksize, itab += ksize*ksize) {    int isum = 0;    NNDeltaTab_i[i*INTER_TAB_SIZE + j][0] = j < INTER_TAB_SIZE / 2;    NNDeltaTab_i[i*INTER_TAB_SIZE + j][1] = i < INTER_TAB_SIZE / 2;    for (k1 = 0; k1 < ksize; k1++) {     float vy = _tab[i*ksize + k1];     for (k2 = 0; k2 < ksize; k2++) {      float v = vy*_tab[j*ksize + k2];      tab[k1*ksize + k2] = v;      isum += itab[k1*ksize + k2] = saturate_cast<short>(v*INTER_REMAP_COEF_SCALE);     }    }    if (isum != INTER_REMAP_COEF_SCALE) {     int diff = isum - INTER_REMAP_COEF_SCALE;     int ksize2 = ksize / 2, Mk1 = ksize2, Mk2 = ksize2, mk1 = ksize2, mk2 = ksize2;     for (k1 = ksize2; k1 < ksize2 + 2; k1++) {      for (k2 = ksize2; k2 < ksize2 + 2; k2++) {       if (itab[k1*ksize + k2] < itab[mk1*ksize + mk2])        mk1 = k1, mk2 = k2;       else if (itab[k1*ksize + k2] > itab[Mk1*ksize + Mk2])        Mk1 = k1, Mk2 = k2;      }     }     if (diff < 0)      itab[Mk1*ksize + Mk2] = (short)(itab[Mk1*ksize + Mk2] - diff);     else      itab[mk1*ksize + mk2] = (short)(itab[mk1*ksize + mk2] - diff);    }   }  }  tab -= INTER_TAB_SIZE2*ksize*ksize;  itab -= INTER_TAB_SIZE2*ksize*ksize;  inittab[method] = true; } return fixpt ? (const void*)itab : (const void*)tab;}template<typename _Tp>static bool initAllInterTab2D()return  initInterTab2D<uchar>(INTER_LINEAR, false) &&  initInterTab2D<uchar>(INTER_LINEAR, true) &&  initInterTab2D<uchar>(INTER_CUBIC, false) &&  initInterTab2D<uchar>(INTER_CUBIC, true) &&  initInterTab2D<uchar>(INTER_LANCZOS4, false) &&  initInterTab2D<uchar>(INTER_LANCZOS4, true);}static volatile bool doInitAllInterTab2D = initAllInterTab2D<uchar>();template<typename _Tp1, typename _Tp2, int chs1, int chs2>static void remapNearest(const Mat_<_Tp1, chs1>& _src, Mat_<_Tp1, chs1>& _dst, const Mat_<_Tp2, chs2>& _xy, int borderType, const Scalar& _borderValue){ Size ssize = _src.size(), dsize = _dst.size(); int cn = _src.channels; const _Tp1* S0 = (const _Tp1*)_src.ptr(); size_t sstep = _src.step / sizeof(S0[0]); Scalar_<_Tp1> cval(saturate_cast<_Tp1>(_borderValue[0]), saturate_cast<_Tp1>(_borderValue[1]), saturate_cast<_Tp1>(_borderValue[2]), saturate_cast<_Tp1>(_borderValue[3])); i
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值