Home | History | Annotate | Download | only in src
      1 /*M///////////////////////////////////////////////////////////////////////////////////////
      2 //
      3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
      4 //
      5 //  By downloading, copying, installing or using the software you agree to this license.
      6 //  If you do not agree to this license, do not download, install,
      7 //  copy or use the software.
      8 //
      9 //
     10 //                        Intel License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
     14 // Third party copyrights are property of their respective owners.
     15 //
     16 // Redistribution and use in source and binary forms, with or without modification,
     17 // are permitted provided that the following conditions are met:
     18 //
     19 //   * Redistribution's of source code must retain the above copyright notice,
     20 //     this list of conditions and the following disclaimer.
     21 //
     22 //   * Redistribution's in binary form must reproduce the above copyright notice,
     23 //     this list of conditions and the following disclaimer in the documentation
     24 //     and/or other materials provided with the distribution.
     25 //
     26 //   * The name of Intel Corporation may not be used to endorse or promote products
     27 //     derived from this software without specific prior written permission.
     28 //
     29 // This software is provided by the copyright holders and contributors "as is" and
     30 // any express or implied warranties, including, but not limited to, the implied
     31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     32 // In no event shall the Intel Corporation or contributors be liable for any direct,
     33 // indirect, incidental, special, exemplary, or consequential damages
     34 // (including, but not limited to, procurement of substitute goods or services;
     35 // loss of use, data, or profits; or business interruption) however caused
     36 // and on any theory of liability, whether in contract, strict liability,
     37 // or tort (including negligence or otherwise) arising in any way out of
     38 // the use of this software, even if advised of the possibility of such damage.
     39 //
     40 //M*/
     41 #include "_cv.h"
     42 
     43 static const double eps = 1e-6;
     44 
     45 static CvStatus
     46 icvFitLine2D_wods( CvPoint2D32f * points, int _count, float *weights, float *line )
     47 {
     48     double x = 0, y = 0, x2 = 0, y2 = 0, xy = 0, w = 0;
     49     double dx2, dy2, dxy;
     50     int i;
     51     int count = _count;
     52     float t;
     53 
     54     /* Calculating the average of x and y... */
     55 
     56     if( weights == 0 )
     57     {
     58         for( i = 0; i < count; i += 1 )
     59         {
     60             x += points[i].x;
     61             y += points[i].y;
     62             x2 += points[i].x * points[i].x;
     63             y2 += points[i].y * points[i].y;
     64             xy += points[i].x * points[i].y;
     65         }
     66         w = (float) count;
     67     }
     68     else
     69     {
     70         for( i = 0; i < count; i += 1 )
     71         {
     72             x += weights[i] * points[i].x;
     73             y += weights[i] * points[i].y;
     74             x2 += weights[i] * points[i].x * points[i].x;
     75             y2 += weights[i] * points[i].y * points[i].y;
     76             xy += weights[i] * points[i].x * points[i].y;
     77             w += weights[i];
     78         }
     79     }
     80 
     81     x /= w;
     82     y /= w;
     83     x2 /= w;
     84     y2 /= w;
     85     xy /= w;
     86 
     87     dx2 = x2 - x * x;
     88     dy2 = y2 - y * y;
     89     dxy = xy - x * y;
     90 
     91     t = (float) atan2( 2 * dxy, dx2 - dy2 ) / 2;
     92     line[0] = (float) cos( t );
     93     line[1] = (float) sin( t );
     94 
     95     line[2] = (float) x;
     96     line[3] = (float) y;
     97 
     98     return CV_NO_ERR;
     99 }
    100 
    101 static CvStatus
    102 icvFitLine3D_wods( CvPoint3D32f * points, int count, float *weights, float *line )
    103 {
    104     int i;
    105     float w0 = 0;
    106     float x0 = 0, y0 = 0, z0 = 0;
    107     float x2 = 0, y2 = 0, z2 = 0, xy = 0, yz = 0, xz = 0;
    108     float dx2, dy2, dz2, dxy, dxz, dyz;
    109     float *v;
    110     float n;
    111     float det[9], evc[9], evl[3];
    112 
    113     memset( evl, 0, 3*sizeof(evl[0]));
    114     memset( evc, 0, 9*sizeof(evl[0]));
    115 
    116     if( weights )
    117     {
    118         for( i = 0; i < count; i++ )
    119         {
    120             float x = points[i].x;
    121             float y = points[i].y;
    122             float z = points[i].z;
    123             float w = weights[i];
    124 
    125 
    126             x2 += x * x * w;
    127             xy += x * y * w;
    128             xz += x * z * w;
    129             y2 += y * y * w;
    130             yz += y * z * w;
    131             z2 += z * z * w;
    132             x0 += x * w;
    133             y0 += y * w;
    134             z0 += z * w;
    135             w0 += w;
    136         }
    137     }
    138     else
    139     {
    140         for( i = 0; i < count; i++ )
    141         {
    142             float x = points[i].x;
    143             float y = points[i].y;
    144             float z = points[i].z;
    145 
    146             x2 += x * x;
    147             xy += x * y;
    148             xz += x * z;
    149             y2 += y * y;
    150             yz += y * z;
    151             z2 += z * z;
    152             x0 += x;
    153             y0 += y;
    154             z0 += z;
    155         }
    156         w0 = (float) count;
    157     }
    158 
    159     x2 /= w0;
    160     xy /= w0;
    161     xz /= w0;
    162     y2 /= w0;
    163     yz /= w0;
    164     z2 /= w0;
    165 
    166     x0 /= w0;
    167     y0 /= w0;
    168     z0 /= w0;
    169 
    170     dx2 = x2 - x0 * x0;
    171     dxy = xy - x0 * y0;
    172     dxz = xz - x0 * z0;
    173     dy2 = y2 - y0 * y0;
    174     dyz = yz - y0 * z0;
    175     dz2 = z2 - z0 * z0;
    176 
    177     det[0] = dz2 + dy2;
    178     det[1] = -dxy;
    179     det[2] = -dxz;
    180     det[3] = det[1];
    181     det[4] = dx2 + dz2;
    182     det[5] = -dyz;
    183     det[6] = det[2];
    184     det[7] = det[5];
    185     det[8] = dy2 + dx2;
    186 
    187     /* Searching for a eigenvector of det corresponding to the minimal eigenvalue */
    188 #if 1
    189     {
    190     CvMat _det = cvMat( 3, 3, CV_32F, det );
    191     CvMat _evc = cvMat( 3, 3, CV_32F, evc );
    192     CvMat _evl = cvMat( 3, 1, CV_32F, evl );
    193     cvEigenVV( &_det, &_evc, &_evl, 0 );
    194     i = evl[0] < evl[1] ? (evl[0] < evl[2] ? 0 : 2) : (evl[1] < evl[2] ? 1 : 2);
    195     }
    196 #else
    197     {
    198         CvMat _det = cvMat( 3, 3, CV_32F, det );
    199         CvMat _evc = cvMat( 3, 3, CV_32F, evc );
    200         CvMat _evl = cvMat( 1, 3, CV_32F, evl );
    201 
    202         cvSVD( &_det, &_evl, &_evc, 0, CV_SVD_MODIFY_A+CV_SVD_U_T );
    203     }
    204     i = 2;
    205 #endif
    206     v = &evc[i * 3];
    207     n = (float) sqrt( (double)v[0] * v[0] + (double)v[1] * v[1] + (double)v[2] * v[2] );
    208     n = (float)MAX(n, eps);
    209     line[0] = v[0] / n;
    210     line[1] = v[1] / n;
    211     line[2] = v[2] / n;
    212     line[3] = x0;
    213     line[4] = y0;
    214     line[5] = z0;
    215 
    216     return CV_NO_ERR;
    217 }
    218 
    219 static double
    220 icvCalcDist2D( CvPoint2D32f * points, int count, float *_line, float *dist )
    221 {
    222     int j;
    223     float px = _line[2], py = _line[3];
    224     float nx = _line[1], ny = -_line[0];
    225     double sum_dist = 0.;
    226 
    227     for( j = 0; j < count; j++ )
    228     {
    229         float x, y;
    230 
    231         x = points[j].x - px;
    232         y = points[j].y - py;
    233 
    234         dist[j] = (float) fabs( nx * x + ny * y );
    235         sum_dist += dist[j];
    236     }
    237 
    238     return sum_dist;
    239 }
    240 
    241 static double
    242 icvCalcDist3D( CvPoint3D32f * points, int count, float *_line, float *dist )
    243 {
    244     int j;
    245     float px = _line[3], py = _line[4], pz = _line[5];
    246     float vx = _line[0], vy = _line[1], vz = _line[2];
    247     double sum_dist = 0.;
    248 
    249     for( j = 0; j < count; j++ )
    250     {
    251         float x, y, z;
    252         double p1, p2, p3;
    253 
    254         x = points[j].x - px;
    255         y = points[j].y - py;
    256         z = points[j].z - pz;
    257 
    258         p1 = vy * z - vz * y;
    259         p2 = vz * x - vx * z;
    260         p3 = vx * y - vy * x;
    261 
    262         dist[j] = (float) sqrt( p1*p1 + p2*p2 + p3*p3 );
    263         sum_dist += dist[j];
    264     }
    265 
    266     return sum_dist;
    267 }
    268 
    269 static void
    270 icvWeightL1( float *d, int count, float *w )
    271 {
    272     int i;
    273 
    274     for( i = 0; i < count; i++ )
    275     {
    276         double t = fabs( (double) d[i] );
    277         w[i] = (float)(1. / MAX(t, eps));
    278     }
    279 }
    280 
    281 static void
    282 icvWeightL12( float *d, int count, float *w )
    283 {
    284     int i;
    285 
    286     for( i = 0; i < count; i++ )
    287     {
    288         w[i] = 1.0f / (float) sqrt( 1 + (double) (d[i] * d[i] * 0.5) );
    289     }
    290 }
    291 
    292 
    293 static void
    294 icvWeightHuber( float *d, int count, float *w, float _c )
    295 {
    296     int i;
    297     const float c = _c <= 0 ? 1.345f : _c;
    298 
    299     for( i = 0; i < count; i++ )
    300     {
    301         if( d[i] < c )
    302             w[i] = 1.0f;
    303         else
    304             w[i] = c/d[i];
    305     }
    306 }
    307 
    308 
    309 static void
    310 icvWeightFair( float *d, int count, float *w, float _c )
    311 {
    312     int i;
    313     const float c = _c == 0 ? 1 / 1.3998f : 1 / _c;
    314 
    315     for( i = 0; i < count; i++ )
    316     {
    317         w[i] = 1 / (1 + d[i] * c);
    318     }
    319 }
    320 
    321 static void
    322 icvWeightWelsch( float *d, int count, float *w, float _c )
    323 {
    324     int i;
    325     const float c = _c == 0 ? 1 / 2.9846f : 1 / _c;
    326 
    327     for( i = 0; i < count; i++ )
    328     {
    329         w[i] = (float) exp( -d[i] * d[i] * c * c );
    330     }
    331 }
    332 
    333 
    334 /* Takes an array of 2D points, type of distance (including user-defined
    335 distance specified by callbacks, fills the array of four floats with line
    336 parameters A, B, C, D, where (A, B) is the normalized direction vector,
    337 (C, D) is the point that belongs to the line. */
    338 
    339 static CvStatus  icvFitLine2D( CvPoint2D32f * points, int count, int dist,
    340                                float _param, float reps, float aeps, float *line )
    341 {
    342     double EPS = count*FLT_EPSILON;
    343     void (*calc_weights) (float *, int, float *) = 0;
    344     void (*calc_weights_param) (float *, int, float *, float) = 0;
    345     float *w;                   /* weights */
    346     float *r;                   /* square distances */
    347     int i, j, k;
    348     float _line[6], _lineprev[6];
    349     float rdelta = reps != 0 ? reps : 1.0f;
    350     float adelta = aeps != 0 ? aeps : 0.01f;
    351     double min_err = DBL_MAX, err = 0;
    352     CvRNG rng = cvRNG(-1);
    353 
    354     memset( line, 0, 4*sizeof(line[0]) );
    355 
    356     switch (dist)
    357     {
    358     case CV_DIST_L2:
    359         return icvFitLine2D_wods( points, count, 0, line );
    360 
    361     case CV_DIST_L1:
    362         calc_weights = icvWeightL1;
    363         break;
    364 
    365     case CV_DIST_L12:
    366         calc_weights = icvWeightL12;
    367         break;
    368 
    369     case CV_DIST_FAIR:
    370         calc_weights_param = icvWeightFair;
    371         break;
    372 
    373     case CV_DIST_WELSCH:
    374         calc_weights_param = icvWeightWelsch;
    375         break;
    376 
    377     case CV_DIST_HUBER:
    378         calc_weights_param = icvWeightHuber;
    379         break;
    380 
    381     /*case CV_DIST_USER:
    382         calc_weights = (void ( * )(float *, int, float *)) _PFP.fp;
    383         break;*/
    384 
    385     default:
    386         return CV_BADFACTOR_ERR;
    387     }
    388 
    389     w = (float *) cvAlloc( count * sizeof( float ));
    390     r = (float *) cvAlloc( count * sizeof( float ));
    391 
    392     for( k = 0; k < 20; k++ )
    393     {
    394         int first = 1;
    395         for( i = 0; i < count; i++ )
    396             w[i] = 0.f;
    397 
    398         for( i = 0; i < MIN(count,10); )
    399         {
    400             j = cvRandInt(&rng) % count;
    401             if( w[j] < FLT_EPSILON )
    402             {
    403                 w[j] = 1.f;
    404                 i++;
    405             }
    406         }
    407 
    408         icvFitLine2D_wods( points, count, w, _line );
    409         for( i = 0; i < 30; i++ )
    410         {
    411             double sum_w = 0;
    412 
    413             if( first )
    414             {
    415                 first = 0;
    416             }
    417             else
    418             {
    419                 double t = _line[0] * _lineprev[0] + _line[1] * _lineprev[1];
    420                 t = MAX(t,-1.);
    421                 t = MIN(t,1.);
    422                 if( fabs(acos(t)) < adelta )
    423                 {
    424                     float x, y, d;
    425 
    426                     x = (float) fabs( _line[2] - _lineprev[2] );
    427                     y = (float) fabs( _line[3] - _lineprev[3] );
    428 
    429                     d = x > y ? x : y;
    430                     if( d < rdelta )
    431                         break;
    432                 }
    433             }
    434             /* calculate distances */
    435             err = icvCalcDist2D( points, count, _line, r );
    436             if( err < EPS )
    437                 break;
    438 
    439             /* calculate weights */
    440             if( calc_weights )
    441                 calc_weights( r, count, w );
    442             else
    443                 calc_weights_param( r, count, w, _param );
    444 
    445             for( j = 0; j < count; j++ )
    446                 sum_w += w[j];
    447 
    448             if( fabs(sum_w) > FLT_EPSILON )
    449             {
    450                 sum_w = 1./sum_w;
    451                 for( j = 0; j < count; j++ )
    452                     w[j] = (float)(w[j]*sum_w);
    453             }
    454             else
    455             {
    456                 for( j = 0; j < count; j++ )
    457                     w[j] = 1.f;
    458             }
    459 
    460             /* save the line parameters */
    461             memcpy( _lineprev, _line, 4 * sizeof( float ));
    462 
    463             /* Run again... */
    464             icvFitLine2D_wods( points, count, w, _line );
    465         }
    466 
    467         if( err < min_err )
    468         {
    469             min_err = err;
    470             memcpy( line, _line, 4 * sizeof(line[0]));
    471             if( err < EPS )
    472                 break;
    473         }
    474     }
    475 
    476     cvFree( &w );
    477     cvFree( &r );
    478     return CV_OK;
    479 }
    480 
    481 
    482 /* Takes an array of 3D points, type of distance (including user-defined
    483 distance specified by callbacks, fills the array of four floats with line
    484 parameters A, B, C, D, E, F, where (A, B, C) is the normalized direction vector,
    485 (D, E, F) is the point that belongs to the line. */
    486 
    487 static CvStatus
    488 icvFitLine3D( CvPoint3D32f * points, int count, int dist,
    489               float _param, float reps, float aeps, float *line )
    490 {
    491     double EPS = count*FLT_EPSILON;
    492     void (*calc_weights) (float *, int, float *) = 0;
    493     void (*calc_weights_param) (float *, int, float *, float) = 0;
    494     float *w;                   /* weights */
    495     float *r;                   /* square distances */
    496     int i, j, k;
    497     float _line[6], _lineprev[6];
    498     float rdelta = reps != 0 ? reps : 1.0f;
    499     float adelta = aeps != 0 ? aeps : 0.01f;
    500     double min_err = DBL_MAX, err = 0;
    501     CvRNG rng = cvRNG(-1);
    502 
    503     memset( line, 0, 6*sizeof(line[0]) );
    504 
    505     switch (dist)
    506     {
    507     case CV_DIST_L2:
    508         return icvFitLine3D_wods( points, count, 0, line );
    509 
    510     case CV_DIST_L1:
    511         calc_weights = icvWeightL1;
    512         break;
    513 
    514     case CV_DIST_L12:
    515         calc_weights = icvWeightL12;
    516         break;
    517 
    518     case CV_DIST_FAIR:
    519         calc_weights_param = icvWeightFair;
    520         break;
    521 
    522     case CV_DIST_WELSCH:
    523         calc_weights_param = icvWeightWelsch;
    524         break;
    525 
    526     case CV_DIST_HUBER:
    527         calc_weights_param = icvWeightHuber;
    528         break;
    529 
    530     /*case CV_DIST_USER:
    531         _PFP.p = param;
    532         calc_weights = (void ( * )(float *, int, float *)) _PFP.fp;
    533         break;*/
    534 
    535     default:
    536         return CV_BADFACTOR_ERR;
    537     }
    538 
    539     w = (float *) cvAlloc( count * sizeof( float ));
    540     r = (float *) cvAlloc( count * sizeof( float ));
    541 
    542     for( k = 0; k < 20; k++ )
    543     {
    544         int first = 1;
    545         for( i = 0; i < count; i++ )
    546             w[i] = 0.f;
    547 
    548         for( i = 0; i < MIN(count,10); )
    549         {
    550             j = cvRandInt(&rng) % count;
    551             if( w[j] < FLT_EPSILON )
    552             {
    553                 w[j] = 1.f;
    554                 i++;
    555             }
    556         }
    557 
    558         icvFitLine3D_wods( points, count, w, _line );
    559         for( i = 0; i < 30; i++ )
    560         {
    561             double sum_w = 0;
    562 
    563             if( first )
    564             {
    565                 first = 0;
    566             }
    567             else
    568             {
    569                 double t = _line[0] * _lineprev[0] + _line[1] * _lineprev[1] + _line[2] * _lineprev[2];
    570                 t = MAX(t,-1.);
    571                 t = MIN(t,1.);
    572                 if( fabs(acos(t)) < adelta )
    573                 {
    574                     float x, y, z, ax, ay, az, dx, dy, dz, d;
    575 
    576                     x = _line[3] - _lineprev[3];
    577                     y = _line[4] - _lineprev[4];
    578                     z = _line[5] - _lineprev[5];
    579                     ax = _line[0] - _lineprev[0];
    580                     ay = _line[1] - _lineprev[1];
    581                     az = _line[2] - _lineprev[2];
    582                     dx = (float) fabs( y * az - z * ay );
    583                     dy = (float) fabs( z * ax - x * az );
    584                     dz = (float) fabs( x * ay - y * ax );
    585 
    586                     d = dx > dy ? (dx > dz ? dx : dz) : (dy > dz ? dy : dz);
    587                     if( d < rdelta )
    588                         break;
    589                 }
    590             }
    591             /* calculate distances */
    592             if( icvCalcDist3D( points, count, _line, r ) < FLT_EPSILON*count )
    593                 break;
    594 
    595             /* calculate weights */
    596             if( calc_weights )
    597                 calc_weights( r, count, w );
    598             else
    599                 calc_weights_param( r, count, w, _param );
    600 
    601             for( j = 0; j < count; j++ )
    602                 sum_w += w[j];
    603 
    604             if( fabs(sum_w) > FLT_EPSILON )
    605             {
    606                 sum_w = 1./sum_w;
    607                 for( j = 0; j < count; j++ )
    608                     w[j] = (float)(w[j]*sum_w);
    609             }
    610             else
    611             {
    612                 for( j = 0; j < count; j++ )
    613                     w[j] = 1.f;
    614             }
    615 
    616             /* save the line parameters */
    617             memcpy( _lineprev, _line, 6 * sizeof( float ));
    618 
    619             /* Run again... */
    620             icvFitLine3D_wods( points, count, w, _line );
    621         }
    622 
    623         if( err < min_err )
    624         {
    625             min_err = err;
    626             memcpy( line, _line, 6 * sizeof(line[0]));
    627             if( err < EPS )
    628                 break;
    629         }
    630     }
    631 
    632     // Return...
    633     cvFree( &w );
    634     cvFree( &r );
    635     return CV_OK;
    636 }
    637 
    638 
    639 CV_IMPL void
    640 cvFitLine( const CvArr* array, int dist, double param,
    641            double reps, double aeps, float *line )
    642 {
    643     schar* buffer = 0;
    644     CV_FUNCNAME( "cvFitLine" );
    645 
    646     __BEGIN__;
    647 
    648     schar* points = 0;
    649     union { CvContour contour; CvSeq seq; } header;
    650     CvSeqBlock block;
    651     CvSeq* ptseq = (CvSeq*)array;
    652     int type;
    653 
    654     if( !line )
    655         CV_ERROR( CV_StsNullPtr, "NULL pointer to line parameters" );
    656 
    657     if( CV_IS_SEQ(ptseq) )
    658     {
    659         type = CV_SEQ_ELTYPE(ptseq);
    660         if( ptseq->total == 0 )
    661             CV_ERROR( CV_StsBadSize, "The sequence has no points" );
    662         if( (type!=CV_32FC2 && type!=CV_32FC3 && type!=CV_32SC2 && type!=CV_32SC3) ||
    663             CV_ELEM_SIZE(type) != ptseq->elem_size )
    664             CV_ERROR( CV_StsUnsupportedFormat,
    665                 "Input sequence must consist of 2d points or 3d points" );
    666     }
    667     else
    668     {
    669         CvMat* mat = (CvMat*)array;
    670         type = CV_MAT_TYPE(mat->type);
    671         if( !CV_IS_MAT(mat))
    672             CV_ERROR( CV_StsBadArg, "Input array is not a sequence nor matrix" );
    673 
    674         if( !CV_IS_MAT_CONT(mat->type) ||
    675             (type!=CV_32FC2 && type!=CV_32FC3 && type!=CV_32SC2 && type!=CV_32SC3) ||
    676             (mat->width != 1 && mat->height != 1))
    677             CV_ERROR( CV_StsBadArg,
    678             "Input array must be 1d continuous array of 2d or 3d points" );
    679 
    680         CV_CALL( ptseq = cvMakeSeqHeaderForArray(
    681             CV_SEQ_KIND_GENERIC|type, sizeof(CvContour), CV_ELEM_SIZE(type), mat->data.ptr,
    682             mat->width + mat->height - 1, &header.seq, &block ));
    683     }
    684 
    685     if( reps < 0 || aeps < 0 )
    686         CV_ERROR( CV_StsOutOfRange, "Both reps and aeps must be non-negative" );
    687 
    688     if( CV_MAT_DEPTH(type) == CV_32F && ptseq->first->next == ptseq->first )
    689     {
    690         /* no need to copy data in this case */
    691         points = ptseq->first->data;
    692     }
    693     else
    694     {
    695         CV_CALL( buffer = points = (schar*)cvAlloc( ptseq->total*CV_ELEM_SIZE(type) ));
    696         CV_CALL( cvCvtSeqToArray( ptseq, points, CV_WHOLE_SEQ ));
    697 
    698         if( CV_MAT_DEPTH(type) != CV_32F )
    699         {
    700             int i, total = ptseq->total*CV_MAT_CN(type);
    701             assert( CV_MAT_DEPTH(type) == CV_32S );
    702 
    703             for( i = 0; i < total; i++ )
    704                 ((float*)points)[i] = (float)((int*)points)[i];
    705         }
    706     }
    707 
    708     if( dist == CV_DIST_USER )
    709         CV_ERROR( CV_StsBadArg, "User-defined distance is not allowed" );
    710 
    711     if( CV_MAT_CN(type) == 2 )
    712     {
    713         IPPI_CALL( icvFitLine2D( (CvPoint2D32f*)points, ptseq->total,
    714                                  dist, (float)param, (float)reps, (float)aeps, line ));
    715     }
    716     else
    717     {
    718         IPPI_CALL( icvFitLine3D( (CvPoint3D32f*)points, ptseq->total,
    719                                  dist, (float)param, (float)reps, (float)aeps, line ));
    720     }
    721 
    722     __END__;
    723 
    724     cvFree( &buffer );
    725 }
    726 
    727 /* End of file. */
    728