• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "precomp.hpp"
42 
43 namespace cv
44 {
45 
46 static const double eps = 1e-6;
47 
fitLine2D_wods(const Point2f * points,int count,float * weights,float * line)48 static void fitLine2D_wods( const Point2f* points, int count, float *weights, float *line )
49 {
50     double x = 0, y = 0, x2 = 0, y2 = 0, xy = 0, w = 0;
51     double dx2, dy2, dxy;
52     int i;
53     float t;
54 
55     // Calculating the average of x and y...
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 
fitLine3D_wods(const Point3f * points,int count,float * weights,float * line)99 static void fitLine3D_wods( const Point3f * points, int count, float *weights, float *line )
100 {
101     int i;
102     float w0 = 0;
103     float x0 = 0, y0 = 0, z0 = 0;
104     float x2 = 0, y2 = 0, z2 = 0, xy = 0, yz = 0, xz = 0;
105     float dx2, dy2, dz2, dxy, dxz, dyz;
106     float *v;
107     float n;
108     float det[9], evc[9], evl[3];
109 
110     memset( evl, 0, 3*sizeof(evl[0]));
111     memset( evc, 0, 9*sizeof(evl[0]));
112 
113     if( weights )
114     {
115         for( i = 0; i < count; i++ )
116         {
117             float x = points[i].x;
118             float y = points[i].y;
119             float z = points[i].z;
120             float w = weights[i];
121 
122 
123             x2 += x * x * w;
124             xy += x * y * w;
125             xz += x * z * w;
126             y2 += y * y * w;
127             yz += y * z * w;
128             z2 += z * z * w;
129             x0 += x * w;
130             y0 += y * w;
131             z0 += z * w;
132             w0 += w;
133         }
134     }
135     else
136     {
137         for( i = 0; i < count; i++ )
138         {
139             float x = points[i].x;
140             float y = points[i].y;
141             float z = points[i].z;
142 
143             x2 += x * x;
144             xy += x * y;
145             xz += x * z;
146             y2 += y * y;
147             yz += y * z;
148             z2 += z * z;
149             x0 += x;
150             y0 += y;
151             z0 += z;
152         }
153         w0 = (float) count;
154     }
155 
156     x2 /= w0;
157     xy /= w0;
158     xz /= w0;
159     y2 /= w0;
160     yz /= w0;
161     z2 /= w0;
162 
163     x0 /= w0;
164     y0 /= w0;
165     z0 /= w0;
166 
167     dx2 = x2 - x0 * x0;
168     dxy = xy - x0 * y0;
169     dxz = xz - x0 * z0;
170     dy2 = y2 - y0 * y0;
171     dyz = yz - y0 * z0;
172     dz2 = z2 - z0 * z0;
173 
174     det[0] = dz2 + dy2;
175     det[1] = -dxy;
176     det[2] = -dxz;
177     det[3] = det[1];
178     det[4] = dx2 + dz2;
179     det[5] = -dyz;
180     det[6] = det[2];
181     det[7] = det[5];
182     det[8] = dy2 + dx2;
183 
184     // Searching for a eigenvector of det corresponding to the minimal eigenvalue
185     Mat _det( 3, 3, CV_32F, det );
186     Mat _evc( 3, 3, CV_32F, evc );
187     Mat _evl( 3, 1, CV_32F, evl );
188     eigen( _det, _evl, _evc );
189     i = evl[0] < evl[1] ? (evl[0] < evl[2] ? 0 : 2) : (evl[1] < evl[2] ? 1 : 2);
190 
191     v = &evc[i * 3];
192     n = (float) std::sqrt( (double)v[0] * v[0] + (double)v[1] * v[1] + (double)v[2] * v[2] );
193     n = (float)MAX(n, eps);
194     line[0] = v[0] / n;
195     line[1] = v[1] / n;
196     line[2] = v[2] / n;
197     line[3] = x0;
198     line[4] = y0;
199     line[5] = z0;
200 }
201 
calcDist2D(const Point2f * points,int count,float * _line,float * dist)202 static double calcDist2D( const Point2f* points, int count, float *_line, float *dist )
203 {
204     int j;
205     float px = _line[2], py = _line[3];
206     float nx = _line[1], ny = -_line[0];
207     double sum_dist = 0.;
208 
209     for( j = 0; j < count; j++ )
210     {
211         float x, y;
212 
213         x = points[j].x - px;
214         y = points[j].y - py;
215 
216         dist[j] = (float) fabs( nx * x + ny * y );
217         sum_dist += dist[j];
218     }
219 
220     return sum_dist;
221 }
222 
calcDist3D(const Point3f * points,int count,float * _line,float * dist)223 static double calcDist3D( const Point3f* points, int count, float *_line, float *dist )
224 {
225     int j;
226     float px = _line[3], py = _line[4], pz = _line[5];
227     float vx = _line[0], vy = _line[1], vz = _line[2];
228     double sum_dist = 0.;
229 
230     for( j = 0; j < count; j++ )
231     {
232         float x, y, z;
233         double p1, p2, p3;
234 
235         x = points[j].x - px;
236         y = points[j].y - py;
237         z = points[j].z - pz;
238 
239         p1 = vy * z - vz * y;
240         p2 = vz * x - vx * z;
241         p3 = vx * y - vy * x;
242 
243         dist[j] = (float) std::sqrt( p1*p1 + p2*p2 + p3*p3 );
244         sum_dist += dist[j];
245     }
246 
247     return sum_dist;
248 }
249 
weightL1(float * d,int count,float * w)250 static void weightL1( float *d, int count, float *w )
251 {
252     int i;
253 
254     for( i = 0; i < count; i++ )
255     {
256         double t = fabs( (double) d[i] );
257         w[i] = (float)(1. / MAX(t, eps));
258     }
259 }
260 
weightL12(float * d,int count,float * w)261 static void weightL12( float *d, int count, float *w )
262 {
263     int i;
264 
265     for( i = 0; i < count; i++ )
266     {
267         w[i] = 1.0f / (float) std::sqrt( 1 + (double) (d[i] * d[i] * 0.5) );
268     }
269 }
270 
271 
weightHuber(float * d,int count,float * w,float _c)272 static void weightHuber( float *d, int count, float *w, float _c )
273 {
274     int i;
275     const float c = _c <= 0 ? 1.345f : _c;
276 
277     for( i = 0; i < count; i++ )
278     {
279         if( d[i] < c )
280             w[i] = 1.0f;
281         else
282             w[i] = c/d[i];
283     }
284 }
285 
286 
weightFair(float * d,int count,float * w,float _c)287 static void weightFair( float *d, int count, float *w, float _c )
288 {
289     int i;
290     const float c = _c == 0 ? 1 / 1.3998f : 1 / _c;
291 
292     for( i = 0; i < count; i++ )
293     {
294         w[i] = 1 / (1 + d[i] * c);
295     }
296 }
297 
weightWelsch(float * d,int count,float * w,float _c)298 static void weightWelsch( float *d, int count, float *w, float _c )
299 {
300     int i;
301     const float c = _c == 0 ? 1 / 2.9846f : 1 / _c;
302 
303     for( i = 0; i < count; i++ )
304     {
305         w[i] = (float) std::exp( -d[i] * d[i] * c * c );
306     }
307 }
308 
309 
310 /* Takes an array of 2D points, type of distance (including user-defined
311  distance specified by callbacks, fills the array of four floats with line
312  parameters A, B, C, D, where (A, B) is the normalized direction vector,
313  (C, D) is the point that belongs to the line. */
314 
fitLine2D(const Point2f * points,int count,int dist,float _param,float reps,float aeps,float * line)315 static void fitLine2D( const Point2f * points, int count, int dist,
316                       float _param, float reps, float aeps, float *line )
317 {
318     double EPS = count*FLT_EPSILON;
319     void (*calc_weights) (float *, int, float *) = 0;
320     void (*calc_weights_param) (float *, int, float *, float) = 0;
321     int i, j, k;
322     float _line[6], _lineprev[6];
323     float rdelta = reps != 0 ? reps : 1.0f;
324     float adelta = aeps != 0 ? aeps : 0.01f;
325     double min_err = DBL_MAX, err = 0;
326     RNG rng((uint64)-1);
327 
328     memset( line, 0, 4*sizeof(line[0]) );
329 
330     switch (dist)
331     {
332     case CV_DIST_L2:
333         return fitLine2D_wods( points, count, 0, line );
334 
335     case CV_DIST_L1:
336         calc_weights = weightL1;
337         break;
338 
339     case CV_DIST_L12:
340         calc_weights = weightL12;
341         break;
342 
343     case CV_DIST_FAIR:
344         calc_weights_param = weightFair;
345         break;
346 
347     case CV_DIST_WELSCH:
348         calc_weights_param = weightWelsch;
349         break;
350 
351     case CV_DIST_HUBER:
352         calc_weights_param = weightHuber;
353         break;
354 
355     /*case DIST_USER:
356      calc_weights = (void ( * )(float *, int, float *)) _PFP.fp;
357      break;*/
358     default:
359         CV_Error(CV_StsBadArg, "Unknown distance type");
360     }
361 
362     AutoBuffer<float> wr(count*2);
363     float *w = wr, *r = w + count;
364 
365     for( k = 0; k < 20; k++ )
366     {
367         int first = 1;
368         for( i = 0; i < count; i++ )
369             w[i] = 0.f;
370 
371         for( i = 0; i < MIN(count,10); )
372         {
373             j = rng.uniform(0, count);
374             if( w[j] < FLT_EPSILON )
375             {
376                 w[j] = 1.f;
377                 i++;
378             }
379         }
380 
381         fitLine2D_wods( points, count, w, _line );
382         for( i = 0; i < 30; i++ )
383         {
384             double sum_w = 0;
385 
386             if( first )
387             {
388                 first = 0;
389             }
390             else
391             {
392                 double t = _line[0] * _lineprev[0] + _line[1] * _lineprev[1];
393                 t = MAX(t,-1.);
394                 t = MIN(t,1.);
395                 if( fabs(acos(t)) < adelta )
396                 {
397                     float x, y, d;
398 
399                     x = (float) fabs( _line[2] - _lineprev[2] );
400                     y = (float) fabs( _line[3] - _lineprev[3] );
401 
402                     d = x > y ? x : y;
403                     if( d < rdelta )
404                         break;
405                 }
406             }
407             /* calculate distances */
408             err = calcDist2D( points, count, _line, r );
409             if( err < EPS )
410                 break;
411 
412             /* calculate weights */
413             if( calc_weights )
414                 calc_weights( r, count, w );
415             else
416                 calc_weights_param( r, count, w, _param );
417 
418             for( j = 0; j < count; j++ )
419                 sum_w += w[j];
420 
421             if( fabs(sum_w) > FLT_EPSILON )
422             {
423                 sum_w = 1./sum_w;
424                 for( j = 0; j < count; j++ )
425                     w[j] = (float)(w[j]*sum_w);
426             }
427             else
428             {
429                 for( j = 0; j < count; j++ )
430                     w[j] = 1.f;
431             }
432 
433             /* save the line parameters */
434             memcpy( _lineprev, _line, 4 * sizeof( float ));
435 
436             /* Run again... */
437             fitLine2D_wods( points, count, w, _line );
438         }
439 
440         if( err < min_err )
441         {
442             min_err = err;
443             memcpy( line, _line, 4 * sizeof(line[0]));
444             if( err < EPS )
445                 break;
446         }
447     }
448 }
449 
450 
451 /* Takes an array of 3D points, type of distance (including user-defined
452  distance specified by callbacks, fills the array of four floats with line
453  parameters A, B, C, D, E, F, where (A, B, C) is the normalized direction vector,
454  (D, E, F) is the point that belongs to the line. */
fitLine3D(Point3f * points,int count,int dist,float _param,float reps,float aeps,float * line)455 static void fitLine3D( Point3f * points, int count, int dist,
456                        float _param, float reps, float aeps, float *line )
457 {
458     double EPS = count*FLT_EPSILON;
459     void (*calc_weights) (float *, int, float *) = 0;
460     void (*calc_weights_param) (float *, int, float *, float) = 0;
461     int i, j, k;
462     float _line[6]={0,0,0,0,0,0}, _lineprev[6]={0,0,0,0,0,0};
463     float rdelta = reps != 0 ? reps : 1.0f;
464     float adelta = aeps != 0 ? aeps : 0.01f;
465     double min_err = DBL_MAX, err = 0;
466     RNG rng((uint64)-1);
467 
468     switch (dist)
469     {
470     case CV_DIST_L2:
471         return fitLine3D_wods( points, count, 0, line );
472 
473     case CV_DIST_L1:
474         calc_weights = weightL1;
475         break;
476 
477     case CV_DIST_L12:
478         calc_weights = weightL12;
479         break;
480 
481     case CV_DIST_FAIR:
482         calc_weights_param = weightFair;
483         break;
484 
485     case CV_DIST_WELSCH:
486         calc_weights_param = weightWelsch;
487         break;
488 
489     case CV_DIST_HUBER:
490         calc_weights_param = weightHuber;
491         break;
492 
493     default:
494         CV_Error(CV_StsBadArg, "Unknown distance");
495     }
496 
497     AutoBuffer<float> buf(count*2);
498     float *w = buf, *r = w + count;
499 
500     for( k = 0; k < 20; k++ )
501     {
502         int first = 1;
503         for( i = 0; i < count; i++ )
504             w[i] = 0.f;
505 
506         for( i = 0; i < MIN(count,10); )
507         {
508             j = rng.uniform(0, count);
509             if( w[j] < FLT_EPSILON )
510             {
511                 w[j] = 1.f;
512                 i++;
513             }
514         }
515 
516         fitLine3D_wods( points, count, w, _line );
517         for( i = 0; i < 30; i++ )
518         {
519             double sum_w = 0;
520 
521             if( first )
522             {
523                 first = 0;
524             }
525             else
526             {
527                 double t = _line[0] * _lineprev[0] + _line[1] * _lineprev[1] + _line[2] * _lineprev[2];
528                 t = MAX(t,-1.);
529                 t = MIN(t,1.);
530                 if( fabs(acos(t)) < adelta )
531                 {
532                     float x, y, z, ax, ay, az, dx, dy, dz, d;
533 
534                     x = _line[3] - _lineprev[3];
535                     y = _line[4] - _lineprev[4];
536                     z = _line[5] - _lineprev[5];
537                     ax = _line[0] - _lineprev[0];
538                     ay = _line[1] - _lineprev[1];
539                     az = _line[2] - _lineprev[2];
540                     dx = (float) fabs( y * az - z * ay );
541                     dy = (float) fabs( z * ax - x * az );
542                     dz = (float) fabs( x * ay - y * ax );
543 
544                     d = dx > dy ? (dx > dz ? dx : dz) : (dy > dz ? dy : dz);
545                     if( d < rdelta )
546                         break;
547                 }
548             }
549             /* calculate distances */
550             err = calcDist3D( points, count, _line, r );
551             //if( err < FLT_EPSILON*count )
552             //    break;
553 
554             /* calculate weights */
555             if( calc_weights )
556                 calc_weights( r, count, w );
557             else
558                 calc_weights_param( r, count, w, _param );
559 
560             for( j = 0; j < count; j++ )
561                 sum_w += w[j];
562 
563             if( fabs(sum_w) > FLT_EPSILON )
564             {
565                 sum_w = 1./sum_w;
566                 for( j = 0; j < count; j++ )
567                     w[j] = (float)(w[j]*sum_w);
568             }
569             else
570             {
571                 for( j = 0; j < count; j++ )
572                     w[j] = 1.f;
573             }
574 
575             /* save the line parameters */
576             memcpy( _lineprev, _line, 6 * sizeof( float ));
577 
578             /* Run again... */
579             fitLine3D_wods( points, count, w, _line );
580         }
581 
582         if( err < min_err )
583         {
584             min_err = err;
585             memcpy( line, _line, 6 * sizeof(line[0]));
586             if( err < EPS )
587                 break;
588         }
589     }
590 }
591 
592 }
593 
fitLine(InputArray _points,OutputArray _line,int distType,double param,double reps,double aeps)594 void cv::fitLine( InputArray _points, OutputArray _line, int distType,
595                  double param, double reps, double aeps )
596 {
597     Mat points = _points.getMat();
598 
599     float linebuf[6]={0.f};
600     int npoints2 = points.checkVector(2, -1, false);
601     int npoints3 = points.checkVector(3, -1, false);
602 
603     CV_Assert( npoints2 >= 0 || npoints3 >= 0 );
604 
605     if( points.depth() != CV_32F || !points.isContinuous() )
606     {
607         Mat temp;
608         points.convertTo(temp, CV_32F);
609         points = temp;
610     }
611 
612     if( npoints2 >= 0 )
613         fitLine2D( points.ptr<Point2f>(), npoints2, distType,
614                    (float)param, (float)reps, (float)aeps, linebuf);
615     else
616         fitLine3D( points.ptr<Point3f>(), npoints3, distType,
617                    (float)param, (float)reps, (float)aeps, linebuf);
618 
619     Mat(npoints2 >= 0 ? 4 : 6, 1, CV_32F, linebuf).copyTo(_line);
620 }
621 
622 
623 CV_IMPL void
cvFitLine(const CvArr * array,int dist,double param,double reps,double aeps,float * line)624 cvFitLine( const CvArr* array, int dist, double param,
625            double reps, double aeps, float *line )
626 {
627     CV_Assert(line != 0);
628 
629     cv::AutoBuffer<double> buf;
630     cv::Mat points = cv::cvarrToMat(array, false, false, 0, &buf);
631     cv::Mat linemat(points.checkVector(2) >= 0 ? 4 : 6, 1, CV_32F, line);
632 
633     cv::fitLine(points, linemat, dist, param, reps, aeps);
634 }
635 
636 /* End of file. */
637