Advertisement
Guest User

OpenCV code for image interpolation with cv::remap()

a guest
Mar 30th, 2013
1,537
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.29 KB | None | 0 0
  1. void cv::remap( InputArray _src, OutputArray _dst,
  2.                 InputArray _map1, InputArray _map2,
  3.                 int interpolation, int borderType, const Scalar& borderValue )
  4. {
  5.     static RemapNNFunc nn_tab[] =
  6.     {
  7.         remapNearest<uchar>, remapNearest<uchar>, remapNearest<ushort>, remapNearest<ushort>,
  8.         remapNearest<int>, remapNearest<int>, remapNearest<double>, 0
  9.     };
  10.  
  11.     static RemapFunc linear_tab[] =
  12.     {
  13.         remapBilinear<FixedPtCast<int, uchar, INTER_REMAP_COEF_BITS>, RemapVec_8u, short>, 0,
  14.         remapBilinear<Cast<float, ushort>, RemapNoVec, float>,
  15.         remapBilinear<Cast<float, short>, RemapNoVec, float>, 0,
  16.         remapBilinear<Cast<float, float>, RemapNoVec, float>,
  17.         remapBilinear<Cast<double, double>, RemapNoVec, float>, 0
  18.     };
  19.  
  20.     static RemapFunc cubic_tab[] =
  21.     {
  22.         remapBicubic<FixedPtCast<int, uchar, INTER_REMAP_COEF_BITS>, short, INTER_REMAP_COEF_SCALE>, 0,
  23.         remapBicubic<Cast<float, ushort>, float, 1>,
  24.         remapBicubic<Cast<float, short>, float, 1>, 0,
  25.         remapBicubic<Cast<float, float>, float, 1>,
  26.         remapBicubic<Cast<double, double>, float, 1>, 0
  27.     };
  28.  
  29.     static RemapFunc lanczos4_tab[] =
  30.     {
  31.         remapLanczos4<FixedPtCast<int, uchar, INTER_REMAP_COEF_BITS>, short, INTER_REMAP_COEF_SCALE>, 0,
  32.         remapLanczos4<Cast<float, ushort>, float, 1>,
  33.         remapLanczos4<Cast<float, short>, float, 1>, 0,
  34.         remapLanczos4<Cast<float, float>, float, 1>,
  35.         remapLanczos4<Cast<double, double>, float, 1>, 0
  36.     };
  37.  
  38.     Mat src = _src.getMat(), map1 = _map1.getMat(), map2 = _map2.getMat();
  39.    
  40.     CV_Assert( (!map2.data || map2.size() == map1.size()));
  41.    
  42.     _dst.create( map1.size(), src.type() );
  43.     Mat dst = _dst.getMat();
  44.     CV_Assert(dst.data != src.data);
  45.  
  46.     int depth = src.depth(), map_depth = map1.depth();
  47.     RemapNNFunc nnfunc = 0;
  48.     RemapFunc ifunc = 0;
  49.     const void* ctab = 0;
  50.     bool fixpt = depth == CV_8U;
  51.     bool planar_input = false;
  52.  
  53.     if( interpolation == INTER_NEAREST )
  54.     {
  55.         nnfunc = nn_tab[depth];
  56.         CV_Assert( nnfunc != 0 );
  57.  
  58.         if( map1.type() == CV_16SC2 && !map2.data ) // the data is already in the right format
  59.         {
  60.             nnfunc( src, dst, map1, borderType, borderValue );
  61.             return;
  62.         }
  63.     }
  64.     else
  65.     {
  66.         if( interpolation == INTER_AREA )
  67.             interpolation = INTER_LINEAR;
  68.  
  69.         if( interpolation == INTER_LINEAR )
  70.             ifunc = linear_tab[depth];
  71.         else if( interpolation == INTER_CUBIC )
  72.             ifunc = cubic_tab[depth];
  73.         else if( interpolation == INTER_LANCZOS4 )
  74.             ifunc = lanczos4_tab[depth];
  75.         else
  76.             CV_Error( CV_StsBadArg, "Unknown interpolation method" );
  77.         CV_Assert( ifunc != 0 );
  78.         ctab = initInterTab2D( interpolation, fixpt );
  79.     }
  80.  
  81.     const Mat *m1 = &map1, *m2 = &map2;
  82.  
  83.     if( (map1.type() == CV_16SC2 && (map2.type() == CV_16UC1 || map2.type() == CV_16SC1)) ||
  84.         (map2.type() == CV_16SC2 && (map1.type() == CV_16UC1 || map1.type() == CV_16SC1)) )
  85.     {
  86.         if( map1.type() != CV_16SC2 )
  87.             std::swap(m1, m2);
  88.         if( ifunc )
  89.         {
  90.             ifunc( src, dst, *m1, *m2, ctab, borderType, borderValue );
  91.             return;
  92.         }
  93.     }
  94.     else
  95.     {
  96.         CV_Assert( (map1.type() == CV_32FC2 && !map2.data) ||
  97.             (map1.type() == CV_32FC1 && map2.type() == CV_32FC1) );
  98.         planar_input = map1.channels() == 1;
  99.     }
  100.  
  101.     int x, y, x1, y1;
  102.     const int buf_size = 1 << 14;
  103.     int brows0 = std::min(128, dst.rows);
  104.     int bcols0 = std::min(buf_size/brows0, dst.cols);
  105.     brows0 = std::min(buf_size/bcols0, dst.rows);
  106. #if CV_SSE2
  107.     bool useSIMD = checkHardwareSupport(CV_CPU_SSE2);
  108. #endif
  109.  
  110.     Mat _bufxy(brows0, bcols0, CV_16SC2), _bufa;
  111.     if( !nnfunc )
  112.         _bufa.create(brows0, bcols0, CV_16UC1);
  113.  
  114.     for( y = 0; y < dst.rows; y += brows0 )
  115.     {
  116.         for( x = 0; x < dst.cols; x += bcols0 )
  117.         {
  118.             int brows = std::min(brows0, dst.rows - y);
  119.             int bcols = std::min(bcols0, dst.cols - x);
  120.             Mat dpart(dst, Rect(x, y, bcols, brows));
  121.             Mat bufxy(_bufxy, Rect(0, 0, bcols, brows));
  122.  
  123.             if( nnfunc )
  124.             {
  125.                 if( map_depth != CV_32F )
  126.                 {
  127.                     for( y1 = 0; y1 < brows; y1++ )
  128.                     {
  129.                         short* XY = (short*)(bufxy.data + bufxy.step*y1);
  130.                         const short* sXY = (const short*)(m1->data + m1->step*(y+y1)) + x*2;
  131.                         const ushort* sA = (const ushort*)(m2->data + m2->step*(y+y1)) + x;
  132.  
  133.                         for( x1 = 0; x1 < bcols; x1++ )
  134.                         {
  135.                             int a = sA[x1] & (INTER_TAB_SIZE2-1);
  136.                             XY[x1*2] = sXY[x1*2] + NNDeltaTab_i[a][0];
  137.                             XY[x1*2+1] = sXY[x1*2+1] + NNDeltaTab_i[a][1];
  138.                         }
  139.                     }
  140.                 }
  141.                 else if( !planar_input )
  142.                     map1(Rect(0,0,bcols,brows)).convertTo(bufxy, bufxy.depth());
  143.                 else
  144.                 {
  145.                     for( y1 = 0; y1 < brows; y1++ )
  146.                     {
  147.                         short* XY = (short*)(bufxy.data + bufxy.step*y1);
  148.                         const float* sX = (const float*)(map1.data + map1.step*(y+y1)) + x;
  149.                         const float* sY = (const float*)(map2.data + map2.step*(y+y1)) + x;
  150.                         x1 = 0;
  151.  
  152.                     #if CV_SSE2
  153.                         if( useSIMD )
  154.                         {
  155.                             for( ; x1 <= bcols - 8; x1 += 8 )
  156.                             {
  157.                                 __m128 fx0 = _mm_loadu_ps(sX + x1);
  158.                                 __m128 fx1 = _mm_loadu_ps(sX + x1 + 4);
  159.                                 __m128 fy0 = _mm_loadu_ps(sY + x1);
  160.                                 __m128 fy1 = _mm_loadu_ps(sY + x1 + 4);
  161.                                 __m128i ix0 = _mm_cvtps_epi32(fx0);
  162.                                 __m128i ix1 = _mm_cvtps_epi32(fx1);
  163.                                 __m128i iy0 = _mm_cvtps_epi32(fy0);
  164.                                 __m128i iy1 = _mm_cvtps_epi32(fy1);
  165.                                 ix0 = _mm_packs_epi32(ix0, ix1);
  166.                                 iy0 = _mm_packs_epi32(iy0, iy1);
  167.                                 ix1 = _mm_unpacklo_epi16(ix0, iy0);
  168.                                 iy1 = _mm_unpackhi_epi16(ix0, iy0);
  169.                                 _mm_storeu_si128((__m128i*)(XY + x1*2), ix1);
  170.                                 _mm_storeu_si128((__m128i*)(XY + x1*2 + 8), iy1);
  171.                             }
  172.                         }
  173.                     #endif
  174.  
  175.                         for( ; x1 < bcols; x1++ )
  176.                         {
  177.                             XY[x1*2] = saturate_cast<short>(sX[x1]);
  178.                             XY[x1*2+1] = saturate_cast<short>(sY[x1]);
  179.                         }
  180.                     }
  181.                 }
  182.                 nnfunc( src, dpart, bufxy, borderType, borderValue );
  183.                 continue;
  184.             }
  185.  
  186.             Mat bufa(_bufa, Rect(0,0,bcols, brows));
  187.             for( y1 = 0; y1 < brows; y1++ )
  188.             {
  189.                 short* XY = (short*)(bufxy.data + bufxy.step*y1);
  190.                 ushort* A = (ushort*)(bufa.data + bufa.step*y1);
  191.  
  192.                 if( planar_input )
  193.                 {
  194.                     const float* sX = (const float*)(map1.data + map1.step*(y+y1)) + x;
  195.                     const float* sY = (const float*)(map2.data + map2.step*(y+y1)) + x;
  196.  
  197.                     x1 = 0;
  198.                 #if CV_SSE2
  199.                     if( useSIMD )
  200.                     {
  201.                         __m128 scale = _mm_set1_ps((float)INTER_TAB_SIZE);
  202.                         __m128i mask = _mm_set1_epi32(INTER_TAB_SIZE-1);
  203.                         for( ; x1 <= bcols - 8; x1 += 8 )
  204.                         {
  205.                             __m128 fx0 = _mm_loadu_ps(sX + x1);
  206.                             __m128 fx1 = _mm_loadu_ps(sX + x1 + 4);
  207.                             __m128 fy0 = _mm_loadu_ps(sY + x1);
  208.                             __m128 fy1 = _mm_loadu_ps(sY + x1 + 4);
  209.                             __m128i ix0 = _mm_cvtps_epi32(_mm_mul_ps(fx0, scale));
  210.                             __m128i ix1 = _mm_cvtps_epi32(_mm_mul_ps(fx1, scale));
  211.                             __m128i iy0 = _mm_cvtps_epi32(_mm_mul_ps(fy0, scale));
  212.                             __m128i iy1 = _mm_cvtps_epi32(_mm_mul_ps(fy1, scale));
  213.                             __m128i mx0 = _mm_and_si128(ix0, mask);
  214.                             __m128i mx1 = _mm_and_si128(ix1, mask);
  215.                             __m128i my0 = _mm_and_si128(iy0, mask);
  216.                             __m128i my1 = _mm_and_si128(iy1, mask);
  217.                             mx0 = _mm_packs_epi32(mx0, mx1);
  218.                             my0 = _mm_packs_epi32(my0, my1);
  219.                             my0 = _mm_slli_epi16(my0, INTER_BITS);
  220.                             mx0 = _mm_or_si128(mx0, my0);
  221.                             _mm_storeu_si128((__m128i*)(A + x1), mx0);
  222.                             ix0 = _mm_srai_epi32(ix0, INTER_BITS);
  223.                             ix1 = _mm_srai_epi32(ix1, INTER_BITS);
  224.                             iy0 = _mm_srai_epi32(iy0, INTER_BITS);
  225.                             iy1 = _mm_srai_epi32(iy1, INTER_BITS);
  226.                             ix0 = _mm_packs_epi32(ix0, ix1);
  227.                             iy0 = _mm_packs_epi32(iy0, iy1);
  228.                             ix1 = _mm_unpacklo_epi16(ix0, iy0);
  229.                             iy1 = _mm_unpackhi_epi16(ix0, iy0);
  230.                             _mm_storeu_si128((__m128i*)(XY + x1*2), ix1);
  231.                             _mm_storeu_si128((__m128i*)(XY + x1*2 + 8), iy1);
  232.                         }
  233.                     }
  234.                 #endif
  235.  
  236.                     for( ; x1 < bcols; x1++ )
  237.                     {
  238.                         int sx = cvRound(sX[x1]*INTER_TAB_SIZE);
  239.                         int sy = cvRound(sY[x1]*INTER_TAB_SIZE);
  240.                         int v = (sy & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + (sx & (INTER_TAB_SIZE-1));
  241.                         XY[x1*2] = (short)(sx >> INTER_BITS);
  242.                         XY[x1*2+1] = (short)(sy >> INTER_BITS);
  243.                         A[x1] = (ushort)v;
  244.                     }
  245.                 }
  246.                 else
  247.                 {
  248.                     const float* sXY = (const float*)(map1.data + map1.step*(y+y1)) + x*2;
  249.  
  250.                     for( x1 = 0; x1 < bcols; x1++ )
  251.                     {
  252.                         int sx = cvRound(sXY[x1*2]*INTER_TAB_SIZE);
  253.                         int sy = cvRound(sXY[x1*2+1]*INTER_TAB_SIZE);
  254.                         int v = (sy & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + (sx & (INTER_TAB_SIZE-1));
  255.                         XY[x1*2] = (short)(sx >> INTER_BITS);
  256.                         XY[x1*2+1] = (short)(sy >> INTER_BITS);
  257.                         A[x1] = (ushort)v;
  258.                     }
  259.                 }
  260.             }
  261.             ifunc(src, dpart, bufxy, bufa, ctab, borderType, borderValue);
  262.         }
  263.     }
  264. }
  265.  
  266. // out of the various interpolating functions, used by the above function for "ifunc", here's the bicubic variant as an example:
  267.  
  268. template<class CastOp, typename AT, int ONE>
  269. static void remapBicubic( const Mat& _src, Mat& _dst, const Mat& _xy,
  270.                           const Mat& _fxy, const void* _wtab,
  271.                           int borderType, const Scalar& _borderValue )
  272. {
  273.     typedef typename CastOp::rtype T;
  274.     typedef typename CastOp::type1 WT;
  275.     Size ssize = _src.size(), dsize = _dst.size();
  276.     int cn = _src.channels();
  277.     const AT* wtab = (const AT*)_wtab;
  278.     const T* S0 = (const T*)_src.data;
  279.     size_t sstep = _src.step/sizeof(S0[0]);
  280.     Scalar_<T> cval(saturate_cast<T>(_borderValue[0]),
  281.         saturate_cast<T>(_borderValue[1]),
  282.         saturate_cast<T>(_borderValue[2]),
  283.         saturate_cast<T>(_borderValue[3]));
  284.     int dx, dy;
  285.     CastOp castOp;
  286.     int borderType1 = borderType != BORDER_TRANSPARENT ? borderType : BORDER_REFLECT_101;
  287.  
  288.     unsigned width1 = std::max(ssize.width-3, 0), height1 = std::max(ssize.height-3, 0);
  289.  
  290.     if( _dst.isContinuous() && _xy.isContinuous() && _fxy.isContinuous() )
  291.     {
  292.         dsize.width *= dsize.height;
  293.         dsize.height = 1;
  294.     }
  295.  
  296.     for( dy = 0; dy < dsize.height; dy++ )
  297.     {
  298.         T* D = (T*)(_dst.data + _dst.step*dy);
  299.         const short* XY = (const short*)(_xy.data + _xy.step*dy);
  300.         const ushort* FXY = (const ushort*)(_fxy.data + _fxy.step*dy);
  301.  
  302.         for( dx = 0; dx < dsize.width; dx++, D += cn )
  303.         {
  304.             int sx = XY[dx*2]-1, sy = XY[dx*2+1]-1;
  305.             const AT* w = wtab + FXY[dx]*16;
  306.             int i, k;
  307.             if( (unsigned)sx < width1 && (unsigned)sy < height1 )
  308.             {
  309.                 const T* S = S0 + sy*sstep + sx*cn;
  310.                 for( k = 0; k < cn; k++ )
  311.                 {
  312.                     WT sum = S[0]*w[0] + S[cn]*w[1] + S[cn*2]*w[2] + S[cn*3]*w[3];
  313.                     S += sstep;
  314.                     sum += S[0]*w[4] + S[cn]*w[5] + S[cn*2]*w[6] + S[cn*3]*w[7];
  315.                     S += sstep;
  316.                     sum += S[0]*w[8] + S[cn]*w[9] + S[cn*2]*w[10] + S[cn*3]*w[11];
  317.                     S += sstep;
  318.                     sum += S[0]*w[12] + S[cn]*w[13] + S[cn*2]*w[14] + S[cn*3]*w[15];
  319.                     S += 1 - sstep*3;
  320.                     D[k] = castOp(sum);
  321.                 }
  322.             }
  323.             else
  324.             {
  325.                 int x[4], y[4];
  326.                 if( borderType == BORDER_TRANSPARENT &&
  327.                     ((unsigned)(sx+1) >= (unsigned)ssize.width ||
  328.                     (unsigned)(sy+1) >= (unsigned)ssize.height) )
  329.                     continue;
  330.  
  331.                 if( borderType1 == BORDER_CONSTANT &&
  332.                     (sx >= ssize.width || sx+4 <= 0 ||
  333.                     sy >= ssize.height || sy+4 <= 0))
  334.                 {
  335.                     for( k = 0; k < cn; k++ )
  336.                         D[k] = cval[k];
  337.                     continue;
  338.                 }
  339.  
  340.                 for( i = 0; i < 4; i++ )
  341.                 {
  342.                     x[i] = borderInterpolate(sx + i, ssize.width, borderType1)*cn;
  343.                     y[i] = borderInterpolate(sy + i, ssize.height, borderType1);
  344.                 }
  345.  
  346.                 for( k = 0; k < cn; k++, S0++, w -= 16 )
  347.                 {
  348.                     WT cv = cval[k], sum = cv*ONE;
  349.                     for( i = 0; i < 4; i++, w += 4 )
  350.                     {
  351.                         int yi = y[i];
  352.                         const T* S = S0 + yi*sstep;
  353.                         if( yi < 0 )
  354.                             continue;
  355.                         if( x[0] >= 0 )
  356.                             sum += (S[x[0]] - cv)*w[0];
  357.                         if( x[1] >= 0 )
  358.                             sum += (S[x[1]] - cv)*w[1];
  359.                         if( x[2] >= 0 )
  360.                             sum += (S[x[2]] - cv)*w[2];
  361.                         if( x[3] >= 0 )
  362.                             sum += (S[x[3]] - cv)*w[3];
  363.                     }
  364.                     D[k] = castOp(sum);
  365.                 }
  366.                 S0 -= cn;
  367.             }
  368.         }
  369.     }
  370. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement