Home | History | Annotate | Download | only in dbreg
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /*
     18 #sourcefile  vpmotion/vp_motionmodel.c
     19 #category    motion-model
     20 *
     21 * Copyright 1998 Sarnoff Corporation
     22 * All Rights Reserved
     23 *
     24 * Modification History
     25 *      Date: 02/14/98
     26 *      Author: supuns
     27 *      Shop Order: 17xxx
     28 *              @(#) $Id: vp_motionmodel.c,v 1.4 2011/06/17 14:04:33 mbansal Exp $
     29 */
     30 
     31 /*
     32 * ===================================================================
     33 * Include Files
     34 */
     35 
     36 #include <string.h> /* memmove */
     37 #include <math.h>
     38 #include "vp_motionmodel.h"
     39 
     40 /* Static Functions */
     41 static
     42 double Det3(double m[3][3])
     43 {
     44   double result;
     45 
     46   result =
     47     m[0][0]*m[1][1]*m[2][2] + m[0][1]*m[1][2]*m[2][0] +
     48     m[0][2]*m[1][0]*m[2][1] - m[0][2]*m[1][1]*m[2][0] -
     49     m[0][0]*m[1][2]*m[2][1] - m[0][1]*m[1][0]*m[2][2];
     50 
     51   return(result);
     52 }
     53 
     54 typedef double MATRIX[4][4];
     55 
     56 static
     57 double Det4(MATRIX m)
     58 {
     59     /* ==> This is a poor implementation of determinant.
     60        Writing the formula out in closed form is unnecessarily complicated
     61        and mistakes are easy to make. */
     62   double result;
     63 
     64   result=
     65     m[0][3] *m[1][2] *m[2][1] *m[3][0] - m[0][2] *m[1][3] *m[2][1] *m[3][0] - m[0][3] *m[1][1] *m[2][2] *m[3][0] +
     66     m[0][1] *m[1][3] *m[2][2] *m[3][0] + m[0][2] *m[1][1] *m[2][3] *m[3][0] - m[0][1] *m[1][2] *m[2][3] *m[3][0] - m[0][3] *m[1][2] *m[2][0] *m[3][1] +
     67     m[0][2] *m[1][3] *m[2][0] *m[3][1] + m[0][3] *m[1][0] *m[2][2] *m[3][1] - m[0][0] *m[1][3] *m[2][2] *m[3][1] - m[0][2] *m[1][0] *m[2][3] *m[3][1] +
     68     m[0][0] *m[1][2] *m[2][3] *m[3][1] + m[0][3] *m[1][1] *m[2][0] *m[3][2] - m[0][1] *m[1][3] *m[2][0] *m[3][2] - m[0][3] *m[1][0] *m[2][1] *m[3][2] +
     69     m[0][0] *m[1][3] *m[2][1] *m[3][2] + m[0][1] *m[1][0] *m[2][3] *m[3][2] - m[0][0] *m[1][1] *m[2][3] *m[3][2] - m[0][2] *m[1][1] *m[2][0] *m[3][3] +
     70     m[0][1] *m[1][2] *m[2][0] *m[3][3] + m[0][2] *m[1][0] *m[2][1] *m[3][3] - m[0][0] *m[1][2] *m[2][1] *m[3][3] - m[0][1] *m[1][0] *m[2][2] *m[3][3] +
     71     m[0][0] *m[1][1] *m[2][2] *m[3][3];
     72   /*
     73     m[0][0]*m[1][1]*m[2][2]*m[3][3]-m[0][1]*m[1][0]*m[2][2]*m[3][3]+
     74     m[0][1]*m[1][2]*m[2][0]*m[3][3]-m[0][2]*m[1][1]*m[2][0]*m[3][3]+
     75     m[0][2]*m[1][0]*m[2][1]*m[3][3]-m[0][0]*m[1][2]*m[2][1]*m[3][3]+
     76     m[0][0]*m[1][2]*m[2][3]*m[3][1]-m[0][2]*m[1][0]*m[2][3]*m[3][1]+
     77     m[0][2]*m[1][3]*m[2][0]*m[3][1]-m[0][3]*m[1][2]*m[2][0]*m[3][1]+
     78     m[0][3]*m[1][0]*m[2][2]*m[3][1]-m[0][0]*m[1][3]*m[2][2]*m[3][1]+
     79     m[0][0]*m[1][3]*m[2][1]*m[3][2]-m[0][3]*m[1][0]*m[2][3]*m[3][2]+
     80     m[0][1]*m[1][0]*m[2][3]*m[3][2]-m[0][0]*m[1][1]*m[2][0]*m[3][2]+
     81     m[0][3]*m[1][1]*m[2][0]*m[3][2]-m[0][1]*m[1][3]*m[2][1]*m[3][2]+
     82     m[0][1]*m[1][3]*m[2][2]*m[3][0]-m[0][3]*m[1][1]*m[2][2]*m[3][0]+
     83     m[0][2]*m[1][1]*m[2][3]*m[3][0]-m[0][1]*m[1][2]*m[2][3]*m[3][0]+
     84     m[0][3]*m[1][2]*m[2][1]*m[3][0]-m[0][2]*m[1][3]*m[2][1]*m[3][0];
     85     */
     86   return(result);
     87 }
     88 
     89 static
     90 int inv4Mat(const VP_MOTION* in, VP_MOTION* out)
     91 {
     92     /* ==> This is a poor implementation of inversion.  The determinant
     93        method is O(N^4), i.e. unnecessarily slow, and not numerically accurate.
     94        The real complexity of inversion is O(N^3), and is best done using
     95        LU decomposition. */
     96 
     97   MATRIX inmat,outmat;
     98   int i, j, k, l, m, n,ntemp;
     99   double mat[3][3], indet, temp;
    100 
    101   /* check for non-empty structures structure */
    102   if (((VP_MOTION *) NULL == in) || ((VP_MOTION *) NULL == out)) {
    103     return 1;
    104   }
    105 
    106   for(k=0,i=0;i<4;i++)
    107     for(j=0;j<4;j++,k++)
    108       inmat[i][j]=(double)in->par[k];
    109 
    110   indet = Det4(inmat);
    111   if (indet==0) return(-1);
    112 
    113   for (i=0;i<4;i++) {
    114     for (j=0;j<4;j++) {
    115       m = 0;
    116       for (k=0;k<4;k++) {
    117     if (i != k) {
    118       n = 0;
    119       for (l=0;l<4;l++)
    120         if (j != l) {
    121           mat[m][n] = inmat[k][l];
    122           n++;
    123         }
    124       m++;
    125     }
    126       }
    127 
    128       temp = -1.;
    129       ntemp = (i +j ) %2;
    130       if( ntemp == 0)  temp = 1.;
    131 
    132       outmat[j][i] = temp * Det3(mat)/indet;
    133     }
    134   }
    135 
    136   for(k=0,i=0;i<4;i++)
    137     for(j=0;j<4;j++,k++)
    138       out->par[k]=(VP_PAR)outmat[i][j]; /*lint !e771*/
    139 
    140   return(0);
    141 }
    142 
    143 /*
    144 * ===================================================================
    145 * Public Functions
    146 #htmlstart
    147 */
    148 
    149 /*
    150  * ===================================================================
    151 #fn vp_invert_motion
    152 #ft invert a motion
    153 #fd DEFINITION
    154        Bool
    155        vp_invert_motion(const VP_MOTION* in,VP_MOTION* out)
    156 #fd PURPOSE
    157        This inverts the motion given in 'in'.
    158        All motion models upto VP_MOTION_SEMI_PROJ_3D are supported.
    159        It is assumed that the all 16 parameters are properly
    160        initialized although you may not be using them. You could
    161        use the VP_KEEP_ macro's defined in vp_motionmodel.h to set
    162        the un-initialized parameters. This uses a 4x4 matrix invertion
    163        function internally.
    164        It is SAFE to pass the same pointer as both the 'in' and 'out'
    165        parameters.
    166 #fd INPUTS
    167        in  - input motion
    168 #fd OUTPUTS
    169        out - output inverted motion. If singular matrix uninitialized.
    170              if MWW(in) is non-zero it is also normalized.
    171 #fd RETURNS
    172        FALSE - matrix is singular or motion model not supported
    173        TRUE  - otherwise
    174 #fd SIDE EFFECTS
    175        None
    176 #endfn
    177 */
    178 
    179 int vp_invert_motion(const VP_MOTION* in,VP_MOTION* out)
    180 {
    181   int refid;
    182 
    183   /* check for non-empty structures structure */
    184   if (((VP_MOTION *) NULL == in) || ((VP_MOTION *) NULL == out)) {
    185     return FALSE;
    186   }
    187 
    188   if (in->type>VP_MOTION_SEMI_PROJ_3D) {
    189     return FALSE;
    190   }
    191 
    192   if (inv4Mat(in,out)<0)
    193     return FALSE;
    194 
    195   /*VP_NORMALIZE(*out);*/
    196   out->type = in->type;
    197   refid=in->refid;
    198   out->refid=in->insid;
    199   out->insid=refid;
    200   return TRUE;
    201 }
    202 
    203 /*
    204 * ===================================================================
    205 #fn vp_cascade_motion
    206 #ft Cascade two motion transforms
    207 #fd DEFINITION
    208       Bool
    209       vp_cascade_motion(const VP_MOTION* InAB,const VP_MOTION* InBC,VP_MOTION* OutAC)
    210 #fd PURPOSE
    211       Given Motion Transforms A->B and B->C, this function will
    212       generate a New Motion that describes the transformation
    213       from A->C.
    214       More specifically, OutAC = InBC * InAC.
    215       This function works ok if InAB,InBC and OutAC are the same pointer.
    216 #fd INPUTS
    217       InAB - First Motion Transform
    218       InBC - Second Motion Tranform
    219 #fd OUTPUTS
    220       OutAC - Cascaded Motion
    221 #fd RETURNS
    222       FALSE - motion model not supported
    223       TRUE  - otherwise
    224 #fd SIDE EFFECTS
    225       None
    226 #endfn
    227 */
    228 
    229 int vp_cascade_motion(const VP_MOTION* InA, const VP_MOTION* InB,VP_MOTION* Out)
    230 {
    231     /* ==> This is a poor implementation of matrix multiplication.
    232        Writing the formula out in closed form is unnecessarily complicated
    233        and mistakes are easy to make. */
    234   VP_PAR mxx,mxy,mxz,mxw;
    235   VP_PAR myx,myy,myz,myw;
    236   VP_PAR mzx,mzy,mzz,mzw;
    237   VP_PAR mwx,mwy,mwz,mww;
    238 
    239   /* check for non-empty structures structure */
    240   if (((VP_MOTION *) NULL == InA) || ((VP_MOTION *) NULL == InB) ||
    241       ((VP_MOTION *) NULL == Out)) {
    242     return FALSE;
    243   }
    244 
    245   if (InA->type>VP_MOTION_PROJ_3D) {
    246     return FALSE;
    247   }
    248 
    249   if (InB->type>VP_MOTION_PROJ_3D) {
    250     return FALSE;
    251   }
    252 
    253   mxx = MXX(*InB)*MXX(*InA)+MXY(*InB)*MYX(*InA)+MXZ(*InB)*MZX(*InA)+MXW(*InB)*MWX(*InA);
    254   mxy = MXX(*InB)*MXY(*InA)+MXY(*InB)*MYY(*InA)+MXZ(*InB)*MZY(*InA)+MXW(*InB)*MWY(*InA);
    255   mxz = MXX(*InB)*MXZ(*InA)+MXY(*InB)*MYZ(*InA)+MXZ(*InB)*MZZ(*InA)+MXW(*InB)*MWZ(*InA);
    256   mxw = MXX(*InB)*MXW(*InA)+MXY(*InB)*MYW(*InA)+MXZ(*InB)*MZW(*InA)+MXW(*InB)*MWW(*InA);
    257   myx = MYX(*InB)*MXX(*InA)+MYY(*InB)*MYX(*InA)+MYZ(*InB)*MZX(*InA)+MYW(*InB)*MWX(*InA);
    258   myy = MYX(*InB)*MXY(*InA)+MYY(*InB)*MYY(*InA)+MYZ(*InB)*MZY(*InA)+MYW(*InB)*MWY(*InA);
    259   myz = MYX(*InB)*MXZ(*InA)+MYY(*InB)*MYZ(*InA)+MYZ(*InB)*MZZ(*InA)+MYW(*InB)*MWZ(*InA);
    260   myw = MYX(*InB)*MXW(*InA)+MYY(*InB)*MYW(*InA)+MYZ(*InB)*MZW(*InA)+MYW(*InB)*MWW(*InA);
    261   mzx = MZX(*InB)*MXX(*InA)+MZY(*InB)*MYX(*InA)+MZZ(*InB)*MZX(*InA)+MZW(*InB)*MWX(*InA);
    262   mzy = MZX(*InB)*MXY(*InA)+MZY(*InB)*MYY(*InA)+MZZ(*InB)*MZY(*InA)+MZW(*InB)*MWY(*InA);
    263   mzz = MZX(*InB)*MXZ(*InA)+MZY(*InB)*MYZ(*InA)+MZZ(*InB)*MZZ(*InA)+MZW(*InB)*MWZ(*InA);
    264   mzw = MZX(*InB)*MXW(*InA)+MZY(*InB)*MYW(*InA)+MZZ(*InB)*MZW(*InA)+MZW(*InB)*MWW(*InA);
    265   mwx = MWX(*InB)*MXX(*InA)+MWY(*InB)*MYX(*InA)+MWZ(*InB)*MZX(*InA)+MWW(*InB)*MWX(*InA);
    266   mwy = MWX(*InB)*MXY(*InA)+MWY(*InB)*MYY(*InA)+MWZ(*InB)*MZY(*InA)+MWW(*InB)*MWY(*InA);
    267   mwz = MWX(*InB)*MXZ(*InA)+MWY(*InB)*MYZ(*InA)+MWZ(*InB)*MZZ(*InA)+MWW(*InB)*MWZ(*InA);
    268   mww = MWX(*InB)*MXW(*InA)+MWY(*InB)*MYW(*InA)+MWZ(*InB)*MZW(*InA)+MWW(*InB)*MWW(*InA);
    269 
    270   MXX(*Out)=mxx; MXY(*Out)=mxy; MXZ(*Out)=mxz; MXW(*Out)=mxw;
    271   MYX(*Out)=myx; MYY(*Out)=myy; MYZ(*Out)=myz; MYW(*Out)=myw;
    272   MZX(*Out)=mzx; MZY(*Out)=mzy; MZZ(*Out)=mzz; MZW(*Out)=mzw;
    273   MWX(*Out)=mwx; MWY(*Out)=mwy; MWZ(*Out)=mwz; MWW(*Out)=mww;
    274   /* VP_NORMALIZE(*Out); */
    275   Out->type= (InA->type > InB->type) ? InA->type : InB->type;
    276   Out->refid=InA->refid;
    277   Out->insid=InB->insid;
    278 
    279   return TRUE;
    280 }
    281 
    282 /*
    283 * ===================================================================
    284 #fn vp_copy_motion
    285 #ft Copies the source motion to the destination motion.
    286 #fd DEFINITION
    287     void
    288     vp_copy_motion  (const VP_MOTION *src, VP_MOTION *dst)
    289 #fd PURPOSE
    290     Copies the source motion to the destination motion.
    291         It is OK if src == dst.
    292     NOTE THAT THE SOURCE IS THE FIRST ARGUMENT.
    293     This is different from some of the other VP
    294     copy functions.
    295 #fd INPUTS
    296     src is the source motion
    297     dst is the destination motion
    298 #fd RETURNS
    299     void
    300 #endfn
    301 */
    302 void vp_copy_motion  (const VP_MOTION *src, VP_MOTION *dst)
    303 {
    304   /* Use memmove rather than memcpy because it handles overlapping memory
    305      OK. */
    306   memmove(dst, src, sizeof(VP_MOTION));
    307   return;
    308 } /* vp_copy_motion() */
    309 
    310 #define VP_SQR(x)   ( (x)*(x) )
    311 double vp_motion_cornerdiff(const VP_MOTION *mot_a, const VP_MOTION *mot_b,
    312                      int xo, int yo, int w, int h)
    313 {
    314   double ax1, ay1, ax2, ay2, ax3, ay3, ax4, ay4;
    315   double bx1, by1, bx2, by2, bx3, by3, bx4, by4;
    316   double err;
    317 
    318   /*lint -e639 -e632 -e633 */
    319   VP_WARP_POINT_2D(xo, yo,         *mot_a, ax1, ay1);
    320   VP_WARP_POINT_2D(xo+w-1, yo,     *mot_a, ax2, ay2);
    321   VP_WARP_POINT_2D(xo+w-1, yo+h-1, *mot_a, ax3, ay3);
    322   VP_WARP_POINT_2D(xo, yo+h-1,     *mot_a, ax4, ay4);
    323   VP_WARP_POINT_2D(xo, yo,         *mot_b, bx1, by1);
    324   VP_WARP_POINT_2D(xo+w-1, yo,     *mot_b, bx2, by2);
    325   VP_WARP_POINT_2D(xo+w-1, yo+h-1, *mot_b, bx3, by3);
    326   VP_WARP_POINT_2D(xo, yo+h-1,     *mot_b, bx4, by4);
    327   /*lint +e639 +e632 +e633 */
    328 
    329   err = 0;
    330   err += (VP_SQR(ax1 - bx1) + VP_SQR(ay1 - by1));
    331   err += (VP_SQR(ax2 - bx2) + VP_SQR(ay2 - by2));
    332   err += (VP_SQR(ax3 - bx3) + VP_SQR(ay3 - by3));
    333   err += (VP_SQR(ax4 - bx4) + VP_SQR(ay4 - by4));
    334 
    335   return(sqrt(err));
    336 }
    337 
    338 int vp_zoom_motion2d(VP_MOTION* in, VP_MOTION* out,
    339                  int n, int w, int h, double zoom)
    340 {
    341   int ii;
    342   VP_PAR inv_zoom;
    343   VP_PAR cx, cy;
    344   VP_MOTION R2r,R2f;
    345   VP_MOTION *res;
    346 
    347   /* check for non-empty structures structure */
    348   if (((VP_MOTION *) NULL == in)||(zoom <= 0.0)||(w <= 0)||(h <= 0)) {
    349     return FALSE;
    350   }
    351 
    352   /* ==> Not sure why the special case of out=NULL is necessary.  Why couldn't
    353      the caller just pass the same pointer for both in and out? */
    354   res = ((VP_MOTION *) NULL == out)?in:out;
    355 
    356   cx = (VP_PAR) (w/2.0);
    357   cy = (VP_PAR) (h/2.0);
    358 
    359   VP_MOTION_ID(R2r);
    360   inv_zoom = (VP_PAR)(1.0/zoom);
    361   MXX(R2r) = inv_zoom;
    362   MYY(R2r) = inv_zoom;
    363   MXW(R2r)=cx*(((VP_PAR)1.0) - inv_zoom);
    364   MYW(R2r)=cy*(((VP_PAR)1.0) - inv_zoom);
    365 
    366   VP_KEEP_AFFINE_2D(R2r);
    367 
    368   for(ii=0;ii<n;ii++) {
    369     (void) vp_cascade_motion(&R2r,in+ii,&R2f);
    370     res[ii]=R2f;
    371   }
    372 
    373   return TRUE;
    374 } /* vp_zoom_motion2d() */
    375 
    376 /* =================================================================== */
    377 /* end vp_motionmodel.c */
    378