- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# mot_comp.cpp

    00001 /* ***** BEGIN LICENSE BLOCK *****
    00002 *
    00003 * $Id: mot_comp.cpp,v 1.3 2005/01/30 05:11:40 gabest Exp $ $Name:  $
    00004 *
    00005 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
    00006 *
    00007 * The contents of this file are subject to the Mozilla Public License
    00008 * Version 1.1 (the "License"); you may not use this file except in compliance
    00009 * with the License. You may obtain a copy of the License at
    00010 * http://www.mozilla.org/MPL/
    00011 *
    00012 * Software distributed under the License is distributed on an "AS IS" basis,
    00013 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
    00014 * the specific language governing rights and limitations under the License.
    00015 *
    00016 * The Original Code is BBC Research and Development code.
    00017 *
    00018 * The Initial Developer of the Original Code is the British Broadcasting
    00019 * Corporation.
    00020 * Portions created by the Initial Developer are Copyright (C) 2004.
    00021 * All Rights Reserved.
    00022 *
    00023 * Contributor(s): Richard Felton (Original Author),
    00024 *                 Thomas Davies,
    00025 *                 Steve Bearcroft
    00026 *
    00027 * Alternatively, the contents of this file may be used under the terms of
    00028 * the GNU General Public License Version 2 (the "GPL"), or the GNU Lesser
    00029 * Public License Version 2.1 (the "LGPL"), in which case the provisions of
    00030 * the GPL or the LGPL are applicable instead of those above. If you wish to
    00031 * allow use of your version of this file only under the terms of the either
    00032 * the GPL or LGPL and not to allow others to use your version of this file
    00033 * under the MPL, indicate your decision by deleting the provisions above
    00034 * and replace them with the notice and other provisions required by the GPL
    00035 * or LGPL. If you do not delete the provisions above, a recipient may use
    00036 * your version of this file under the terms of any one of the MPL, the GPL
    00037 * or the LGPL.
    00038 * ***** END LICENSE BLOCK ***** */
    00039
    00040
    00041 #include <libdirac_common/mot_comp.h>
    00042 #include <libdirac_common/motion.h>
    00043 #include <libdirac_common/frame_buffer.h>
    00044 using namespace dirac;
    00045
    00046 using std::vector;
    00047
    00048 //--public member functions--//
    00050
    00051
    00052 //Constructor
    00053 //Initialises the lookup table that is needed for 1/8th pixel accuracy
    00054 //motion estimation. Creates the necessary arithmetic objects and
    00055 //calls ReConfig to create weighting blocks to fit the values within
    00056 //m_cparams.
    00057 MotionCompensator::MotionCompensator( const CodecParams &cp , const AddOrSub direction ):
    00058     m_cparams(cp),
    00059     luma_or_chroma(true),
    00060     m_add_or_sub( direction )
    00061 {
    00062     //Configure weighting blocks for the first time
    00063     m_block_weights = NULL;
    00064     m_half_block_weights = NULL;
    00065     ReConfig();
    00066 }
    00067
    00068 //Destructor
    00069 MotionCompensator::~MotionCompensator(){
    00070
    00071     //Tidy up the pointers
    00072     delete[] m_block_weights;
    00073     delete[] m_half_block_weights;
    00074 }
    00075
    00076 //Called to perform motion compensated addition/subtraction on an entire frame.
    00077 void MotionCompensator::CompensateFrame(FrameBuffer& my_buffer,int fnum,const MvData& mv_data)
    00078 {
    00079
    00080      int ref1_idx,ref2_idx;
    00081      Frame& my_frame=my_buffer.GetFrame(fnum);
    00082      const FrameSort& fsort=my_frame.GetFparams().FSort();
    00083
    00084      m_cformat = my_frame.GetFparams().CFormat();
    00085
    00086      if (fsort!=I_frame)
    00087      {//we can motion compensate
    00088
    00089          const vector<int>& refs=my_frame.GetFparams().Refs();
    00090          if (refs.size()>0)
    00091          {
    00092              //extract the references
    00093              ref1_idx=refs[0];
    00094              if (refs.size()>1)
    00095                  ref2_idx=refs[1];
    00096              else
    00097                  ref2_idx=refs[0];
    00098
    00099              const Frame& ref1frame=my_buffer.GetFrame(ref1_idx);
    00100              const Frame& ref2frame=my_buffer.GetFrame(ref2_idx);
    00101
    00102              luma_or_chroma = true;
    00103              //now do all the components
    00104              CompensateComponent( my_frame , ref1frame , ref2frame , mv_data , Y_COMP);
    00105
    00106              if ( m_cformat != Yonly )
    00107              {
    00108                  luma_or_chroma = false;
    00109                  CompensateComponent( my_frame , ref1frame , ref2frame , mv_data , U_COMP);
    00110                  CompensateComponent( my_frame , ref1frame , ref2frame , mv_data , V_COMP);
    00111              }
    00112          }
    00113      }
    00114 }
    00115
    00116 //--private member functions--//
    00118
    00119 //Needs to be called if the blocksize changes (and
    00120 //on startup). This method creates an array of weighting
    00121 //blocks that are used to acheive correctly overlapping
    00122 //blocks.
    00123 void MotionCompensator::ReConfig()
    00124 {
    00125     if (luma_or_chroma)
    00126         m_bparams = m_cparams.LumaBParams(2);
    00127     else
    00128         m_bparams = m_cparams.ChromaBParams(2);
    00129
    00130     if(m_block_weights != NULL)
    00131         delete[] m_block_weights;
    00132
    00133     if(m_half_block_weights != NULL)
    00134         delete[] m_half_block_weights;
    00135
    00136     // Create new weights array.
    00137     m_block_weights = new TwoDArray<CalcValueType>[9];
    00138     m_half_block_weights = new TwoDArray<CalcValueType>[9];
    00139     for(int i = 0; i < 9; i++)
    00140     {
    00141         m_block_weights[i].Resize(  m_bparams.Yblen() , m_bparams.Xblen() );
    00142         m_half_block_weights[i].Resize(  m_bparams.Yblen() , m_bparams.Xblen() );
    00143     }
    00144     // We can create all nine weighting blocks by calculating values
    00145     // for four blocks and mirroring them to generate the others.
    00146     CreateBlock( m_bparams , false , false , m_half_block_weights[0] );
    00147     CreateBlock( m_bparams , false , true , m_half_block_weights[3] );
    00148     CreateBlock( m_bparams , true , false , m_half_block_weights[1] );
    00149     CreateBlock( m_bparams , true , true , m_half_block_weights[4] );
    00150
    00151     // Note order of flipping is important.
    00152     FlipX( m_half_block_weights[3] , m_bparams , m_half_block_weights[5] );
    00153     FlipX( m_half_block_weights[0] , m_bparams , m_half_block_weights[2] );
    00154     FlipY( m_half_block_weights[0] , m_bparams , m_half_block_weights[6] );
    00155     FlipX( m_half_block_weights[6] , m_bparams , m_half_block_weights[8] );
    00156     FlipY( m_half_block_weights[1] , m_bparams , m_half_block_weights[7] );
    00157
    00158     for( int k = 0; k < 9; k++)
    00159     {
    00160         for ( int j =m_half_block_weights[k].FirstY(); j <= m_half_block_weights[k].LastY(); j++)
    00161         {
    00162             for ( int i =m_half_block_weights[k].FirstX(); i <= m_half_block_weights[k].LastX(); i++)
    00163             {
    00164                 m_block_weights[k][j][i] = m_half_block_weights[k][j][i] << 1;
    00165             }// i
    00166         }// j
    00167     }// k
    00168 }
    00169
    00170 void MotionCompensator::CompensateComponent(Frame& picframe, const Frame &ref1frame, const Frame& ref2frame,
    00171     const MvData& mv_data,const CompSort cs)
    00172 {
    00173     // Set up references to pictures and references
    00174     PicArray& pic_data_out = picframe.Data( cs );
    00175
    00176     const PicArray& ref1up = ref1frame.UpData( cs );
    00177     const PicArray& ref2up = ref2frame.UpData( cs );
    00178
    00179     // Set up another picture which will contain the MC data, which
    00180     // we'll add or subtract to pic_data_out
    00181     TwoDArray<CalcValueType> pic_data(pic_data_out.LengthY(), pic_data_out.LengthX() , 0);
    00182
    00183     // Factors to compensate for subsampling of chroma
    00184     int xscale_factor = 1;
    00185     int yscale_factor = 1;
    00186
    00187     if ( cs != Y_COMP )
    00188     {
    00189         if (m_cformat == format420)
    00190         {
    00191             xscale_factor = 2;
    00192             yscale_factor = 2;
    00193         }
    00194         else if (m_cformat == format422)
    00195         {
    00196             xscale_factor = 2;
    00197             yscale_factor = 1;
    00198         }
    00199         else if (m_cformat == format411)
    00200         {
    00201             xscale_factor = 4;
    00202             yscale_factor = 1;
    00203         }
    00204
    00205     }
    00206
    00207     // Reference to the relevant DC array
    00208     const TwoDArray<ValueType>& dcarray = mv_data.DC( cs );
    00209
    00210     // Set up references to the vectors
    00211     const int num_refs = picframe.GetFparams().Refs().size();
    00212     const MvArray* mv_array1;
    00213     const MvArray* mv_array2;
    00214     mv_array1 = &mv_data.Vectors(1);
    00215     if (num_refs ==2 )
    00216         mv_array2 = &mv_data.Vectors(2);
    00217     else
    00218         mv_array2 = &mv_data.Vectors(1);
    00219
    00220     ReConfig();//set all the weighting blocks up
    00221
    00222     //Blocks are listed left to right, line by line.
    00223     MVector mv1,mv2;
    00224     PredMode block_mode;
    00225     ValueType dc;
    00226
    00227     //Coords of the top-left corner of a block
    00228     ImageCoords pos;
    00229
    00230     //Loop for each block in the output image.
    00231     //The CompensateBlock function will use the image pointed to by ref1up
    00232     //and add the compensated pixels to the image pointed to by pic_data.
    00233     size_t wgt_idx;
    00234
    00235     //Loop over all the block rows
    00236
    00237     pos.y = -m_bparams.Yoffset();
    00238     for(int yblock = 0; yblock < m_cparams.YNumBlocks(); ++yblock)
    00239     {
    00240         pos.x = -m_bparams.Xoffset();
    00241         //loop over all the blocks in a row
    00242         for(int xblock = 0 ; xblock < m_cparams.XNumBlocks(); ++xblock)
    00243         {
    00244
    00245             //Decide which weights to use.
    00246             if((xblock != 0)&&(xblock < m_cparams.XNumBlocks() - 1))
    00247             {
    00248                 if((yblock != 0)&&(yblock < m_cparams.YNumBlocks() - 1))
    00249                     wgt_idx = 4;
    00250                 else if(yblock == 0)
    00251                     wgt_idx = 1;
    00252                 else
    00253                     wgt_idx= 7;
    00254             }
    00255             else if(xblock == 0)
    00256             {
    00257                 if((yblock != 0)&&(yblock < m_cparams.YNumBlocks() - 1))
    00258                     wgt_idx = 3;
    00259                 else if(yblock == 0)
    00260                     wgt_idx = 0;
    00261                 else
    00262                     wgt_idx = 6;
    00263             }
    00264             else
    00265             {
    00266                 if((yblock != 0)&&(yblock < m_cparams.YNumBlocks() - 1))
    00267                     wgt_idx = 5;
    00268                 else if(yblock == 0)
    00269                     wgt_idx = 2;
    00270                 else
    00271                     wgt_idx = 8;
    00272             }
    00273
    00274             block_mode = mv_data.Mode()[yblock][xblock];
    00275             mv1 = (*mv_array1)[yblock][xblock];
    00276             mv1.x /= xscale_factor;
    00277             mv1.y /= yscale_factor;
    00278
    00279             mv2 = (*mv_array2)[yblock][xblock];
    00280             mv2.x /= xscale_factor;
    00281             mv2.y /= yscale_factor;
    00282
    00283
    00284             dc = dcarray[yblock][xblock]<<2;// DC is only given 8 bits,
    00285                                             // so need to shift to get 10-bit data
    00286
    00287             if(block_mode == REF1_ONLY)
    00288             {
    00289                 CompensateBlock(pic_data, ref1up, mv1, pos, m_block_weights[wgt_idx]);
    00290             }
    00291             else if (block_mode == REF2_ONLY)
    00292             {
    00293                 CompensateBlock(pic_data, ref2up, mv2, pos, m_block_weights[wgt_idx]);
    00294             }
    00295             else if(block_mode == REF1AND2)
    00296             {
    00297                 CompensateBlock(pic_data, ref1up, mv1, pos, m_half_block_weights[wgt_idx]);
    00298                 CompensateBlock(pic_data, ref2up, mv2, pos, m_half_block_weights[wgt_idx]);
    00299             }
    00300             else
    00301             {//we have a DC block.
    00302                 DCBlock(pic_data, dc,pos, m_block_weights[wgt_idx]);
    00303             }
    00304
    00305             //Increment the block horizontal position
    00306             pos.x += m_bparams.Xbsep();
    00307
    00308         }//xblock
    00309
    00310         //Increment the block vertical position
    00311         pos.y += m_bparams.Ybsep();
    00312
    00313     }//yblock
    00314
    00315     if ( m_add_or_sub == SUBTRACT)
    00316     {
    00317         int x_end_data = std::min(pic_data.LastX(), m_cparams.XNumBlocks()*m_bparams.Xbsep() );
    00318         int y_end_data = std::min(pic_data.LastY(), m_cparams.YNumBlocks()*m_bparams.Ybsep() );
    00319
    00320         for ( int i =pic_data.FirstY(); i <= y_end_data; i++)
    00321         {
    00322             for ( int j =pic_data.FirstX(); j <= x_end_data; ++j)
    00323             {
    00324                 pic_data_out[i][j] -= static_cast<ValueType>( (pic_data[i][j] + 1024) >> 11 );
    00325             }
    00326
    00327             // Okay, we've done all the actual blocks. Now if the picture is further padded
    00328             // we need to set the padded values to zero beyond the last block in the row,
    00329             // for all the picture lines in the block row. Need only do this when we're
    00330             // subtracting.
    00331
    00332             for (int j=( m_cparams.XNumBlocks()*m_bparams.Xbsep() ); j<pic_data.LengthX() ; ++j )
    00333             {
    00334                 pic_data_out[i][j] = 0;
    00335             }
    00336         }
    00337         // Finally, now we've done all the blocks, we must set all padded lines below
    00338         // the last row equal to 0, if we're subtracting
    00339         for ( int y=m_cparams.YNumBlocks()*m_bparams.Ybsep() ; y<pic_data.LengthY() ; ++y )
    00340         {
    00341             for ( int x=0 ; x<pic_data.LengthX() ; ++x )
    00342             {
    00343                 pic_data_out[y][x] = 0;
    00344             }
    00345
    00346         }
    00347     }
    00348     else
    00349     {
    00350         for ( int i =pic_data.FirstY(); i <= pic_data.LastY(); i++)
    00351         {
    00352             for ( int j =pic_data.FirstX(); j <= pic_data.LastX(); j++)
    00353             {
    00354                 pic_data_out[i][j] += static_cast<ValueType>( (pic_data[i][j] + 1024) >> 11 );
    00355             }
    00356         }
    00357     }
    00358 }
    00359
    00360 void MotionCompensator::CompensateBlock( TwoDArray<CalcValueType> &pic_data , const PicArray &refup_data , const MVector &mv ,
    00361 const ImageCoords& pos , const TwoDArray<CalcValueType>& wt_array )
    00362 {
    00363
    00364     //Coordinates in the image being written to.
    00365     const ImageCoords start_pos( std::max(pos.x,0) , std::max(pos.y,0) );
    00366     const ImageCoords end_pos( std::min( pos.x + m_bparams.Xblen() , pic_data.LengthX() ) ,
    00367                                std::min( pos.y + m_bparams.Yblen() , pic_data.LengthY() ) );
    00368
    00369     //The difference between the desired start point
    00370     //pos and the actual start point start_pos.
    00371     const ImageCoords diff( start_pos.x - pos.x , start_pos.y - pos.y );
    00372
    00373     //Set up the start point in the reference image by rounding the motion vector
    00374     //NB: bit shift rounds negative values DOWN, as required
    00375     const MVector roundvec( mv.x>>2 , mv.y>>2 );
    00376
    00377     //Get the remainder after rounding. NB rmdr values always 0,1,2 or 3
    00378     const MVector rmdr( mv.x - ( roundvec.x<<2 ) , mv.y - ( roundvec.y<<2 ) );
    00379
    00380     //Where to start in the upconverted image
    00381     const ImageCoords ref_start( ( start_pos.x<<1 ) + roundvec.x ,( start_pos.y<<1 ) + roundvec.y );
    00382
    00383     //weights for doing linear interpolation, calculated from the remainder values
    00384     const ValueType TLweight( (4 - rmdr.x) * (4 - rmdr.y) );
    00385     const ValueType TRweight( rmdr.x * ( 4 - rmdr.y ) );
    00386     const ValueType BLweight( ( 4 - rmdr.x ) * rmdr.y );
    00387     const ValueType BRweight( rmdr.x * rmdr.y );
    00388
    00389     //An additional stage to make sure the block to be copied does not fall outside
    00390     //the reference image.
    00391     const int refXlen = refup_data.LengthX();
    00392     const int refYlen = refup_data.LengthY();
    00393     bool do_bounds_checking = false;
    00394
    00395     //Check if there are going to be any problems copying the block from
    00396     //the upvconverted reference image.
    00397     if( ref_start.x < 0 )
    00398         do_bounds_checking = true;
    00399     else if( ref_start.x + ((end_pos.x - start_pos.x)<<1 ) >= refXlen )
    00400         do_bounds_checking = true;
    00401     if( ref_start.y < 0 )
    00402         do_bounds_checking = true;
    00403     else if( ref_start.y + ((end_pos.y - start_pos.y)<<1 ) >= refYlen)
    00404         do_bounds_checking = true;
    00405
    00406      if( !do_bounds_checking )
    00407      {
    00408          for(int c = start_pos.y, wY = diff.y, uY = ref_start.y; c < end_pos.y; ++c, ++wY, uY += 2)
    00409          {
    00410              for(int l = start_pos.x, wX = diff.x, uX = ref_start.x; l < end_pos.x; ++l, ++wX, uX += 2)
    00411              {
    00412
    00413                  pic_data[c][l] += (( TLweight * refup_data[uY][uX] +
    00414                           TRweight * refup_data[uY][uX+1] +
    00415                           BLweight * refup_data[uY+1][uX] +
    00416                           BRweight * refup_data[uY+1][uX+1] +
    00417                           8
    00418                           ) >> 4) * wt_array[wY][wX];
    00419              }//l
    00420          }//c
    00421      }
    00422      else
    00423      {
    00424          //We're doing bounds checking because we'll fall off the edge of the reference otherwise.
    00425
    00426         for(int c = start_pos.y, wY = diff.y, uY = ref_start.y,BuY=BChk(uY,refYlen),BuY1=BChk(uY+1,refYlen);
    00427             c < end_pos.y; ++c, ++wY, uY += 2,BuY=BChk(uY,refYlen),BuY1=BChk(uY+1,refYlen))
    00428         {
    00429             for(int l = start_pos.x, wX = diff.x, uX = ref_start.x,BuX=BChk(uX,refXlen),BuX1=BChk(uX+1,refXlen);
    00430                 l < end_pos.x; ++l, ++wX, uX += 2,BuX=BChk(uX,refXlen),BuX1=BChk(uX+1,refXlen))
    00431             {
    00432
    00433                 pic_data[c][l] += (( TLweight * refup_data[BuY][BuX] +
    00434                          TRweight * refup_data[BuY][BuX1]  +
    00435                          BLweight * refup_data[BuY1][BuX]+
    00436                          BRweight * refup_data[BuY1][BuX1] +
    00437                          8
    00438                          ) >> 4) * wt_array[wY][wX];
    00439             }//l
    00440         }//c
    00441
    00442     }
    00443
    00444 }
    00445
    00446 void MotionCompensator::DCBlock( TwoDArray<CalcValueType> &pic_data ,const ValueType dc , const ImageCoords& pos ,
    00447     const TwoDArray<CalcValueType>& wt_array)
    00448 {
    00449
    00450     //Coordinates in the image being written to.
    00451     const ImageCoords start_pos( std::max(0 , pos.x) , std::max(0 , pos.y) );
    00452     const ImageCoords end_pos( std::min(pos.x + m_bparams.Xblen() , pic_data.LengthX() ) ,
    00453                                std::min(pos.y + m_bparams.Yblen() , pic_data.LengthY() ) );
    00454
    00455     //The difference between the desired start point
    00456     //pos and the actual start point start_pos.
    00457     const ImageCoords diff(start_pos.x - pos.x , start_pos.y - pos.y);
    00458
    00459     //Quick process where we can just copy from the double size image.
    00460
    00461     for(int c = start_pos.y, wY = diff.y; c < end_pos.y; ++c, ++wY)
    00462     {
    00463         for(int l = start_pos.x, wX = diff.x; l < end_pos.x; ++l, ++wX)
    00464         {
    00465             pic_data[c][l] += dc * wt_array[wY][wX];
    00466         }
    00467     }
    00468 }
    00469
    00470 //Overlapping blocks are acheived by applying a 2D raised cosine shape
    00471 //to them. This function facilitates the calculations
    00472 float MotionCompensator::RaisedCosine(float t, float B)
    00473 {
    00474     if(std::abs(t)>(B+1.0)/2.0)
    00475         return 0.0f;
    00476     else if(std::abs(t)<(1.0-B)/2.0)
    00477         return 1.0f;
    00478     else
    00479         return( 0.5 * ( 1.0 + std::cos( 3.141592654 * ( std::abs(t)-(1.0-B)/2.0 )/B ) ) );
    00480 }
    00481
    00482 //Calculates a weighting block.
    00483 //bparams defines the block parameters so the relevant weighting arrays can be created.
    00484 //FullX and FullY refer to whether the weight should be adjusted for the edge of an image.
    00485 //eg. 1D Weighting shapes in x direction
    00486
    00487 //  FullX true        FullX false
    00488 //     ***           ********
    00489 //   *     *                  *
    00490 //  *       *                  *
    00491 //*           *                  *
    00492
    00493 void MotionCompensator::CreateBlock(const OLBParams &bparams, bool FullX, bool FullY, TwoDArray<CalcValueType>& WeightArray)
    00494 {
    00495     // Create temporary arrays
    00496     OneDArray<CalcValueType> HWts( WeightArray.LengthX() );
    00497     OneDArray<CalcValueType> VWts( WeightArray.LengthY() );
    00498
    00499     // Calculation variables
    00500     float rolloffX = (float(bparams.Xblen()+1)/float(bparams.Xbsep())) - 1;
    00501     float rolloffY = (float(bparams.Yblen()+1)/float(bparams.Ybsep())) - 1;
    00502     float val;
    00503
    00504     // Window in the x direction
    00505     for(int x = 0; x < bparams.Xblen(); ++x)
    00506     {
    00507         val = (float(x) - (float(bparams.Xblen()-1)/2.0))/float(bparams.Xbsep());
    00508         HWts[x] = static_cast<CalcValueType>( 32.0 * RaisedCosine(val,rolloffX) );
    00509         HWts[x] = std::max( HWts[x] , 1 );
    00510         HWts[x] = std::min( HWts[x] , 32 );
    00511     }// x
    00512
    00513     // Window in the y direction
    00514     for(int y = 0; y < bparams.Yblen(); ++y)
    00515     {
    00516         val = (float(y) - (float(bparams.Yblen()-1)/2.0))/float(bparams.Ybsep());
    00517         VWts[y] = static_cast<CalcValueType>( 32.0 * RaisedCosine(val,rolloffY) );
    00518         VWts[y] = std::max( VWts[y] , 1 );
    00519         VWts[y] = std::min( VWts[y] , 32 );
    00520     }// y
    00521
    00522     // Rationalise to avoid rounding errors
    00523     for(int x = HWts.Last(); x > HWts.Last()-bparams.Xoffset(); --x)
    00524     {
    00525         if (HWts[x] + HWts[HWts.Last()-(x-bparams.Xbsep())] > 32)
    00526             HWts[HWts.Last()-(x-bparams.Xbsep())] = 32-HWts[x];
    00527
    00528         else if (HWts[x] + HWts[HWts.Last()-(x-bparams.Xbsep())] < 32)
    00529             HWts[x] = 32-HWts[HWts.Last()-(x-bparams.Xbsep())];
    00530     }// x
    00531
    00532     // Now reflect or pad, as appropriate
    00533     if (!FullX)
    00534     {
    00535         for( int x = 0; x < (bparams.Xblen()>>1) ; ++x)
    00536             HWts[x] = 32;
    00537     }
    00538     else
    00539     {
    00540         for( int x = 0; x < (bparams.Xblen()>>1); ++x)
    00541             HWts[x] = HWts[HWts.Last()-x];
    00542     }
    00543
    00544     // Rationalise to avoid rounding errors
    00545     for(int y = VWts.Last(); y > VWts.Last()-bparams.Yoffset(); --y)
    00546     {
    00547         if (VWts[y] + VWts[VWts.Last()-(y-bparams.Ybsep())] > 32)
    00548             VWts[VWts.Last()-(y-bparams.Ybsep())] = 32-VWts[y];
    00549         else if (VWts[y] + VWts[VWts.Last()-(y-bparams.Ybsep())] < 32)
    00550             VWts[y] = 32-VWts[VWts.Last()-(y-bparams.Ybsep())];
    00551     }// x
    00552
    00553     // Reflect or pad, as appropriate
    00554     if (!FullY)
    00555     {
    00556         for( int y = 0 ; y < (bparams.Yblen()>>1); ++y)
    00557             VWts[y] = 32;
    00558     }
    00559     else
    00560     {
    00561         for( int y = 0 ; y < (bparams.Yblen()>>1); ++y)
    00562             VWts[y] = VWts[VWts.Last()-y];
    00563     }
    00564
    00565     for(int y = 0; y < bparams.Yblen(); ++y)
    00566     {
    00567         for(int x = 0; x < bparams.Xblen(); ++x)
    00568         {
    00569             WeightArray[y][x] = VWts[y] * HWts[x];
    00570         }// x
    00571     }// y
    00572
    00573 }
    00574
    00575 //Flips the values in an array in the x direction.
    00576 void MotionCompensator::FlipX(const TwoDArray<CalcValueType>& Original, const OLBParams &bparams, TwoDArray<CalcValueType>& Flipped)
    00577 {
    00578     for(int x = 0; x < bparams.Xblen(); ++x)
    00579     {
    00580         for(int y = 0; y < bparams.Yblen(); ++y)
    00581         {
    00582             Flipped[y][x] = Original[y][(bparams.Xblen()-1) - x];
    00583         }// y
    00584     }// x
    00585 }
    00586
    00587 //Flips the values in an array in the y direction.
    00588 void MotionCompensator::FlipY(const TwoDArray<CalcValueType>& Original, const OLBParams &bparams, TwoDArray<CalcValueType>& Flipped)
    00589 {
    00590     for(int x = 0; x < bparams.Xblen(); ++x)
    00591     {
    00592         for(int y = 0; y < bparams.Yblen(); ++y)
    00593         {
    00594             Flipped[y][x] = Original[(bparams.Yblen()-1) - y][x];
    00595         }// y
    00596     }// x
    00597 }