www.pudn.com > OpenCV-Intel.zip > cvposit.cpp


/*M/////////////////////////////////////////////////////////////////////////////////////// 
// 
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 
// 
//  By downloading, copying, installing or using the software you agree to this license. 
//  If you do not agree to this license, do not download, install, 
//  copy or use the software. 
// 
// 
//                        Intel License Agreement 
//                For Open Source Computer Vision Library 
// 
// Copyright (C) 2000, Intel Corporation, all rights reserved. 
// Third party copyrights are property of their respective owners. 
// 
// Redistribution and use in source and binary forms, with or without modification, 
// are permitted provided that the following conditions are met: 
// 
//   * Redistribution's of source code must retain the above copyright notice, 
//     this list of conditions and the following disclaimer. 
// 
//   * Redistribution's in binary form must reproduce the above copyright notice, 
//     this list of conditions and the following disclaimer in the documentation 
//     and/or other materials provided with the distribution. 
// 
//   * The name of Intel Corporation may not be used to endorse or promote products 
//     derived from this software without specific prior written permission. 
// 
// This software is provided by the copyright holders and contributors "as is" and 
// any express or implied warranties, including, but not limited to, the implied 
// warranties of merchantability and fitness for a particular purpose are disclaimed. 
// In no event shall the Intel Corporation or contributors be liable for any direct, 
// indirect, incidental, special, exemplary, or consequential damages 
// (including, but not limited to, procurement of substitute goods or services; 
// loss of use, data, or profits; or business interruption) however caused 
// and on any theory of liability, whether in contract, strict liability, 
// or tort (including negligence or otherwise) arising in any way out of 
// the use of this software, even if advised of the possibility of such damage. 
// 
//M*/ 
#include "_cv.h" 
 
/* POSIT structure */ 
struct CvPOSITObject 
{ 
    int N; 
    float* inv_matr; 
    float* obj_vecs; 
    float* img_vecs; 
}; 
 
static void icvPseudoInverse3D( float *a, float *b, int n, int method ); 
 
static  CvStatus  icvCreatePOSITObject( CvPoint3D32f *points, 
                                        int numPoints, 
                                        CvPOSITObject **ppObject ) 
{ 
    int i; 
 
    /* Compute size of required memory */ 
    /* buffer for inverse matrix = N*3*float */ 
    /* buffer for storing weakImagePoints = numPoints * 2 * float */ 
    /* buffer for storing object vectors = N*3*float */ 
    /* buffer for storing image vectors = N*2*float */ 
 
    int N = numPoints - 1; 
    int inv_matr_size = N * 3 * sizeof( float ); 
    int obj_vec_size = inv_matr_size; 
    int img_vec_size = N * 2 * sizeof( float ); 
    CvPOSITObject *pObject; 
 
    /* check bad arguments */ 
    if( points == NULL ) 
        return CV_NULLPTR_ERR; 
    if( numPoints < 4 ) 
        return CV_BADSIZE_ERR; 
    if( ppObject == NULL ) 
        return CV_NULLPTR_ERR; 
 
    /* memory allocation */ 
    pObject = (CvPOSITObject *) cvAlloc( sizeof( CvPOSITObject ) + 
                                         inv_matr_size + obj_vec_size + img_vec_size ); 
 
    if( !pObject ) 
        return CV_OUTOFMEM_ERR; 
 
    /* part the memory between all structures */ 
    pObject->N = N; 
    pObject->inv_matr = (float *) ((char *) pObject + sizeof( CvPOSITObject )); 
    pObject->obj_vecs = (float *) ((char *) (pObject->inv_matr) + inv_matr_size); 
    pObject->img_vecs = (float *) ((char *) (pObject->obj_vecs) + obj_vec_size); 
 
/****************************************************************************************\ 
*          Construct object vectors from object points                                   * 
\****************************************************************************************/ 
    for( i = 0; i < numPoints - 1; i++ ) 
    { 
        pObject->obj_vecs[i] = points[i + 1].x - points[0].x; 
        pObject->obj_vecs[N + i] = points[i + 1].y - points[0].y; 
        pObject->obj_vecs[2 * N + i] = points[i + 1].z - points[0].z; 
    } 
/****************************************************************************************\ 
*   Compute pseudoinverse matrix                                                         * 
\****************************************************************************************/ 
    icvPseudoInverse3D( pObject->obj_vecs, pObject->inv_matr, N, 0 ); 
 
    *ppObject = pObject; 
    return CV_NO_ERR; 
} 
 
 
static  CvStatus  icvPOSIT( CvPOSITObject *pObject, CvPoint2D32f *imagePoints, 
                            float focalLength, CvTermCriteria criteria, 
                            CvMatr32f rotation, CvVect32f translation ) 
{ 
    int i, j, k; 
    int count = 0, converged = 0; 
    float inorm, jnorm, invInorm, invJnorm, invScale, scale = 0, inv_Z = 0; 
    float diff = (float)criteria.epsilon; 
    float inv_focalLength = 1 / focalLength; 
 
    /* init variables */ 
    int N = pObject->N; 
    float *objectVectors = pObject->obj_vecs; 
    float *invMatrix = pObject->inv_matr; 
    float *imgVectors = pObject->img_vecs; 
 
    /* Check bad arguments */ 
    if( imagePoints == NULL ) 
        return CV_NULLPTR_ERR; 
    if( pObject == NULL ) 
        return CV_NULLPTR_ERR; 
    if( focalLength <= 0 ) 
        return CV_BADFACTOR_ERR; 
    if( !rotation ) 
        return CV_NULLPTR_ERR; 
    if( !translation ) 
        return CV_NULLPTR_ERR; 
    if( (criteria.type == 0) || (criteria.type > (CV_TERMCRIT_ITER | CV_TERMCRIT_EPS))) 
        return CV_BADFLAG_ERR; 
    if( (criteria.type & CV_TERMCRIT_EPS) && criteria.epsilon < 0 ) 
        return CV_BADFACTOR_ERR; 
    if( (criteria.type & CV_TERMCRIT_ITER) && criteria.max_iter <= 0 ) 
        return CV_BADFACTOR_ERR; 
 
    while( !converged ) 
    { 
        if( count == 0 ) 
        { 
            /* subtract out origin to get image vectors */ 
            for( i = 0; i < N; i++ ) 
            { 
                imgVectors[i] = imagePoints[i + 1].x - imagePoints[0].x; 
                imgVectors[N + i] = imagePoints[i + 1].y - imagePoints[0].y; 
            } 
        } 
        else 
        { 
            diff = 0; 
            /* Compute new SOP (scaled orthograthic projection) image from pose */ 
            for( i = 0; i < N; i++ ) 
            { 
                /* objectVector * k */ 
                float old; 
                float tmp = objectVectors[i] * rotation[6] /*[2][0]*/ + 
                    objectVectors[N + i] * rotation[7]     /*[2][1]*/ + 
                    objectVectors[2 * N + i] * rotation[8] /*[2][2]*/; 
 
                tmp *= inv_Z; 
                tmp += 1; 
 
                old = imgVectors[i]; 
                imgVectors[i] = imagePoints[i + 1].x * tmp - imagePoints[0].x; 
 
                diff = MAX( diff, (float) fabs( imgVectors[i] - old )); 
 
                old = imgVectors[N + i]; 
                imgVectors[N + i] = imagePoints[i + 1].y * tmp - imagePoints[0].y; 
 
                diff = MAX( diff, (float) fabs( imgVectors[N + i] - old )); 
            } 
        } 
 
        /* calculate I and J vectors */ 
        for( i = 0; i < 2; i++ ) 
        { 
            for( j = 0; j < 3; j++ ) 
            { 
                rotation[3*i+j] /*[i][j]*/ = 0; 
                for( k = 0; k < N; k++ ) 
                { 
                    rotation[3*i+j] /*[i][j]*/ += invMatrix[j * N + k] * imgVectors[i * N + k]; 
                } 
            } 
        } 
 
        inorm = rotation[0] /*[0][0]*/ * rotation[0] /*[0][0]*/ + 
                rotation[1] /*[0][1]*/ * rotation[1] /*[0][1]*/ +  
                rotation[2] /*[0][2]*/ * rotation[2] /*[0][2]*/; 
 
        jnorm = rotation[3] /*[1][0]*/ * rotation[3] /*[1][0]*/ + 
                rotation[4] /*[1][1]*/ * rotation[4] /*[1][1]*/ +  
                rotation[5] /*[1][2]*/ * rotation[5] /*[1][2]*/; 
 
        invInorm = cvInvSqrt( inorm ); 
        invJnorm = cvInvSqrt( jnorm ); 
 
        inorm *= invInorm; 
        jnorm *= invJnorm; 
 
        rotation[0] /*[0][0]*/ *= invInorm; 
        rotation[1] /*[0][1]*/ *= invInorm; 
        rotation[2] /*[0][2]*/ *= invInorm; 
 
        rotation[3] /*[1][0]*/ *= invJnorm; 
        rotation[4] /*[1][1]*/ *= invJnorm; 
        rotation[5] /*[1][2]*/ *= invJnorm; 
 
        /* row2 = row0 x row1 (cross product) */ 
        rotation[6] /*->m[2][0]*/ = rotation[1] /*->m[0][1]*/ * rotation[5] /*->m[1][2]*/ - 
                                    rotation[2] /*->m[0][2]*/ * rotation[4] /*->m[1][1]*/; 
         
        rotation[7] /*->m[2][1]*/ = rotation[2] /*->m[0][2]*/ * rotation[3] /*->m[1][0]*/ - 
                                    rotation[0] /*->m[0][0]*/ * rotation[5] /*->m[1][2]*/; 
         
        rotation[8] /*->m[2][2]*/ = rotation[0] /*->m[0][0]*/ * rotation[4] /*->m[1][1]*/ - 
                                    rotation[1] /*->m[0][1]*/ * rotation[3] /*->m[1][0]*/; 
 
        scale = (inorm + jnorm) / 2.0f; 
        inv_Z = scale * inv_focalLength; 
 
        count++; 
        converged = ((criteria.type & CV_TERMCRIT_EPS) && (diff < criteria.epsilon)); 
        converged |= ((criteria.type & CV_TERMCRIT_ITER) && (count == criteria.max_iter)); 
    } 
    invScale = 1 / scale; 
    translation[0] = imagePoints[0].x * invScale; 
    translation[1] = imagePoints[0].y * invScale; 
    translation[2] = 1 / inv_Z; 
 
    return CV_NO_ERR; 
} 
 
 
static  CvStatus  icvReleasePOSITObject( CvPOSITObject ** ppObject ) 
{ 
    cvFree( (void**)ppObject ); 
    return CV_NO_ERR; 
} 
 
/*F/////////////////////////////////////////////////////////////////////////////////////// 
//    Name:       icvPseudoInverse3D      
//    Purpose:    Pseudoinverse N x 3 matrix     N >= 3 
//    Context:    
//    Parameters: 
//                a - input matrix 
//                b - pseudoinversed a 
//                n - number of rows in a 
//                method - if 0, then b = inv(transpose(a)*a) * transpose(a) 
//                         if 1, then SVD used. 
//    Returns:    
//    Notes:      Both matrix are stored by n-dimensional vectors. 
//                Now only method == 0 supported. 
//F*/ 
void 
icvPseudoInverse3D( float *a, float *b, int n, int method ) 
{ 
    int k; 
 
    if( method == 0 ) 
    { 
        float ata00 = 0; 
        float ata11 = 0; 
        float ata22 = 0; 
        float ata01 = 0; 
        float ata02 = 0; 
        float ata12 = 0; 
        float det = 0; 
 
        /* compute matrix ata = transpose(a) * a  */ 
        for( k = 0; k < n; k++ ) 
        { 
            float a0 = a[k]; 
            float a1 = a[n + k]; 
            float a2 = a[2 * n + k]; 
 
            ata00 += a0 * a0; 
            ata11 += a1 * a1; 
            ata22 += a2 * a2; 
 
            ata01 += a0 * a1; 
            ata02 += a0 * a2; 
            ata12 += a1 * a2; 
        } 
        /* inverse matrix ata */ 
        { 
            float inv_det; 
            float p00 = ata11 * ata22 - ata12 * ata12; 
            float p01 = -(ata01 * ata22 - ata12 * ata02); 
            float p02 = ata12 * ata01 - ata11 * ata02; 
 
            float p11 = ata00 * ata22 - ata02 * ata02; 
            float p12 = -(ata00 * ata12 - ata01 * ata02); 
            float p22 = ata00 * ata11 - ata01 * ata01; 
 
            det += ata00 * p00; 
            det += ata01 * p01; 
            det += ata02 * p02; 
 
            inv_det = 1 / det; 
 
            /* compute resultant matrix */ 
            for( k = 0; k < n; k++ ) 
            { 
                float a0 = a[k]; 
                float a1 = a[n + k]; 
                float a2 = a[2 * n + k]; 
 
                b[k] = (p00 * a0 + p01 * a1 + p02 * a2) * inv_det; 
                b[n + k] = (p01 * a0 + p11 * a1 + p12 * a2) * inv_det; 
                b[2 * n + k] = (p02 * a0 + p12 * a1 + p22 * a2) * inv_det; 
            } 
        } 
    } 
 
    /*if ( method == 1 ) 
       { 
       } 
     */ 
 
    return; 
} 
 
CV_IMPL CvPOSITObject * 
cvCreatePOSITObject( CvPoint3D32f * points, int numPoints ) 
{ 
    CvPOSITObject *pObject = 0; 
 
    CV_FUNCNAME( "cvCreatePOSITObject" ); 
 
    __BEGIN__; 
 
    IPPI_CALL( icvCreatePOSITObject( points, numPoints, &pObject )); 
 
    __END__; 
 
    return pObject; 
} 
 
 
CV_IMPL void 
cvPOSIT( CvPOSITObject * pObject, CvPoint2D32f * imagePoints, 
         double focalLength, CvTermCriteria criteria, 
         CvMatr32f rotation, CvVect32f translation ) 
{ 
    CV_FUNCNAME( "cvPOSIT" ); 
 
    __BEGIN__; 
 
    IPPI_CALL( icvPOSIT( pObject, imagePoints,(float) focalLength, criteria, 
                         rotation, translation )); 
 
    __END__; 
} 
 
CV_IMPL void 
cvReleasePOSITObject( CvPOSITObject ** ppObject ) 
{ 
    CV_FUNCNAME( "cvReleasePOSITObject" ); 
 
    __BEGIN__; 
 
    IPPI_CALL( icvReleasePOSITObject( ppObject )); 
 
    __END__; 
} 
 
/* End of file. */