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

多媒体编程

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2. *
  3. * $Id: pixel_match.cpp,v 1.2 2005/01/30 05:11:42 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 Copm_yright (C) 2004.
  21. * All Rights Reserved.
  22. *
  23. * Contributor(s): Thomas Davies (Original Author)
  24. *
  25. * Alternatively, the contents of this file may be used under the terms of
  26. * the GNU General Public License Version 2 (the "GPL"), or the GNU Lesser
  27. * Public License Version 2.1 (the "LGPL"), in which case the provisions of
  28. * the GPL or the LGPL are applicable instead of those above. If you wish to
  29. * allow use of your version of this file only under the terms of the either
  30. * the GPL or LGPL and not to allow others to use your version of this file
  31. * under the MPL, indicate your decision by deleting the provisions above
  32. * and replace them with the notice and other provisions required by the GPL
  33. * or LGPL. If you do not delete the provisions above, a recipient may use
  34. * your version of this file under the terms of any one of the MPL, the GPL
  35. * or the LGPL.
  36. * ***** END LICENSE BLOCK ***** */
  37. #include <libdirac_motionest/pixel_match.h>
  38. #include <libdirac_motionest/block_match.h>
  39. #include <libdirac_common/motion.h>
  40. #include <libdirac_common/frame_buffer.h>
  41. #include <libdirac_motionest/downconvert.h>
  42. #include <libdirac_motionest/me_mode_decn.h>
  43. #include <libdirac_motionest/me_subpel.h>
  44. using namespace dirac;
  45. #include <cmath>
  46. #include <vector>
  47. using std::vector;
  48. using std::log;
  49. PixelMatcher::PixelMatcher( const EncoderParams& encp):
  50.     m_encparams(encp)
  51. {}
  52. void PixelMatcher::DoSearch(const FrameBuffer& my_buffer, int frame_num, MEData& me_data)
  53. {
  54.      //does an initial search using hierarchical matching to get guide vectors    
  55.     // Frame numbers of references
  56.     int ref1,ref2;
  57.     // Use the luminance only for motion estimating
  58.     const PicArray& pic_data = my_buffer.GetComponent( frame_num , Y_COMP );
  59.     const vector<int>& refs = my_buffer.GetFrame( frame_num ).GetFparams().Refs();
  60.     ref1 = refs[0];
  61.     if (refs.size()>1)
  62.         ref2 = refs[1];
  63.     else    
  64.         ref2 = ref1;
  65.     // Obtain C++ references to the reference picture luma components
  66.     const PicArray& ref1_data = my_buffer.GetComponent(ref1 , Y_COMP);
  67.     const PicArray& ref2_data = my_buffer.GetComponent(ref2 , Y_COMP);
  68.     // Determine the frame sort - this affects the motion estimation Lagrangian parameter
  69.     m_fsort = my_buffer.GetFrame(frame_num).GetFparams().FSort();
  70.     // Set the number of downconversion levels - not too many or we run out of picture!    
  71.     m_depth = ( int) std::min( log(((double) pic_data.LengthX())/12.0)/log(2.0) , 
  72.                              log(((double) pic_data.LengthY())/12.0)/log(2.0) );
  73.     // These arrays will contain the downconverted picture and MvData hierarchy
  74.     OneDArray<PicArray*> ref1_down( Range( 1 , m_depth ) );
  75.     OneDArray<PicArray*> ref2_down( Range( 1 , m_depth ) );
  76.     OneDArray<PicArray*> pic_down( Range( 1 , m_depth ) );
  77.     OneDArray<MEData*> me_data_set( Range( 1 , m_depth ) );
  78.     // Populate the hierarchies
  79.     MakePicHierarchy( pic_data , pic_down );
  80.     MakePicHierarchy( ref1_data , ref1_down );
  81.     if (ref1 != ref2)
  82.         MakePicHierarchy( ref2_data , ref2_down );
  83.     MakeMEDataHierarchy( pic_down , me_data_set );
  84.      // Now do the work! //
  85.     //////////////////////
  86.     // Start with motion estimating at the very lowest level
  87.     m_level = m_depth;
  88.     MatchPic( *(pic_down[m_depth]) , *(ref1_down[m_depth]) , *(me_data_set[m_depth]) ,
  89.                                      *(me_data_set[m_depth]) , 1 );    
  90.     if ( ref1 != ref2 )
  91.         MatchPic( *(pic_down[m_depth]) , *(ref2_down[m_depth]) , *(me_data_set[m_depth]) , 
  92.                                          *(me_data_set[m_depth]) , 2 );
  93.      // Do the intervening levels - here we can have a genuine set of guide vectors
  94.     for ( m_level=m_depth-1 ; m_level>=1 ; --m_level )
  95.     {
  96.         MatchPic( *(pic_down[m_level]) , *(ref1_down[m_level]) , *(me_data_set[m_level]) , 
  97.                                          *(me_data_set[m_level+1]) , 1 );
  98.         if (ref1!=ref2)
  99.             MatchPic( *(pic_down[m_level]) , *(ref2_down[m_level]) , *(me_data_set[m_level]) , 
  100.                                              *(me_data_set[m_level+1]) , 2 );
  101.         
  102.     }// level
  103.     // Finally, do the top level, with the pictures themselves
  104.     m_level = 0;
  105.     MatchPic( pic_data , ref1_data, me_data , *(me_data_set[1]) , 1 );
  106.     if ( ref1 != ref2 )
  107.         MatchPic( pic_data , ref2_data , me_data , *(me_data_set[1]) , 2 );
  108.     // Now we're finished, tidy everything up ...
  109.     TidyPics( pic_down );
  110.     TidyPics( ref1_down );
  111.     if (ref1 != ref2)
  112.         TidyPics( ref2_down );
  113.     TidyMEData( me_data_set );
  114. }
  115. void PixelMatcher::MakePicHierarchy(const PicArray& data ,
  116.                                     OneDArray< PicArray* >& down_data)
  117. {
  118.     DownConverter mydcon;
  119.     // Allocate
  120.     int scale_factor = 1;
  121.     for (int i=1 ; i<=m_depth;++i)
  122.     {
  123.         // Dimensions of pic_down[i] will be shrunk by a factor 2**i
  124.         scale_factor*=2;
  125.         down_data[i] = new PicArray( data.LengthY()/scale_factor , data.LengthX()/scale_factor);
  126.     }
  127.     //do all the downconversions
  128.     if (m_depth>0)
  129.     {
  130.         mydcon.DoDownConvert( data , *(down_data[1]) );
  131.         for (int i=1 ; i<m_depth ; ++i)
  132.             mydcon.DoDownConvert( *(down_data[i]) , *(down_data[i+1]) );
  133.     }
  134. }
  135. void PixelMatcher::MakeMEDataHierarchy(const OneDArray< PicArray*>& down_data,
  136.                                        OneDArray< MEData* >& me_data_set )
  137. {
  138.     int xnumblocks , ynumblocks;
  139.     const OLBParams bparams = m_encparams.LumaBParams(2);
  140.     for (int i=1 ; i<=m_depth;++i)
  141.     {
  142.         xnumblocks = down_data[i]->LengthX()/bparams.Xbsep();
  143.         ynumblocks = down_data[i]->LengthY()/bparams.Ybsep();
  144.         if (( down_data[i]->LengthX() )%bparams.Xbsep() != 0)
  145.             xnumblocks++;
  146.         if (( down_data[i]->LengthY() )%bparams.Ybsep() != 0)
  147.             ynumblocks++;
  148.         me_data_set[i] = new MEData( 0 , 0 , xnumblocks , ynumblocks );
  149.     }// i
  150. }
  151. void PixelMatcher::TidyPics( OneDArray< PicArray*>& down_data )
  152. {
  153.     for (int i=1 ; i <= m_depth ; ++i)
  154.     {
  155.         delete down_data[i];
  156.     }// i
  157. }
  158. void PixelMatcher::TidyMEData( OneDArray< MEData*>& me_data_set )
  159. {
  160.     for (int i=1 ; i <= m_depth ; ++i)
  161.     {
  162.         delete me_data_set[i];
  163.     }// i
  164. }
  165. void PixelMatcher::MatchPic(const PicArray& pic_data , const PicArray& ref_data , MEData& me_data ,
  166.                             const MvData& guide_data, int ref_id)
  167. {    
  168.     // Initialisation //
  169.     ////////////////////
  170.     // Set the search ranges according to the level
  171.     if ( m_level == m_depth )
  172.     {
  173.         m_xr = 5;
  174.         m_yr = 5;
  175.     }
  176.     else if ( m_level == m_depth-1 )
  177.     {
  178.         m_xr = 4;
  179.         m_yr = 4;
  180.     }
  181.     else
  182.     {
  183.         m_xr = 2;
  184.         m_yr = 2;
  185.     }
  186.     // Provide aliases for the appropriate motion vector data components
  187.     
  188.     MvArray& mv_array = me_data.Vectors( ref_id );
  189.     const MvArray& guide_array = guide_data.Vectors( ref_id );
  190.     TwoDArray<MvCostData>& pred_costs = me_data.PredCosts( ref_id );
  191.     // Provide a block matching object to do the work
  192.     BlockMatcher my_bmatch( pic_data , ref_data , m_encparams.LumaBParams(2) , mv_array , pred_costs );
  193.     float loc_lambda( 0.0 );
  194.     // Do the work - loop over all the blocks, finding the best match //
  195.     ////////////////////////////////////////////////////////////////////
  196.     /*    
  197.     The idea is for each block construct a list of candidate vectors,which will 
  198.     be tested. This list is actually a list of lists, implemented as a C++
  199.     vector of C++ vectors. This is so that FindBestMatch can shorten the
  200.     search process by looking at the beginning of each sublist and 
  201.     discarding that sub-list if it's too far off.
  202.     */
  203.     // Make a zero-based list that is always used
  204.     m_cand_list.clear();
  205.     MVector zero_mv( 0 , 0 );    
  206.     AddNewVlistD( m_cand_list , zero_mv , m_xr , m_yr);
  207.     // Now loop over the blocks and find the best matches. 
  208.     // The loop is unrolled because predictions are different at picture edges.
  209.     // The purpose of the loop is to create appropriate candidate lists, and then 
  210.     // call the DoBlock() function which does the actual work.
  211.     // First do TL corner
  212.     // Set the prediction as the zero vector
  213.     m_mv_prediction = zero_mv;
  214.     // m_lambda is the Lagrangian smoothing parameter set to zero to get us started
  215.     m_lambda = 0.0;
  216.     DoBlock(0, 0 , pred_costs , mv_array, guide_array , my_bmatch);
  217.     // The rest of the first row
  218.     // ( use reduced lambda here )
  219.     m_lambda = loc_lambda / float( m_encparams.YNumBlocks() );
  220.     for ( int xpos=1 ; xpos<mv_array.LengthX() ; ++xpos )
  221.     {
  222.         m_mv_prediction = mv_array[0][xpos-1];
  223.         DoBlock(xpos, 0 , pred_costs , mv_array, guide_array , my_bmatch);
  224.     }// xpos
  225.     // All the remaining rows except the last 
  226.     for ( int ypos=1 ; ypos<mv_array.LengthY() ; ++ypos )
  227.     {
  228.         // The first element of each row
  229.         m_mv_prediction = mv_array[ypos-1][0];
  230.         m_lambda = loc_lambda/float(m_encparams.XNumBlocks());
  231.         DoBlock(0, ypos , pred_costs , mv_array, guide_array , my_bmatch );
  232.          // The middle elementes of each row
  233.         m_lambda = loc_lambda;
  234.         for ( int xpos=1 ; xpos<mv_array.LastX() ; ++xpos )
  235.         {
  236.             m_mv_prediction = MvMedian( mv_array[ypos][xpos-1],
  237.                                         mv_array[ypos-1][xpos],
  238.                                         mv_array[ypos-1][xpos+1]);
  239.             DoBlock(xpos, ypos , pred_costs , mv_array, guide_array , my_bmatch );
  240.         }// xpos
  241.          // The last element in each row
  242.         m_lambda = loc_lambda/float( m_encparams.XNumBlocks() );
  243.         m_mv_prediction = MvMean( mv_array[ypos-1][ mv_array.LastX() ],
  244.                                   mv_array[ypos][ mv_array.LastX()-1 ]);
  245.         DoBlock(mv_array.LastX() , ypos , pred_costs , mv_array, guide_array , my_bmatch );
  246.     }//ypos
  247. }
  248. void PixelMatcher::DoBlock(int xpos, int ypos ,
  249.                            TwoDArray<MvCostData>& pred_costs,
  250.                            MvArray& mv_array,
  251.                            const MvArray& guide_array,
  252.                            BlockMatcher& block_match)
  253. {
  254.     // Find the best match for each block ...
  255.     // Use guide from lower down if one exists
  256.     if ( m_level<m_depth )
  257.         AddNewVlistD( m_cand_list , guide_array[ ypos>>1 ][ xpos>>1 ] * 2 , m_xr , m_yr );
  258.     // use the spatial prediction, also, as a guide
  259.     AddNewVlistD( m_cand_list , m_mv_prediction , m_xr , m_yr );
  260.     // Find the best motion vector //
  261.     /////////////////////////////////
  262.     block_match.FindBestMatch( xpos , ypos , m_cand_list, m_mv_prediction, m_lambda );
  263.     // Reset the lists ready for the next block (don't erase the first sublist as
  264.     // this is a neighbourhood of zero, which we always look at)
  265.     m_cand_list.erase( m_cand_list.begin()+1 , m_cand_list.end() );
  266. }