+++ /dev/null
-/*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"
-
-static const double eps = 1e-6;
-
-static CvStatus
-icvFitLine2D_wods( CvPoint2D32f * points, int _count, float *weights, float *line )
-{
- double x = 0, y = 0, x2 = 0, y2 = 0, xy = 0, w = 0;
- double dx2, dy2, dxy;
- int i;
- int count = _count;
- float t;
-
- /* Calculating the average of x and y... */
-
- if( weights == 0 )
- {
- for( i = 0; i < count; i += 1 )
- {
- x += points[i].x;
- y += points[i].y;
- x2 += points[i].x * points[i].x;
- y2 += points[i].y * points[i].y;
- xy += points[i].x * points[i].y;
- }
- w = (float) count;
- }
- else
- {
- for( i = 0; i < count; i += 1 )
- {
- x += weights[i] * points[i].x;
- y += weights[i] * points[i].y;
- x2 += weights[i] * points[i].x * points[i].x;
- y2 += weights[i] * points[i].y * points[i].y;
- xy += weights[i] * points[i].x * points[i].y;
- w += weights[i];
- }
- }
-
- x /= w;
- y /= w;
- x2 /= w;
- y2 /= w;
- xy /= w;
-
- dx2 = x2 - x * x;
- dy2 = y2 - y * y;
- dxy = xy - x * y;
-
- t = (float) atan2( 2 * dxy, dx2 - dy2 ) / 2;
- line[0] = (float) cos( t );
- line[1] = (float) sin( t );
-
- line[2] = (float) x;
- line[3] = (float) y;
-
- return CV_NO_ERR;
-}
-
-static CvStatus
-icvFitLine3D_wods( CvPoint3D32f * points, int count, float *weights, float *line )
-{
- int i;
- float w0 = 0;
- float x0 = 0, y0 = 0, z0 = 0;
- float x2 = 0, y2 = 0, z2 = 0, xy = 0, yz = 0, xz = 0;
- float dx2, dy2, dz2, dxy, dxz, dyz;
- float *v;
- float n;
- float det[9], evc[9], evl[3];
-
- memset( evl, 0, 3*sizeof(evl[0]));
- memset( evc, 0, 9*sizeof(evl[0]));
-
- if( weights )
- {
- for( i = 0; i < count; i++ )
- {
- float x = points[i].x;
- float y = points[i].y;
- float z = points[i].z;
- float w = weights[i];
-
-
- x2 += x * x * w;
- xy += x * y * w;
- xz += x * z * w;
- y2 += y * y * w;
- yz += y * z * w;
- z2 += z * z * w;
- x0 += x * w;
- y0 += y * w;
- z0 += z * w;
- w0 += w;
- }
- }
- else
- {
- for( i = 0; i < count; i++ )
- {
- float x = points[i].x;
- float y = points[i].y;
- float z = points[i].z;
-
- x2 += x * x;
- xy += x * y;
- xz += x * z;
- y2 += y * y;
- yz += y * z;
- z2 += z * z;
- x0 += x;
- y0 += y;
- z0 += z;
- }
- w0 = (float) count;
- }
-
- x2 /= w0;
- xy /= w0;
- xz /= w0;
- y2 /= w0;
- yz /= w0;
- z2 /= w0;
-
- x0 /= w0;
- y0 /= w0;
- z0 /= w0;
-
- dx2 = x2 - x0 * x0;
- dxy = xy - x0 * y0;
- dxz = xz - x0 * z0;
- dy2 = y2 - y0 * y0;
- dyz = yz - y0 * z0;
- dz2 = z2 - z0 * z0;
-
- det[0] = dz2 + dy2;
- det[1] = -dxy;
- det[2] = -dxz;
- det[3] = det[1];
- det[4] = dx2 + dz2;
- det[5] = -dyz;
- det[6] = det[2];
- det[7] = det[5];
- det[8] = dy2 + dx2;
-
- /* Searching for a eigenvector of det corresponding to the minimal eigenvalue */
-#if 1
- {
- CvMat _det = cvMat( 3, 3, CV_32F, det );
- CvMat _evc = cvMat( 3, 3, CV_32F, evc );
- CvMat _evl = cvMat( 3, 1, CV_32F, evl );
- cvEigenVV( &_det, &_evc, &_evl, 0 );
- i = evl[0] < evl[1] ? (evl[0] < evl[2] ? 0 : 2) : (evl[1] < evl[2] ? 1 : 2);
- }
-#else
- {
- CvMat _det = cvMat( 3, 3, CV_32F, det );
- CvMat _evc = cvMat( 3, 3, CV_32F, evc );
- CvMat _evl = cvMat( 1, 3, CV_32F, evl );
-
- cvSVD( &_det, &_evl, &_evc, 0, CV_SVD_MODIFY_A+CV_SVD_U_T );
- }
- i = 2;
-#endif
- v = &evc[i * 3];
- n = (float) sqrt( (double)v[0] * v[0] + (double)v[1] * v[1] + (double)v[2] * v[2] );
- n = (float)MAX(n, eps);
- line[0] = v[0] / n;
- line[1] = v[1] / n;
- line[2] = v[2] / n;
- line[3] = x0;
- line[4] = y0;
- line[5] = z0;
-
- return CV_NO_ERR;
-}
-
-static double
-icvCalcDist2D( CvPoint2D32f * points, int count, float *_line, float *dist )
-{
- int j;
- float px = _line[2], py = _line[3];
- float nx = _line[1], ny = -_line[0];
- double sum_dist = 0.;
-
- for( j = 0; j < count; j++ )
- {
- float x, y;
-
- x = points[j].x - px;
- y = points[j].y - py;
-
- dist[j] = (float) fabs( nx * x + ny * y );
- sum_dist += dist[j];
- }
-
- return sum_dist;
-}
-
-static double
-icvCalcDist3D( CvPoint3D32f * points, int count, float *_line, float *dist )
-{
- int j;
- float px = _line[3], py = _line[4], pz = _line[5];
- float vx = _line[0], vy = _line[1], vz = _line[2];
- double sum_dist = 0.;
-
- for( j = 0; j < count; j++ )
- {
- float x, y, z;
- double p1, p2, p3;
-
- x = points[j].x - px;
- y = points[j].y - py;
- z = points[j].z - pz;
-
- p1 = vy * z - vz * y;
- p2 = vz * x - vx * z;
- p3 = vx * y - vy * x;
-
- dist[j] = (float) sqrt( p1*p1 + p2*p2 + p3*p3 );
- sum_dist += dist[j];
- }
-
- return sum_dist;
-}
-
-static void
-icvWeightL1( float *d, int count, float *w )
-{
- int i;
-
- for( i = 0; i < count; i++ )
- {
- double t = fabs( (double) d[i] );
- w[i] = (float)(1. / MAX(t, eps));
- }
-}
-
-static void
-icvWeightL12( float *d, int count, float *w )
-{
- int i;
-
- for( i = 0; i < count; i++ )
- {
- w[i] = 1.0f / (float) sqrt( 1 + (double) (d[i] * d[i] * 0.5) );
- }
-}
-
-
-static void
-icvWeightHuber( float *d, int count, float *w, float _c )
-{
- int i;
- const float c = _c <= 0 ? 1.345f : _c;
-
- for( i = 0; i < count; i++ )
- {
- if( d[i] < c )
- w[i] = 1.0f;
- else
- w[i] = c/d[i];
- }
-}
-
-
-static void
-icvWeightFair( float *d, int count, float *w, float _c )
-{
- int i;
- const float c = _c == 0 ? 1 / 1.3998f : 1 / _c;
-
- for( i = 0; i < count; i++ )
- {
- w[i] = 1 / (1 + d[i] * c);
- }
-}
-
-static void
-icvWeightWelsch( float *d, int count, float *w, float _c )
-{
- int i;
- const float c = _c == 0 ? 1 / 2.9846f : 1 / _c;
-
- for( i = 0; i < count; i++ )
- {
- w[i] = (float) exp( -d[i] * d[i] * c * c );
- }
-}
-
-
-/* Takes an array of 2D points, type of distance (including user-defined
-distance specified by callbacks, fills the array of four floats with line
-parameters A, B, C, D, where (A, B) is the normalized direction vector,
-(C, D) is the point that belongs to the line. */
-
-static CvStatus icvFitLine2D( CvPoint2D32f * points, int count, int dist,
- float _param, float reps, float aeps, float *line )
-{
- double EPS = count*FLT_EPSILON;
- void (*calc_weights) (float *, int, float *) = 0;
- void (*calc_weights_param) (float *, int, float *, float) = 0;
- float *w; /* weights */
- float *r; /* square distances */
- int i, j, k;
- float _line[6], _lineprev[6];
- float rdelta = reps != 0 ? reps : 1.0f;
- float adelta = aeps != 0 ? aeps : 0.01f;
- double min_err = DBL_MAX, err = 0;
- CvRNG rng = cvRNG(-1);
-
- memset( line, 0, 4*sizeof(line[0]) );
-
- switch (dist)
- {
- case CV_DIST_L2:
- return icvFitLine2D_wods( points, count, 0, line );
-
- case CV_DIST_L1:
- calc_weights = icvWeightL1;
- break;
-
- case CV_DIST_L12:
- calc_weights = icvWeightL12;
- break;
-
- case CV_DIST_FAIR:
- calc_weights_param = icvWeightFair;
- break;
-
- case CV_DIST_WELSCH:
- calc_weights_param = icvWeightWelsch;
- break;
-
- case CV_DIST_HUBER:
- calc_weights_param = icvWeightHuber;
- break;
-
- /*case CV_DIST_USER:
- calc_weights = (void ( * )(float *, int, float *)) _PFP.fp;
- break;*/
-
- default:
- return CV_BADFACTOR_ERR;
- }
-
- w = (float *) cvAlloc( count * sizeof( float ));
- r = (float *) cvAlloc( count * sizeof( float ));
-
- for( k = 0; k < 20; k++ )
- {
- int first = 1;
- for( i = 0; i < count; i++ )
- w[i] = 0.f;
-
- for( i = 0; i < MIN(count,10); )
- {
- j = cvRandInt(&rng) % count;
- if( w[j] < FLT_EPSILON )
- {
- w[j] = 1.f;
- i++;
- }
- }
-
- icvFitLine2D_wods( points, count, w, _line );
- for( i = 0; i < 30; i++ )
- {
- double sum_w = 0;
-
- if( first )
- {
- first = 0;
- }
- else
- {
- double t = _line[0] * _lineprev[0] + _line[1] * _lineprev[1];
- t = MAX(t,-1.);
- t = MIN(t,1.);
- if( fabs(acos(t)) < adelta )
- {
- float x, y, d;
-
- x = (float) fabs( _line[2] - _lineprev[2] );
- y = (float) fabs( _line[3] - _lineprev[3] );
-
- d = x > y ? x : y;
- if( d < rdelta )
- break;
- }
- }
- /* calculate distances */
- err = icvCalcDist2D( points, count, _line, r );
- if( err < EPS )
- break;
-
- /* calculate weights */
- if( calc_weights )
- calc_weights( r, count, w );
- else
- calc_weights_param( r, count, w, _param );
-
- for( j = 0; j < count; j++ )
- sum_w += w[j];
-
- if( fabs(sum_w) > FLT_EPSILON )
- {
- sum_w = 1./sum_w;
- for( j = 0; j < count; j++ )
- w[j] = (float)(w[j]*sum_w);
- }
- else
- {
- for( j = 0; j < count; j++ )
- w[j] = 1.f;
- }
-
- /* save the line parameters */
- memcpy( _lineprev, _line, 4 * sizeof( float ));
-
- /* Run again... */
- icvFitLine2D_wods( points, count, w, _line );
- }
-
- if( err < min_err )
- {
- min_err = err;
- memcpy( line, _line, 4 * sizeof(line[0]));
- if( err < EPS )
- break;
- }
- }
-
- cvFree( &w );
- cvFree( &r );
- return CV_OK;
-}
-
-
-/* Takes an array of 3D points, type of distance (including user-defined
-distance specified by callbacks, fills the array of four floats with line
-parameters A, B, C, D, E, F, where (A, B, C) is the normalized direction vector,
-(D, E, F) is the point that belongs to the line. */
-
-static CvStatus
-icvFitLine3D( CvPoint3D32f * points, int count, int dist,
- float _param, float reps, float aeps, float *line )
-{
- double EPS = count*FLT_EPSILON;
- void (*calc_weights) (float *, int, float *) = 0;
- void (*calc_weights_param) (float *, int, float *, float) = 0;
- float *w; /* weights */
- float *r; /* square distances */
- int i, j, k;
- float _line[6], _lineprev[6];
- float rdelta = reps != 0 ? reps : 1.0f;
- float adelta = aeps != 0 ? aeps : 0.01f;
- double min_err = DBL_MAX, err = 0;
- CvRNG rng = cvRNG(-1);
-
- memset( line, 0, 6*sizeof(line[0]) );
-
- switch (dist)
- {
- case CV_DIST_L2:
- return icvFitLine3D_wods( points, count, 0, line );
-
- case CV_DIST_L1:
- calc_weights = icvWeightL1;
- break;
-
- case CV_DIST_L12:
- calc_weights = icvWeightL12;
- break;
-
- case CV_DIST_FAIR:
- calc_weights_param = icvWeightFair;
- break;
-
- case CV_DIST_WELSCH:
- calc_weights_param = icvWeightWelsch;
- break;
-
- case CV_DIST_HUBER:
- calc_weights_param = icvWeightHuber;
- break;
-
- /*case CV_DIST_USER:
- _PFP.p = param;
- calc_weights = (void ( * )(float *, int, float *)) _PFP.fp;
- break;*/
-
- default:
- return CV_BADFACTOR_ERR;
- }
-
- w = (float *) cvAlloc( count * sizeof( float ));
- r = (float *) cvAlloc( count * sizeof( float ));
-
- for( k = 0; k < 20; k++ )
- {
- int first = 1;
- for( i = 0; i < count; i++ )
- w[i] = 0.f;
-
- for( i = 0; i < MIN(count,10); )
- {
- j = cvRandInt(&rng) % count;
- if( w[j] < FLT_EPSILON )
- {
- w[j] = 1.f;
- i++;
- }
- }
-
- icvFitLine3D_wods( points, count, w, _line );
- for( i = 0; i < 30; i++ )
- {
- double sum_w = 0;
-
- if( first )
- {
- first = 0;
- }
- else
- {
- double t = _line[0] * _lineprev[0] + _line[1] * _lineprev[1] + _line[2] * _lineprev[2];
- t = MAX(t,-1.);
- t = MIN(t,1.);
- if( fabs(acos(t)) < adelta )
- {
- float x, y, z, ax, ay, az, dx, dy, dz, d;
-
- x = _line[3] - _lineprev[3];
- y = _line[4] - _lineprev[4];
- z = _line[5] - _lineprev[5];
- ax = _line[0] - _lineprev[0];
- ay = _line[1] - _lineprev[1];
- az = _line[2] - _lineprev[2];
- dx = (float) fabs( y * az - z * ay );
- dy = (float) fabs( z * ax - x * az );
- dz = (float) fabs( x * ay - y * ax );
-
- d = dx > dy ? (dx > dz ? dx : dz) : (dy > dz ? dy : dz);
- if( d < rdelta )
- break;
- }
- }
- /* calculate distances */
- if( icvCalcDist3D( points, count, _line, r ) < FLT_EPSILON*count )
- break;
-
- /* calculate weights */
- if( calc_weights )
- calc_weights( r, count, w );
- else
- calc_weights_param( r, count, w, _param );
-
- for( j = 0; j < count; j++ )
- sum_w += w[j];
-
- if( fabs(sum_w) > FLT_EPSILON )
- {
- sum_w = 1./sum_w;
- for( j = 0; j < count; j++ )
- w[j] = (float)(w[j]*sum_w);
- }
- else
- {
- for( j = 0; j < count; j++ )
- w[j] = 1.f;
- }
-
- /* save the line parameters */
- memcpy( _lineprev, _line, 6 * sizeof( float ));
-
- /* Run again... */
- icvFitLine3D_wods( points, count, w, _line );
- }
-
- if( err < min_err )
- {
- min_err = err;
- memcpy( line, _line, 6 * sizeof(line[0]));
- if( err < EPS )
- break;
- }
- }
-
- // Return...
- cvFree( &w );
- cvFree( &r );
- return CV_OK;
-}
-
-
-CV_IMPL void
-cvFitLine( const CvArr* array, int dist, double param,
- double reps, double aeps, float *line )
-{
- schar* buffer = 0;
- CV_FUNCNAME( "cvFitLine" );
-
- __BEGIN__;
-
- schar* points = 0;
- union { CvContour contour; CvSeq seq; } header;
- CvSeqBlock block;
- CvSeq* ptseq = (CvSeq*)array;
- int type;
-
- if( !line )
- CV_ERROR( CV_StsNullPtr, "NULL pointer to line parameters" );
-
- if( CV_IS_SEQ(ptseq) )
- {
- type = CV_SEQ_ELTYPE(ptseq);
- if( ptseq->total == 0 )
- CV_ERROR( CV_StsBadSize, "The sequence has no points" );
- if( (type!=CV_32FC2 && type!=CV_32FC3 && type!=CV_32SC2 && type!=CV_32SC3) ||
- CV_ELEM_SIZE(type) != ptseq->elem_size )
- CV_ERROR( CV_StsUnsupportedFormat,
- "Input sequence must consist of 2d points or 3d points" );
- }
- else
- {
- CvMat* mat = (CvMat*)array;
- type = CV_MAT_TYPE(mat->type);
- if( !CV_IS_MAT(mat))
- CV_ERROR( CV_StsBadArg, "Input array is not a sequence nor matrix" );
-
- if( !CV_IS_MAT_CONT(mat->type) ||
- (type!=CV_32FC2 && type!=CV_32FC3 && type!=CV_32SC2 && type!=CV_32SC3) ||
- (mat->width != 1 && mat->height != 1))
- CV_ERROR( CV_StsBadArg,
- "Input array must be 1d continuous array of 2d or 3d points" );
-
- CV_CALL( ptseq = cvMakeSeqHeaderForArray(
- CV_SEQ_KIND_GENERIC|type, sizeof(CvContour), CV_ELEM_SIZE(type), mat->data.ptr,
- mat->width + mat->height - 1, &header.seq, &block ));
- }
-
- if( reps < 0 || aeps < 0 )
- CV_ERROR( CV_StsOutOfRange, "Both reps and aeps must be non-negative" );
-
- if( CV_MAT_DEPTH(type) == CV_32F && ptseq->first->next == ptseq->first )
- {
- /* no need to copy data in this case */
- points = ptseq->first->data;
- }
- else
- {
- CV_CALL( buffer = points = (schar*)cvAlloc( ptseq->total*CV_ELEM_SIZE(type) ));
- CV_CALL( cvCvtSeqToArray( ptseq, points, CV_WHOLE_SEQ ));
-
- if( CV_MAT_DEPTH(type) != CV_32F )
- {
- int i, total = ptseq->total*CV_MAT_CN(type);
- assert( CV_MAT_DEPTH(type) == CV_32S );
-
- for( i = 0; i < total; i++ )
- ((float*)points)[i] = (float)((int*)points)[i];
- }
- }
-
- if( dist == CV_DIST_USER )
- CV_ERROR( CV_StsBadArg, "User-defined distance is not allowed" );
-
- if( CV_MAT_CN(type) == 2 )
- {
- IPPI_CALL( icvFitLine2D( (CvPoint2D32f*)points, ptseq->total,
- dist, (float)param, (float)reps, (float)aeps, line ));
- }
- else
- {
- IPPI_CALL( icvFitLine3D( (CvPoint3D32f*)points, ptseq->total,
- dist, (float)param, (float)reps, (float)aeps, line ));
- }
-
- __END__;
-
- cvFree( &buffer );
-}
-
-/* End of file. */