Dirac - A Video Codec

Created by the British Broadcasting Corporation.


motion.h

Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK ***** 00002 * 00003 * $Id: motion.h,v 1.12 2004/09/17 15:43:50 asuraparaju Exp $ $Name: Dirac_0_4_3 $ 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): Thomas Davies (Original Author), Chris Bowley 00024 * 00025 * Alternatively, the contents of this file may be used under the terms of 00026 * the GNU General Public License Version 2 (the "GPL"), or the GNU Lesser 00027 * Public License Version 2.1 (the "LGPL"), in which case the provisions of 00028 * the GPL or the LGPL are applicable instead of those above. If you wish to 00029 * allow use of your version of this file only under the terms of the either 00030 * the GPL or LGPL and not to allow others to use your version of this file 00031 * under the MPL, indicate your decision by deleting the provisions above 00032 * and replace them with the notice and other provisions required by the GPL 00033 * or LGPL. If you do not delete the provisions above, a recipient may use 00034 * your version of this file under the terms of any one of the MPL, the GPL 00035 * or the LGPL. 00036 * ***** END LICENSE BLOCK ***** */ 00037 00038 #include <libdirac_common/common.h> 00039 #include <algorithm> 00040 #ifndef _MOTION_H 00041 #define _MOTION_H 00042 00044 //classes and functions for motion estimation and compensation// 00046 00047 //classes 00048 00050 template <class T> 00051 class MotionVector 00052 { 00053 public: 00054 00056 MotionVector<T>(T a, T b) : x(a), y(b) {}; 00058 MotionVector<T>() : x(0), y(0) {}; 00060 MotionVector<T>(T a) : x(a), y(a) {}; 00061 00063 inline MotionVector<T> operator+(const MotionVector<T>& argument) const; 00064 00066 inline MotionVector<T> operator-(const MotionVector<T>& argument) const; 00067 00069 inline MotionVector<T> operator*(const float argument) const; 00070 00072 inline MotionVector<T> operator*(const int argument) const; 00073 00075 inline MotionVector<T> operator<<(const int argument) const; 00076 00078 inline MotionVector<T> operator>>(const int argument) const; 00079 00080 00082 T x,y; 00083 00084 }; 00085 00086 00087 template <class T> 00088 inline MotionVector<T> MotionVector<T>::operator+(const MotionVector<T>& argument) const 00089 { 00090 MotionVector<T> temp; 00091 temp.x = x + argument.x; 00092 temp.y = y + argument.y; 00093 00094 return temp; 00095 } 00096 00097 template <class T> 00098 inline MotionVector<T> MotionVector<T>::operator-(const MotionVector<T>& argument) const 00099 { 00100 MotionVector<T> temp; 00101 temp.x = x-argument.x; 00102 temp.y = y-argument.y; 00103 00104 return temp; 00105 } 00106 00107 template <class T> 00108 inline MotionVector<T> MotionVector<T>::operator*(const float argument) const 00109 { 00110 MotionVector<T> temp; 00111 temp.x = x*argument; 00112 temp.y = y*argument; 00113 00114 return temp; 00115 } 00116 00117 template <class T> 00118 inline MotionVector<T> MotionVector<T>::operator*(const int argument) const 00119 { 00120 MotionVector<T> temp; 00121 temp.x = x*argument; 00122 temp.y = y*argument; 00123 00124 return temp; 00125 } 00126 00127 template <class T> 00128 inline MotionVector<T> MotionVector<T>::operator<<(const int argument) const 00129 { 00130 MotionVector<T> temp; 00131 temp.x = x<<argument; 00132 temp.y = y<<argument; 00133 00134 return temp; 00135 } 00136 00137 template <class T> 00138 inline MotionVector<T> MotionVector<T>::operator>>(const int argument) const 00139 { 00140 MotionVector<T> temp; 00141 temp.x = x>>argument; 00142 temp.y = y>>argument; 00143 00144 return temp; 00145 } 00146 00148 template <class T> 00149 std::ostream & operator<< (std::ostream & stream, MotionVector<T> & mv) 00150 { 00151 stream << mv.x << " " << mv.y; 00152 00153 return stream; 00154 } 00155 00157 template <class T> 00158 std::istream & operator>> (std::istream & stream, MotionVector<T> & mv) 00159 { 00160 stream >> mv.x; 00161 stream >> mv.y; 00162 00163 return stream; 00164 } 00165 00167 typedef MotionVector<int> MVector; 00168 00170 typedef MotionVector<int> ImageCoords; 00171 00173 typedef TwoDArray<MVector> MvArray; 00174 00176 class MvCostData 00177 { 00178 public: 00180 MvCostData(): 00181 SAD(0.0), 00182 mvcost(0.0), 00183 total(0.0){} 00184 00185 void SetTotal( const float lambda ){total = SAD + lambda*mvcost;} 00186 00188 float SAD; 00189 00191 float mvcost; 00192 00194 float total; 00195 }; 00196 00197 00199 00203 class MvData 00204 { 00205 public: 00207 00215 MvData( const int xnumMB, int ynumMB , 00216 const int xnumblocks, int ynumblocks , const int num_refs = 2); 00217 00219 00225 MvData( const int xnumMB, int ynumMB , const int num_refs = 2); 00226 00228 ~MvData(); 00229 00231 MvArray& Vectors(const int ref_id){return *( m_vectors[ref_id] );} 00232 00234 const MvArray& Vectors(const int ref_id) const {return *( m_vectors[ref_id] );} 00235 00237 TwoDArray<ValueType>& DC(CompSort cs){return *( m_dc[cs] );} 00238 00240 const TwoDArray<ValueType>& DC(CompSort cs) const {return *( m_dc[cs] );} 00241 00243 const OneDArray< TwoDArray<ValueType>* >& DC() const {return m_dc;} 00244 00246 TwoDArray<PredMode>& Mode(){return m_modes;} 00247 00249 const TwoDArray<PredMode>& Mode() const {return m_modes;} 00250 00252 TwoDArray<int>& MBSplit(){return m_mb_split;} 00253 00255 const TwoDArray<int>& MBSplit() const{return m_mb_split;} 00256 00258 TwoDArray<bool>& MBCommonMode(){return m_mb_common;} 00259 00261 const TwoDArray<bool>& MBCommonMode() const{return m_mb_common;} 00262 00263 private: 00264 // Initialises the arrays of data 00265 void InitMvData(); 00266 00267 // The motion vectors 00268 OneDArray<MvArray*> m_vectors; 00269 00270 // The block modes 00271 TwoDArray<PredMode> m_modes; 00272 00273 // The DC values 00274 OneDArray< TwoDArray<ValueType>* > m_dc; 00275 00276 // The MB split levels 00277 TwoDArray<int> m_mb_split; 00278 00279 // The MB common mode indicators 00280 TwoDArray<bool> m_mb_common; 00281 00282 00283 }; 00284 00286 00291 class MEData: public MvData 00292 { 00293 public: 00294 00296 00304 MEData( const int xnumMB, const int ynumMB , 00305 const int xnumblocks, const int ynumblocks , const int num_refs = 2); 00306 00308 00314 MEData( const int xnumMB, const int ynumMB , const int num_refs = 2); 00315 00317 ~MEData(); 00318 00320 TwoDArray<MvCostData>& PredCosts(const int ref_id){ return *( m_pred_costs[ref_id] ); } 00321 00323 const TwoDArray<MvCostData>& PredCosts(const int ref_id) const { return *( m_pred_costs[ref_id] ); } 00324 00326 TwoDArray<float>& IntraCosts(){ return m_intra_costs; } 00327 00329 const TwoDArray<float>& IntraCosts() const { return m_intra_costs; } 00330 00332 TwoDArray<MvCostData>& BiPredCosts(){ return m_bipred_costs; } 00333 00335 const TwoDArray<MvCostData>& BiPredCosts() const { return m_bipred_costs; } 00336 00338 TwoDArray<float>& MBCosts(){ return m_MB_costs; } 00339 00341 const TwoDArray<float>& MBCosts() const { return m_MB_costs; } 00342 00344 void SetLambdaMap( const int num_refs , const float lambda ); 00345 00347 void SetLambdaMap( const int level , const TwoDArray<float>& l_map , const float wt ); 00348 00350 const TwoDArray<float> LambdaMap() const { return m_lambda_map; } 00351 00353 friend std::ostream &operator<< (std::ostream & stream, MEData & me_data); 00354 00356 friend std::istream &operator>> (std::istream & stream, MEData & me_data); 00357 00358 private: 00359 // Initialises the arrays of data 00360 void InitMEData(); 00361 00362 // Finds transitions in the motion vectors 00363 void FindTransitions( TwoDArray<bool>& trans_map , const int ref_num ); 00364 00365 // The costs of predicting each block, for each reference 00366 OneDArray< TwoDArray<MvCostData>* > m_pred_costs; 00367 00368 // The costs of predicting each block by DC 00369 TwoDArray<float> m_intra_costs; 00370 00371 // The costs of predicting each block bidirectionally 00372 TwoDArray<MvCostData> m_bipred_costs; 00373 00374 // The costs for each macroblock as a whole 00375 TwoDArray<float> m_MB_costs; 00376 00377 // A map of the lambda values to use 00378 TwoDArray<float> m_lambda_map; 00379 00380 }; 00381 00382 // Motion compensation stuff // 00384 00385 00386 //First have arithmetic classes to avoid code duplication 00387 00389 class ArithObj{ 00390 public: 00391 virtual ~ArithObj(){} 00392 virtual void DoArith(ValueType &lhs, const CalcValueType rhs, const CalcValueType &Weight) const = 0; 00393 00394 protected: 00395 }; 00396 00398 class ArithAddObj : public ArithObj{ 00399 public: 00400 void DoArith(ValueType &lhs, const CalcValueType rhs, const CalcValueType &Weight) const; 00401 }; 00402 00404 class ArithSubtractObj : public ArithObj{ 00405 public: 00406 void DoArith(ValueType &lhs, const CalcValueType rhs, const CalcValueType &Weight) const; 00407 }; 00408 00410 class ArithHalfAddObj : public ArithObj{ 00411 public: 00412 void DoArith(ValueType &lhs, const CalcValueType rhs, const CalcValueType &Weight) const; 00413 }; 00414 00416 class ArithHalfSubtractObj : public ArithObj{ 00417 public: 00418 void DoArith(ValueType &lhs, const CalcValueType rhs, const CalcValueType &Weight) const; 00419 }; 00420 00421 00422 //Overlapping blocks are acheived by applying a 2D raised cosine shape 00423 //to them. This function facilitates the calculations 00424 float RaisedCosine(float t, float B); 00425 00426 //Calculates a weighting block. 00427 //Params defines the block parameters so the relevant weighting arrays can be created. 00428 //FullX and FullY refer to whether the weight should be adjusted for the edge of an image. 00429 //eg. 1D Weighting shapes in x direction 00430 // FullX true FullX false 00431 // *** ******** 00432 // * * * 00433 // * * * 00434 //* * * 00435 void CreateBlock(const OLBParams &bparams, bool FullX, bool FullY, TwoDArray<CalcValueType>& WeightArray); 00436 00438 void FlipX(const TwoDArray<CalcValueType>& Original, const OLBParams &bparams, TwoDArray<CalcValueType>& Flipped); 00439 00441 void FlipY(const TwoDArray<CalcValueType>& Original, const OLBParams &bparams, TwoDArray<CalcValueType>& Flipped); 00442 00443 //motion estimation and coding stuff 00444 00446 inline MVector MvMedian(const MVector& mv1,const MVector& mv2,const MVector& mv3) { 00447 //takes median of each vector component 00448 MVector tmp_mv; 00449 00450 tmp_mv.x=mv1.x; 00451 tmp_mv.x+=mv2.x; 00452 tmp_mv.x+=mv3.x; 00453 00454 tmp_mv.x-=std::max(std::max(mv1.x,mv2.x),mv3.x); 00455 tmp_mv.x-=std::min(std::min(mv1.x,mv2.x),mv3.x); 00456 00457 tmp_mv.y=mv1.y; 00458 tmp_mv.y+=mv2.y; 00459 tmp_mv.y+=mv3.y; 00460 00461 tmp_mv.y-=std::max(std::max(mv1.y,mv2.y),mv3.y); 00462 tmp_mv.y-=std::min(std::min(mv1.y,mv2.y),mv3.y); 00463 00464 return tmp_mv; 00465 } 00466 00468 inline MVector MvMedian(const std::vector<MVector>& vect_list){ 00469 //more general median. Takes the median of each vector component 00470 00471 MVector median; 00472 int num_vals=int(vect_list.size()); 00473 if (num_vals>0) { 00474 int pos=0; 00475 std::vector<int> ordered_vals(vect_list.size()); 00476 //do x first 00477 ordered_vals[0]=vect_list[0].x; 00478 for (int I=1;I<num_vals;++I){ 00479 for (int K=0;K<I;++K){ 00480 if (vect_list[I].x<ordered_vals[K]){ 00481 pos=K; 00482 break; 00483 } 00484 else 00485 pos=K+1; 00486 }//K 00487 if (pos==I) 00488 ordered_vals[I]=vect_list[I].x; 00489 else{ 00490 for (int K=pos;K>=I-1;--K){ 00491 ordered_vals[K+1]=ordered_vals[K]; 00492 } 00493 ordered_vals[pos]=vect_list[I].x; 00494 } 00495 }//I 00496 if (vect_list.size()%2!=0) 00497 median.x=ordered_vals[(num_vals-1)/2]; 00498 else 00499 median.x=(ordered_vals[(num_vals/2)-1]+ordered_vals[num_vals/2])/2; 00500 00501 //now do y 00502 ordered_vals[0]=vect_list[0].y; 00503 for (int I=1;I<num_vals;++I){ 00504 for (int K=0;K<I;++K){ 00505 if (vect_list[I].y<ordered_vals[K]){ 00506 pos=K; 00507 break; 00508 } 00509 else 00510 pos=K+1; 00511 }//K 00512 if (pos==I) 00513 ordered_vals[I]=vect_list[I].y; 00514 else{ 00515 for (int K=pos;K>=I-1;--K){ 00516 ordered_vals[K+1]=ordered_vals[K]; 00517 } 00518 ordered_vals[pos]=vect_list[I].y; 00519 } 00520 }//I 00521 if (num_vals%2!=0) 00522 median.y=ordered_vals[(num_vals-1)/2]; 00523 else 00524 median.y=(ordered_vals[(num_vals/2)-1]+ordered_vals[num_vals/2])/2; 00525 00526 } 00527 else{ 00528 median.x=0; 00529 median.y=0; 00530 } 00531 return median; 00532 } 00533 00535 inline MVector MvMean(MVector& mv1,MVector& mv2) { 00536 //takes median of each vector component 00537 MVector tmp_mv; 00538 00539 tmp_mv.x=mv1.x; 00540 tmp_mv.x+=mv2.x; 00541 tmp_mv.x/=2; 00542 00543 tmp_mv.y=mv1.y; 00544 tmp_mv.y+=mv2.y; 00545 tmp_mv.y/=2; 00546 00547 return tmp_mv; 00548 } 00549 00551 inline int Norm2(const MVector& mv){//L^2 norm of a motion vector 00552 return mv.x*mv.x+mv.y*mv.y; 00553 } 00554 00556 inline int Norm1(const MVector& mv){//L^1 norm of a motion vector 00557 return abs(mv.x)+abs(mv.y); 00558 } 00559 00561 inline int GetMean(std::vector<int>& values){ 00562 int sum=0; 00563 for (unsigned int I=0;I<values.size();++I) 00564 sum+=values[I]; 00565 sum/=int(values.size()); 00566 return sum; 00567 } 00568 00570 inline unsigned int GetMean(std::vector<unsigned int>& values){ 00571 int sum=0; 00572 for (unsigned int I=0;I<values.size();++I) 00573 sum+=values[I]; 00574 sum+=(values.size()>>1); 00575 sum/=values.size(); 00576 return sum; 00577 } 00578 00579 #endif

© 2004 British Broadcasting Corporation. Dirac code licensed under the Mozilla Public License (MPL) Version 1.1.
HTML documentation generated by Dimitri van Heesch's excellent Doxygen tool.