mot_comp.cpp
上传用户:xjjlds
上传日期:2015-12-05
资源大小:22823k
文件大小:22k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2. *
  3. * $Id: mot_comp.cpp,v 1.3 2005/01/30 05:11:40 gabest Exp $ $Name:  $
  4. *
  5. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  6. *
  7. * The contents of this file are subject to the Mozilla Public License
  8. * Version 1.1 (the "License"); you may not use this file except in compliance
  9. * with the License. You may obtain a copy of the License at
  10. * http://www.mozilla.org/MPL/
  11. *
  12. * Software distributed under the License is distributed on an "AS IS" basis,
  13. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
  14. * the specific language governing rights and limitations under the License.
  15. *
  16. * The Original Code is BBC Research and Development code.
  17. *
  18. * The Initial Developer of the Original Code is the British Broadcasting
  19. * Corporation.
  20. * Portions created by the Initial Developer are Copyright (C) 2004.
  21. * All Rights Reserved.
  22. *
  23. * Contributor(s): Richard Felton (Original Author), 
  24. *                 Thomas Davies,
  25. *                 Steve Bearcroft
  26. *
  27. * Alternatively, the contents of this file may be used under the terms of
  28. * the GNU General Public License Version 2 (the "GPL"), or the GNU Lesser
  29. * Public License Version 2.1 (the "LGPL"), in which case the provisions of
  30. * the GPL or the LGPL are applicable instead of those above. If you wish to
  31. * allow use of your version of this file only under the terms of the either
  32. * the GPL or LGPL and not to allow others to use your version of this file
  33. * under the MPL, indicate your decision by deleting the provisions above
  34. * and replace them with the notice and other provisions required by the GPL
  35. * or LGPL. If you do not delete the provisions above, a recipient may use
  36. * your version of this file under the terms of any one of the MPL, the GPL
  37. * or the LGPL.
  38. * ***** END LICENSE BLOCK ***** */
  39. #include <libdirac_common/mot_comp.h>
  40. #include <libdirac_common/motion.h>
  41. #include <libdirac_common/frame_buffer.h>
  42. using namespace dirac;
  43. using std::vector;
  44. //--public member functions--//
  45. ///////////////////////////////
  46. //Constructor
  47. //Initialises the lookup table that is needed for 1/8th pixel accuracy
  48. //motion estimation. Creates the necessary arithmetic objects and
  49. //calls ReConfig to create weighting blocks to fit the values within
  50. //m_cparams.
  51. MotionCompensator::MotionCompensator( const CodecParams &cp , const AddOrSub direction ): 
  52.     m_cparams(cp),
  53.     luma_or_chroma(true),
  54.     m_add_or_sub( direction )
  55. {
  56.     //Configure weighting blocks for the first time
  57.     m_block_weights = NULL;
  58.     m_half_block_weights = NULL;
  59.     ReConfig();
  60. }
  61. //Destructor
  62. MotionCompensator::~MotionCompensator(){
  63.     //Tidy up the pointers
  64.     delete[] m_block_weights;
  65.     delete[] m_half_block_weights;
  66. }
  67. //Called to perform motion compensated addition/subtraction on an entire frame.
  68. void MotionCompensator::CompensateFrame(FrameBuffer& my_buffer,int fnum,const MvData& mv_data)
  69. {
  70.      int ref1_idx,ref2_idx;    
  71.      Frame& my_frame=my_buffer.GetFrame(fnum);
  72.      const FrameSort& fsort=my_frame.GetFparams().FSort();
  73.      m_cformat = my_frame.GetFparams().CFormat();
  74.      if (fsort!=I_frame)
  75.      {//we can motion compensate
  76.          const vector<int>& refs=my_frame.GetFparams().Refs();
  77.          if (refs.size()>0)
  78.          {
  79.              //extract the references
  80.              ref1_idx=refs[0];
  81.              if (refs.size()>1)
  82.                  ref2_idx=refs[1];
  83.              else
  84.                  ref2_idx=refs[0];
  85.              const Frame& ref1frame=my_buffer.GetFrame(ref1_idx);
  86.              const Frame& ref2frame=my_buffer.GetFrame(ref2_idx);
  87.              luma_or_chroma = true;                
  88.              //now do all the components
  89.              CompensateComponent( my_frame , ref1frame , ref2frame , mv_data , Y_COMP);
  90.              if ( m_cformat != Yonly )
  91.              {
  92.                  luma_or_chroma = false;                
  93.                  CompensateComponent( my_frame , ref1frame , ref2frame , mv_data , U_COMP);
  94.                  CompensateComponent( my_frame , ref1frame , ref2frame , mv_data , V_COMP);
  95.              }
  96.          }
  97.      }
  98. }
  99. //--private member functions--//
  100. ////////////////////////////////
  101. //Needs to be called if the blocksize changes (and
  102. //on startup). This method creates an array of weighting
  103. //blocks that are used to acheive correctly overlapping
  104. //blocks.
  105. void MotionCompensator::ReConfig()
  106. {
  107.     if (luma_or_chroma)
  108.         m_bparams = m_cparams.LumaBParams(2);
  109.     else
  110.         m_bparams = m_cparams.ChromaBParams(2);
  111.     if(m_block_weights != NULL)
  112.         delete[] m_block_weights;
  113.     if(m_half_block_weights != NULL)
  114.         delete[] m_half_block_weights;
  115.     // Create new weights array.
  116.     m_block_weights = new TwoDArray<CalcValueType>[9];
  117.     m_half_block_weights = new TwoDArray<CalcValueType>[9];
  118.     for(int i = 0; i < 9; i++)
  119.     {
  120.         m_block_weights[i].Resize(  m_bparams.Yblen() , m_bparams.Xblen() );
  121.         m_half_block_weights[i].Resize(  m_bparams.Yblen() , m_bparams.Xblen() );
  122.     }
  123.     // We can create all nine weighting blocks by calculating values
  124.     // for four blocks and mirroring them to generate the others.
  125.     CreateBlock( m_bparams , false , false , m_half_block_weights[0] );
  126.     CreateBlock( m_bparams , false , true , m_half_block_weights[3] );
  127.     CreateBlock( m_bparams , true , false , m_half_block_weights[1] );
  128.     CreateBlock( m_bparams , true , true , m_half_block_weights[4] );
  129.     // Note order of flipping is important.    
  130.     FlipX( m_half_block_weights[3] , m_bparams , m_half_block_weights[5] );
  131.     FlipX( m_half_block_weights[0] , m_bparams , m_half_block_weights[2] );
  132.     FlipY( m_half_block_weights[0] , m_bparams , m_half_block_weights[6] );
  133.     FlipX( m_half_block_weights[6] , m_bparams , m_half_block_weights[8] );
  134.     FlipY( m_half_block_weights[1] , m_bparams , m_half_block_weights[7] );
  135.     for( int k = 0; k < 9; k++)
  136.     {
  137.         for ( int j =m_half_block_weights[k].FirstY(); j <= m_half_block_weights[k].LastY(); j++)
  138.         {
  139.             for ( int i =m_half_block_weights[k].FirstX(); i <= m_half_block_weights[k].LastX(); i++)
  140.             {
  141.                 m_block_weights[k][j][i] = m_half_block_weights[k][j][i] << 1;
  142.             }// i
  143.         }// j
  144.     }// k
  145. }
  146. void MotionCompensator::CompensateComponent(Frame& picframe, const Frame &ref1frame, const Frame& ref2frame,
  147.     const MvData& mv_data,const CompSort cs)
  148. {
  149.     // Set up references to pictures and references
  150.     PicArray& pic_data_out = picframe.Data( cs );
  151.     const PicArray& ref1up = ref1frame.UpData( cs );
  152.     const PicArray& ref2up = ref2frame.UpData( cs );
  153.     // Set up another picture which will contain the MC data, which
  154.     // we'll add or subtract to pic_data_out
  155.     TwoDArray<CalcValueType> pic_data(pic_data_out.LengthY(), pic_data_out.LengthX() , 0);
  156.     // Factors to compensate for subsampling of chroma
  157.     int xscale_factor = 1;
  158.     int yscale_factor = 1;
  159.     if ( cs != Y_COMP )
  160.     {
  161.         if (m_cformat == format420)
  162.         {
  163.             xscale_factor = 2;
  164.             yscale_factor = 2;
  165.         }
  166.         else if (m_cformat == format422)
  167.         {
  168.             xscale_factor = 2;
  169.             yscale_factor = 1;
  170.         }
  171.         else if (m_cformat == format411)
  172.         {
  173.             xscale_factor = 4;
  174.             yscale_factor = 1;
  175.         }
  176.     } 
  177.     // Reference to the relevant DC array
  178.     const TwoDArray<ValueType>& dcarray = mv_data.DC( cs );
  179.     // Set up references to the vectors
  180.     const int num_refs = picframe.GetFparams().Refs().size();
  181.     const MvArray* mv_array1; 
  182.     const MvArray* mv_array2;
  183.     mv_array1 = &mv_data.Vectors(1);
  184.     if (num_refs ==2 )
  185.         mv_array2 = &mv_data.Vectors(2);
  186.     else
  187.         mv_array2 = &mv_data.Vectors(1);
  188.     ReConfig();//set all the weighting blocks up    
  189.     //Blocks are listed left to right, line by line.
  190.     MVector mv1,mv2;
  191.     PredMode block_mode;
  192.     ValueType dc;
  193.     //Coords of the top-left corner of a block
  194.     ImageCoords pos;
  195.     //Loop for each block in the output image.
  196.     //The CompensateBlock function will use the image pointed to by ref1up
  197.     //and add the compensated pixels to the image pointed to by pic_data.
  198.     size_t wgt_idx;
  199.     //Loop over all the block rows
  200.     pos.y = -m_bparams.Yoffset();
  201.     for(int yblock = 0; yblock < m_cparams.YNumBlocks(); ++yblock)
  202.     {
  203.         pos.x = -m_bparams.Xoffset();
  204.         //loop over all the blocks in a row
  205.         for(int xblock = 0 ; xblock < m_cparams.XNumBlocks(); ++xblock)
  206.         {
  207.             //Decide which weights to use.
  208.             if((xblock != 0)&&(xblock < m_cparams.XNumBlocks() - 1))
  209.             {
  210.                 if((yblock != 0)&&(yblock < m_cparams.YNumBlocks() - 1))    
  211.                     wgt_idx = 4;
  212.                 else if(yblock == 0) 
  213.                     wgt_idx = 1;
  214.                 else 
  215.                     wgt_idx= 7;
  216.             }
  217.             else if(xblock == 0)
  218.             {
  219.                 if((yblock != 0)&&(yblock < m_cparams.YNumBlocks() - 1))    
  220.                     wgt_idx = 3;
  221.                 else if(yblock == 0) 
  222.                     wgt_idx = 0;
  223.                 else 
  224.                     wgt_idx = 6;
  225.             }
  226.             else
  227.             {
  228.                 if((yblock != 0)&&(yblock < m_cparams.YNumBlocks() - 1))    
  229.                     wgt_idx = 5;
  230.                 else if(yblock == 0) 
  231.                     wgt_idx = 2;
  232.                 else 
  233.                     wgt_idx = 8;
  234.             }
  235.             block_mode = mv_data.Mode()[yblock][xblock];
  236.             mv1 = (*mv_array1)[yblock][xblock];
  237.             mv1.x /= xscale_factor;
  238.             mv1.y /= yscale_factor;
  239.             mv2 = (*mv_array2)[yblock][xblock];
  240.             mv2.x /= xscale_factor;
  241.             mv2.y /= yscale_factor;
  242.             dc = dcarray[yblock][xblock]<<2;// DC is only given 8 bits, 
  243.                                             // so need to shift to get 10-bit data
  244.             if(block_mode == REF1_ONLY)
  245.             {
  246.                 CompensateBlock(pic_data, ref1up, mv1, pos, m_block_weights[wgt_idx]);
  247.             }
  248.             else if (block_mode == REF2_ONLY)
  249.             {                
  250.                 CompensateBlock(pic_data, ref2up, mv2, pos, m_block_weights[wgt_idx]);
  251.             }
  252.             else if(block_mode == REF1AND2)
  253.             {
  254.                 CompensateBlock(pic_data, ref1up, mv1, pos, m_half_block_weights[wgt_idx]);
  255.                 CompensateBlock(pic_data, ref2up, mv2, pos, m_half_block_weights[wgt_idx]);                    
  256.             }
  257.             else
  258.             {//we have a DC block.
  259.                 DCBlock(pic_data, dc,pos, m_block_weights[wgt_idx]);
  260.             }
  261.             //Increment the block horizontal position
  262.             pos.x += m_bparams.Xbsep();
  263.         }//xblock
  264.         //Increment the block vertical position
  265.         pos.y += m_bparams.Ybsep();
  266.     }//yblock
  267.     if ( m_add_or_sub == SUBTRACT)
  268.     {
  269.         int x_end_data = std::min(pic_data.LastX(), m_cparams.XNumBlocks()*m_bparams.Xbsep() );
  270.         int y_end_data = std::min(pic_data.LastY(), m_cparams.YNumBlocks()*m_bparams.Ybsep() );
  271.         for ( int i =pic_data.FirstY(); i <= y_end_data; i++)
  272.         {
  273.             for ( int j =pic_data.FirstX(); j <= x_end_data; ++j)
  274.             {
  275.                 pic_data_out[i][j] -= static_cast<ValueType>( (pic_data[i][j] + 1024) >> 11 );
  276.             }
  277.  
  278.             // Okay, we've done all the actual blocks. Now if the picture is further padded
  279.             // we need to set the padded values to zero beyond the last block in the row,
  280.             // for all the picture lines in the block row. Need only do this when we're
  281.             // subtracting.
  282.             for (int j=( m_cparams.XNumBlocks()*m_bparams.Xbsep() ); j<pic_data.LengthX() ; ++j )
  283.             {
  284.                 pic_data_out[i][j] = 0;
  285.             }
  286.         }
  287.         // Finally, now we've done all the blocks, we must set all padded lines below 
  288.         // the last row equal to 0, if we're subtracting
  289.         for ( int y=m_cparams.YNumBlocks()*m_bparams.Ybsep() ; y<pic_data.LengthY() ; ++y )
  290.         {
  291.             for ( int x=0 ; x<pic_data.LengthX() ; ++x )
  292.             {
  293.                 pic_data_out[y][x] = 0;
  294.             }
  295.         }
  296.     }
  297.     else
  298.     {
  299.         for ( int i =pic_data.FirstY(); i <= pic_data.LastY(); i++)
  300.         {
  301.             for ( int j =pic_data.FirstX(); j <= pic_data.LastX(); j++)
  302.             {
  303.                 pic_data_out[i][j] += static_cast<ValueType>( (pic_data[i][j] + 1024) >> 11 );
  304.             }
  305.         }
  306.     }
  307. }
  308. void MotionCompensator::CompensateBlock( TwoDArray<CalcValueType> &pic_data , const PicArray &refup_data , const MVector &mv , 
  309. const ImageCoords& pos , const TwoDArray<CalcValueType>& wt_array )
  310. {
  311.     //Coordinates in the image being written to.
  312.     const ImageCoords start_pos( std::max(pos.x,0) , std::max(pos.y,0) );
  313.     const ImageCoords end_pos( std::min( pos.x + m_bparams.Xblen() , pic_data.LengthX() ) , 
  314.                                std::min( pos.y + m_bparams.Yblen() , pic_data.LengthY() ) );
  315.     //The difference between the desired start point
  316.     //pos and the actual start point start_pos.
  317.     const ImageCoords diff( start_pos.x - pos.x , start_pos.y - pos.y );
  318.     //Set up the start point in the reference image by rounding the motion vector
  319.     //NB: bit shift rounds negative values DOWN, as required
  320.     const MVector roundvec( mv.x>>2 , mv.y>>2 );
  321.     //Get the remainder after rounding. NB rmdr values always 0,1,2 or 3
  322.     const MVector rmdr( mv.x - ( roundvec.x<<2 ) , mv.y - ( roundvec.y<<2 ) );
  323.     //Where to start in the upconverted image
  324.     const ImageCoords ref_start( ( start_pos.x<<1 ) + roundvec.x ,( start_pos.y<<1 ) + roundvec.y );
  325.     //weights for doing linear interpolation, calculated from the remainder values
  326.     const ValueType TLweight( (4 - rmdr.x) * (4 - rmdr.y) );
  327.     const ValueType TRweight( rmdr.x * ( 4 - rmdr.y ) );
  328.     const ValueType BLweight( ( 4 - rmdr.x ) * rmdr.y );
  329.     const ValueType BRweight( rmdr.x * rmdr.y );
  330.     //An additional stage to make sure the block to be copied does not fall outside
  331.     //the reference image.
  332.     const int refXlen = refup_data.LengthX();
  333.     const int refYlen = refup_data.LengthY();
  334.     bool do_bounds_checking = false;
  335.     //Check if there are going to be any problems copying the block from
  336.     //the upvconverted reference image.
  337.     if( ref_start.x < 0 ) 
  338.         do_bounds_checking = true;
  339.     else if( ref_start.x + ((end_pos.x - start_pos.x)<<1 ) >= refXlen )
  340.         do_bounds_checking = true;
  341.     if( ref_start.y < 0 ) 
  342.         do_bounds_checking = true;
  343.     else if( ref_start.y + ((end_pos.y - start_pos.y)<<1 ) >= refYlen)
  344.         do_bounds_checking = true;
  345.      if( !do_bounds_checking )
  346.      {
  347.          for(int c = start_pos.y, wY = diff.y, uY = ref_start.y; c < end_pos.y; ++c, ++wY, uY += 2)
  348.          {
  349.              for(int l = start_pos.x, wX = diff.x, uX = ref_start.x; l < end_pos.x; ++l, ++wX, uX += 2)
  350.              {
  351.                  pic_data[c][l] += (( TLweight * refup_data[uY][uX] +
  352.                           TRweight * refup_data[uY][uX+1] +
  353.                           BLweight * refup_data[uY+1][uX] +
  354.                           BRweight * refup_data[uY+1][uX+1] +
  355.                           8
  356.                           ) >> 4) * wt_array[wY][wX];
  357.              }//l
  358.          }//c
  359.      }
  360.      else
  361.      {
  362.          //We're doing bounds checking because we'll fall off the edge of the reference otherwise.
  363.         for(int c = start_pos.y, wY = diff.y, uY = ref_start.y,BuY=BChk(uY,refYlen),BuY1=BChk(uY+1,refYlen);
  364.             c < end_pos.y; ++c, ++wY, uY += 2,BuY=BChk(uY,refYlen),BuY1=BChk(uY+1,refYlen))
  365.         {
  366.             for(int l = start_pos.x, wX = diff.x, uX = ref_start.x,BuX=BChk(uX,refXlen),BuX1=BChk(uX+1,refXlen);
  367.                 l < end_pos.x; ++l, ++wX, uX += 2,BuX=BChk(uX,refXlen),BuX1=BChk(uX+1,refXlen))
  368.             {
  369.                 pic_data[c][l] += (( TLweight * refup_data[BuY][BuX] +
  370.                          TRweight * refup_data[BuY][BuX1]  +
  371.                          BLweight * refup_data[BuY1][BuX]+
  372.                          BRweight * refup_data[BuY1][BuX1] +
  373.                          8
  374.                          ) >> 4) * wt_array[wY][wX];
  375.             }//l
  376.         }//c
  377.     }
  378. }
  379. void MotionCompensator::DCBlock( TwoDArray<CalcValueType> &pic_data ,const ValueType dc , const ImageCoords& pos ,
  380.     const TwoDArray<CalcValueType>& wt_array)
  381. {
  382.     //Coordinates in the image being written to.
  383.     const ImageCoords start_pos( std::max(0 , pos.x) , std::max(0 , pos.y) );
  384.     const ImageCoords end_pos( std::min(pos.x + m_bparams.Xblen() , pic_data.LengthX() ) , 
  385.                                std::min(pos.y + m_bparams.Yblen() , pic_data.LengthY() ) );
  386.     //The difference between the desired start point
  387.     //pos and the actual start point start_pos.
  388.     const ImageCoords diff(start_pos.x - pos.x , start_pos.y - pos.y);
  389.     //Quick process where we can just copy from the double size image.
  390.     for(int c = start_pos.y, wY = diff.y; c < end_pos.y; ++c, ++wY)
  391.     {
  392.         for(int l = start_pos.x, wX = diff.x; l < end_pos.x; ++l, ++wX)
  393.         {
  394.             pic_data[c][l] += dc * wt_array[wY][wX];
  395.         }
  396.     }
  397. }
  398. //Overlapping blocks are acheived by applying a 2D raised cosine shape
  399. //to them. This function facilitates the calculations
  400. float MotionCompensator::RaisedCosine(float t, float B)
  401. {
  402.     if(std::abs(t)>(B+1.0)/2.0) 
  403.         return 0.0f;
  404.     else if(std::abs(t)<(1.0-B)/2.0) 
  405.         return 1.0f;
  406.     else 
  407.         return( 0.5 * ( 1.0 + std::cos( 3.141592654 * ( std::abs(t)-(1.0-B)/2.0 )/B ) ) );
  408. }
  409. //Calculates a weighting block.
  410. //bparams defines the block parameters so the relevant weighting arrays can be created.
  411. //FullX and FullY refer to whether the weight should be adjusted for the edge of an image.
  412. //eg. 1D Weighting shapes in x direction
  413. //  FullX true        FullX false
  414. //     ***           ********
  415. //   *     *                  *
  416. //  *       *                  *
  417. //*           *                  *
  418. void MotionCompensator::CreateBlock(const OLBParams &bparams, bool FullX, bool FullY, TwoDArray<CalcValueType>& WeightArray)
  419. {
  420.     // Create temporary arrays
  421.     OneDArray<CalcValueType> HWts( WeightArray.LengthX() );
  422.     OneDArray<CalcValueType> VWts( WeightArray.LengthY() );
  423.     // Calculation variables
  424.     float rolloffX = (float(bparams.Xblen()+1)/float(bparams.Xbsep())) - 1;
  425.     float rolloffY = (float(bparams.Yblen()+1)/float(bparams.Ybsep())) - 1;
  426.     float val;
  427.     // Window in the x direction
  428.     for(int x = 0; x < bparams.Xblen(); ++x)
  429.     {
  430.         val = (float(x) - (float(bparams.Xblen()-1)/2.0))/float(bparams.Xbsep());
  431.         HWts[x] = static_cast<CalcValueType>( 32.0 * RaisedCosine(val,rolloffX) );
  432.         HWts[x] = std::max( HWts[x] , 1 );
  433.         HWts[x] = std::min( HWts[x] , 32 );
  434.     }// x
  435.     // Window in the y direction
  436.     for(int y = 0; y < bparams.Yblen(); ++y)
  437.     {
  438.         val = (float(y) - (float(bparams.Yblen()-1)/2.0))/float(bparams.Ybsep());
  439.         VWts[y] = static_cast<CalcValueType>( 32.0 * RaisedCosine(val,rolloffY) );
  440.         VWts[y] = std::max( VWts[y] , 1 );
  441.         VWts[y] = std::min( VWts[y] , 32 );
  442.     }// y
  443.     // Rationalise to avoid rounding errors
  444.     for(int x = HWts.Last(); x > HWts.Last()-bparams.Xoffset(); --x)
  445.     {
  446.         if (HWts[x] + HWts[HWts.Last()-(x-bparams.Xbsep())] > 32)
  447.             HWts[HWts.Last()-(x-bparams.Xbsep())] = 32-HWts[x];
  448.             
  449.         else if (HWts[x] + HWts[HWts.Last()-(x-bparams.Xbsep())] < 32)
  450.             HWts[x] = 32-HWts[HWts.Last()-(x-bparams.Xbsep())];
  451.     }// x 
  452.     // Now reflect or pad, as appropriate
  453.     if (!FullX)
  454.     {
  455.         for( int x = 0; x < (bparams.Xblen()>>1) ; ++x)
  456.             HWts[x] = 32;
  457.     }
  458.     else
  459.     {
  460.         for( int x = 0; x < (bparams.Xblen()>>1); ++x)
  461.             HWts[x] = HWts[HWts.Last()-x];
  462.     }
  463.     // Rationalise to avoid rounding errors
  464.     for(int y = VWts.Last(); y > VWts.Last()-bparams.Yoffset(); --y)
  465.     {
  466.         if (VWts[y] + VWts[VWts.Last()-(y-bparams.Ybsep())] > 32)
  467.             VWts[VWts.Last()-(y-bparams.Ybsep())] = 32-VWts[y];
  468.         else if (VWts[y] + VWts[VWts.Last()-(y-bparams.Ybsep())] < 32)
  469.             VWts[y] = 32-VWts[VWts.Last()-(y-bparams.Ybsep())];
  470.     }// x 
  471.     // Reflect or pad, as appropriate
  472.     if (!FullY)
  473.     {
  474.         for( int y = 0 ; y < (bparams.Yblen()>>1); ++y)
  475.             VWts[y] = 32;
  476.     }
  477.     else
  478.     {
  479.         for( int y = 0 ; y < (bparams.Yblen()>>1); ++y)
  480.             VWts[y] = VWts[VWts.Last()-y];
  481.     }
  482.     for(int y = 0; y < bparams.Yblen(); ++y)
  483.     {
  484.         for(int x = 0; x < bparams.Xblen(); ++x)
  485.         {
  486.             WeightArray[y][x] = VWts[y] * HWts[x];
  487.         }// x
  488.     }// y
  489. }
  490. //Flips the values in an array in the x direction.
  491. void MotionCompensator::FlipX(const TwoDArray<CalcValueType>& Original, const OLBParams &bparams, TwoDArray<CalcValueType>& Flipped)
  492. {
  493.     for(int x = 0; x < bparams.Xblen(); ++x)
  494.     {
  495.         for(int y = 0; y < bparams.Yblen(); ++y)
  496.         {
  497.             Flipped[y][x] = Original[y][(bparams.Xblen()-1) - x];
  498.         }// y
  499.     }// x
  500. }
  501. //Flips the values in an array in the y direction.
  502. void MotionCompensator::FlipY(const TwoDArray<CalcValueType>& Original, const OLBParams &bparams, TwoDArray<CalcValueType>& Flipped)
  503. {
  504.     for(int x = 0; x < bparams.Xblen(); ++x)
  505.     {
  506.         for(int y = 0; y < bparams.Yblen(); ++y)
  507.         {
  508.             Flipped[y][x] = Original[(bparams.Yblen()-1) - y][x];
  509.         }// y
  510.     }// x
  511. }