Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/imgproc/src/geometry.cpp
16354 views
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
44
CV_IMPL CvRect
45
cvMaxRect( const CvRect* rect1, const CvRect* rect2 )
46
{
47
if( rect1 && rect2 )
48
{
49
cv::Rect max_rect;
50
int a, b;
51
52
max_rect.x = a = rect1->x;
53
b = rect2->x;
54
if( max_rect.x > b )
55
max_rect.x = b;
56
57
max_rect.width = a += rect1->width;
58
b += rect2->width;
59
60
if( max_rect.width < b )
61
max_rect.width = b;
62
max_rect.width -= max_rect.x;
63
64
max_rect.y = a = rect1->y;
65
b = rect2->y;
66
if( max_rect.y > b )
67
max_rect.y = b;
68
69
max_rect.height = a += rect1->height;
70
b += rect2->height;
71
72
if( max_rect.height < b )
73
max_rect.height = b;
74
max_rect.height -= max_rect.y;
75
return cvRect(max_rect);
76
}
77
else if( rect1 )
78
return *rect1;
79
else if( rect2 )
80
return *rect2;
81
else
82
return cvRect(0,0,0,0);
83
}
84
85
86
CV_IMPL void
87
cvBoxPoints( CvBox2D box, CvPoint2D32f pt[4] )
88
{
89
if( !pt )
90
CV_Error( CV_StsNullPtr, "NULL vertex array pointer" );
91
cv::RotatedRect(box).points((cv::Point2f*)pt);
92
}
93
94
95
double cv::pointPolygonTest( InputArray _contour, Point2f pt, bool measureDist )
96
{
97
CV_INSTRUMENT_REGION();
98
99
double result = 0;
100
Mat contour = _contour.getMat();
101
int i, total = contour.checkVector(2), counter = 0;
102
int depth = contour.depth();
103
CV_Assert( total >= 0 && (depth == CV_32S || depth == CV_32F));
104
105
bool is_float = depth == CV_32F;
106
double min_dist_num = FLT_MAX, min_dist_denom = 1;
107
Point ip(cvRound(pt.x), cvRound(pt.y));
108
109
if( total == 0 )
110
return measureDist ? -DBL_MAX : -1;
111
112
const Point* cnt = contour.ptr<Point>();
113
const Point2f* cntf = (const Point2f*)cnt;
114
115
if( !is_float && !measureDist && ip.x == pt.x && ip.y == pt.y )
116
{
117
// the fastest "purely integer" branch
118
Point v0, v = cnt[total-1];
119
120
for( i = 0; i < total; i++ )
121
{
122
v0 = v;
123
v = cnt[i];
124
125
if( (v0.y <= ip.y && v.y <= ip.y) ||
126
(v0.y > ip.y && v.y > ip.y) ||
127
(v0.x < ip.x && v.x < ip.x) )
128
{
129
if( ip.y == v.y && (ip.x == v.x || (ip.y == v0.y &&
130
((v0.x <= ip.x && ip.x <= v.x) || (v.x <= ip.x && ip.x <= v0.x)))) )
131
return 0;
132
continue;
133
}
134
135
int64 dist = static_cast<int64>(ip.y - v0.y)*(v.x - v0.x)
136
- static_cast<int64>(ip.x - v0.x)*(v.y - v0.y);
137
if( dist == 0 )
138
return 0;
139
if( v.y < v0.y )
140
dist = -dist;
141
counter += dist > 0;
142
}
143
144
result = counter % 2 == 0 ? -1 : 1;
145
}
146
else
147
{
148
Point2f v0, v;
149
Point iv;
150
151
if( is_float )
152
{
153
v = cntf[total-1];
154
}
155
else
156
{
157
v = cnt[total-1];
158
}
159
160
if( !measureDist )
161
{
162
for( i = 0; i < total; i++ )
163
{
164
double dist;
165
v0 = v;
166
if( is_float )
167
v = cntf[i];
168
else
169
v = cnt[i];
170
171
if( (v0.y <= pt.y && v.y <= pt.y) ||
172
(v0.y > pt.y && v.y > pt.y) ||
173
(v0.x < pt.x && v.x < pt.x) )
174
{
175
if( pt.y == v.y && (pt.x == v.x || (pt.y == v0.y &&
176
((v0.x <= pt.x && pt.x <= v.x) || (v.x <= pt.x && pt.x <= v0.x)))) )
177
return 0;
178
continue;
179
}
180
181
dist = (double)(pt.y - v0.y)*(v.x - v0.x) - (double)(pt.x - v0.x)*(v.y - v0.y);
182
if( dist == 0 )
183
return 0;
184
if( v.y < v0.y )
185
dist = -dist;
186
counter += dist > 0;
187
}
188
189
result = counter % 2 == 0 ? -1 : 1;
190
}
191
else
192
{
193
for( i = 0; i < total; i++ )
194
{
195
double dx, dy, dx1, dy1, dx2, dy2, dist_num, dist_denom = 1;
196
197
v0 = v;
198
if( is_float )
199
v = cntf[i];
200
else
201
v = cnt[i];
202
203
dx = v.x - v0.x; dy = v.y - v0.y;
204
dx1 = pt.x - v0.x; dy1 = pt.y - v0.y;
205
dx2 = pt.x - v.x; dy2 = pt.y - v.y;
206
207
if( dx1*dx + dy1*dy <= 0 )
208
dist_num = dx1*dx1 + dy1*dy1;
209
else if( dx2*dx + dy2*dy >= 0 )
210
dist_num = dx2*dx2 + dy2*dy2;
211
else
212
{
213
dist_num = (dy1*dx - dx1*dy);
214
dist_num *= dist_num;
215
dist_denom = dx*dx + dy*dy;
216
}
217
218
if( dist_num*min_dist_denom < min_dist_num*dist_denom )
219
{
220
min_dist_num = dist_num;
221
min_dist_denom = dist_denom;
222
if( min_dist_num == 0 )
223
break;
224
}
225
226
if( (v0.y <= pt.y && v.y <= pt.y) ||
227
(v0.y > pt.y && v.y > pt.y) ||
228
(v0.x < pt.x && v.x < pt.x) )
229
continue;
230
231
dist_num = dy1*dx - dx1*dy;
232
if( dy < 0 )
233
dist_num = -dist_num;
234
counter += dist_num > 0;
235
}
236
237
result = std::sqrt(min_dist_num/min_dist_denom);
238
if( counter % 2 == 0 )
239
result = -result;
240
}
241
}
242
243
return result;
244
}
245
246
247
CV_IMPL double
248
cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist )
249
{
250
cv::AutoBuffer<double> abuf;
251
cv::Mat contour = cv::cvarrToMat(_contour, false, false, 0, &abuf);
252
return cv::pointPolygonTest(contour, pt, measure_dist != 0);
253
}
254
255
/*
256
This code is described in "Computational Geometry in C" (Second Edition),
257
Chapter 7. It is not written to be comprehensible without the
258
explanation in that book.
259
260
Written by Joseph O'Rourke.
261
Last modified: December 1997
262
Questions to [email protected].
263
--------------------------------------------------------------------
264
This code is Copyright 1997 by Joseph O'Rourke. It may be freely
265
redistributed in its entirety provided that this copyright notice is
266
not removed.
267
--------------------------------------------------------------------
268
*/
269
270
namespace cv
271
{
272
typedef enum { Pin, Qin, Unknown } tInFlag;
273
274
static int areaSign( Point2f a, Point2f b, Point2f c )
275
{
276
static const double eps = 1e-5;
277
double area2 = (b.x - a.x) * (double)(c.y - a.y) - (c.x - a.x ) * (double)(b.y - a.y);
278
return area2 > eps ? 1 : area2 < -eps ? -1 : 0;
279
}
280
281
//---------------------------------------------------------------------
282
// Returns true iff point c lies on the closed segment ab.
283
// Assumes it is already known that abc are collinear.
284
//---------------------------------------------------------------------
285
static bool between( Point2f a, Point2f b, Point2f c )
286
{
287
Point2f ba, ca;
288
289
// If ab not vertical, check betweenness on x; else on y.
290
if ( a.x != b.x )
291
return ((a.x <= c.x) && (c.x <= b.x)) ||
292
((a.x >= c.x) && (c.x >= b.x));
293
else
294
return ((a.y <= c.y) && (c.y <= b.y)) ||
295
((a.y >= c.y) && (c.y >= b.y));
296
}
297
298
enum LineSegmentIntersection
299
{
300
LS_NO_INTERSECTION = 0,
301
LS_SINGLE_INTERSECTION = 1,
302
LS_OVERLAP = 2,
303
LS_ENDPOINT_INTERSECTION = 3
304
};
305
306
static LineSegmentIntersection parallelInt( Point2f a, Point2f b, Point2f c, Point2f d, Point2f& p, Point2f& q )
307
{
308
LineSegmentIntersection code = LS_OVERLAP;
309
if( areaSign(a, b, c) != 0 )
310
code = LS_NO_INTERSECTION;
311
else if( between(a, b, c) && between(a, b, d))
312
p = c, q = d;
313
else if( between(c, d, a) && between(c, d, b))
314
p = a, q = b;
315
else if( between(a, b, c) && between(c, d, b))
316
p = c, q = b;
317
else if( between(a, b, c) && between(c, d, a))
318
p = c, q = a;
319
else if( between(a, b, d) && between(c, d, b))
320
p = d, q = b;
321
else if( between(a, b, d) && between(c, d, a))
322
p = d, q = a;
323
else
324
code = LS_NO_INTERSECTION;
325
return code;
326
}
327
328
// Finds intersection of two line segments: (a, b) and (c, d).
329
static LineSegmentIntersection intersectLineSegments( Point2f a, Point2f b, Point2f c,
330
Point2f d, Point2f& p, Point2f& q )
331
{
332
double denom = a.x * (double)(d.y - c.y) + b.x * (double)(c.y - d.y) +
333
d.x * (double)(b.y - a.y) + c.x * (double)(a.y - b.y);
334
335
// If denom is zero, then segments are parallel: handle separately.
336
if( denom == 0. )
337
return parallelInt(a, b, c, d, p, q);
338
339
double num = a.x * (double)(d.y - c.y) + c.x * (double)(a.y - d.y) + d.x * (double)(c.y - a.y);
340
double s = num / denom;
341
342
num = a.x * (double)(b.y - c.y) + b.x * (double)(c.y - a.y) + c.x * (double)(a.y - b.y);
343
double t = num / denom;
344
345
p.x = (float)(a.x + s*(b.x - a.x));
346
p.y = (float)(a.y + s*(b.y - a.y));
347
q = p;
348
349
return s < 0. || s > 1. || t < 0. || t > 1. ? LS_NO_INTERSECTION :
350
s == 0. || s == 1. || t == 0. || t == 1. ? LS_ENDPOINT_INTERSECTION : LS_SINGLE_INTERSECTION;
351
}
352
353
static tInFlag inOut( Point2f p, tInFlag inflag, int aHB, int bHA, Point2f*& result )
354
{
355
if( p != result[-1] )
356
*result++ = p;
357
// Update inflag.
358
return aHB > 0 ? Pin : bHA > 0 ? Qin : inflag;
359
}
360
361
//---------------------------------------------------------------------
362
// Advances and prints out an inside vertex if appropriate.
363
//---------------------------------------------------------------------
364
static int advance( int a, int *aa, int n, bool inside, Point2f v, Point2f*& result )
365
{
366
if( inside && v != result[-1] )
367
*result++ = v;
368
(*aa)++;
369
return (a+1) % n;
370
}
371
372
static void addSharedSeg( Point2f p, Point2f q, Point2f*& result )
373
{
374
if( p != result[-1] )
375
*result++ = p;
376
if( q != result[-1] )
377
*result++ = q;
378
}
379
380
381
static int intersectConvexConvex_( const Point2f* P, int n, const Point2f* Q, int m,
382
Point2f* result, float* _area )
383
{
384
Point2f* result0 = result;
385
// P has n vertices, Q has m vertices.
386
int a=0, b=0; // indices on P and Q (resp.)
387
Point2f Origin(0,0);
388
tInFlag inflag=Unknown; // {Pin, Qin, Unknown}: which inside
389
int aa=0, ba=0; // # advances on a & b indices (after 1st inter.)
390
bool FirstPoint=true;// Is this the first point? (used to initialize).
391
Point2f p0; // The first point.
392
*result++ = Point2f(FLT_MAX, FLT_MAX);
393
394
do
395
{
396
// Computations of key variables.
397
int a1 = (a + n - 1) % n; // a-1, b-1 (resp.)
398
int b1 = (b + m - 1) % m;
399
400
Point2f A = P[a] - P[a1], B = Q[b] - Q[b1]; // directed edges on P and Q (resp.)
401
402
int cross = areaSign( Origin, A, B ); // sign of z-component of A x B
403
int aHB = areaSign( Q[b1], Q[b], P[a] ); // a in H(b).
404
int bHA = areaSign( P[a1], P[a], Q[b] ); // b in H(A);
405
406
// If A & B intersect, update inflag.
407
Point2f p, q;
408
LineSegmentIntersection code = intersectLineSegments( P[a1], P[a], Q[b1], Q[b], p, q );
409
if( code == LS_SINGLE_INTERSECTION || code == LS_ENDPOINT_INTERSECTION )
410
{
411
if( inflag == Unknown && FirstPoint )
412
{
413
aa = ba = 0;
414
FirstPoint = false;
415
p0 = p;
416
*result++ = p;
417
}
418
inflag = inOut( p, inflag, aHB, bHA, result );
419
}
420
421
//-----Advance rules-----
422
423
// Special case: A & B overlap and oppositely oriented.
424
if( code == LS_OVERLAP && A.ddot(B) < 0 )
425
{
426
addSharedSeg( p, q, result );
427
return (int)(result - result0);
428
}
429
430
// Special case: A & B parallel and separated.
431
if( cross == 0 && aHB < 0 && bHA < 0 )
432
return (int)(result - result0);
433
434
// Special case: A & B collinear.
435
else if ( cross == 0 && aHB == 0 && bHA == 0 ) {
436
// Advance but do not output point.
437
if ( inflag == Pin )
438
b = advance( b, &ba, m, inflag == Qin, Q[b], result );
439
else
440
a = advance( a, &aa, n, inflag == Pin, P[a], result );
441
}
442
443
// Generic cases.
444
else if( cross >= 0 )
445
{
446
if( bHA > 0)
447
a = advance( a, &aa, n, inflag == Pin, P[a], result );
448
else
449
b = advance( b, &ba, m, inflag == Qin, Q[b], result );
450
}
451
else
452
{
453
if( aHB > 0)
454
b = advance( b, &ba, m, inflag == Qin, Q[b], result );
455
else
456
a = advance( a, &aa, n, inflag == Pin, P[a], result );
457
}
458
// Quit when both adv. indices have cycled, or one has cycled twice.
459
}
460
while ( ((aa < n) || (ba < m)) && (aa < 2*n) && (ba < 2*m) );
461
462
// Deal with special cases: not implemented.
463
if( inflag == Unknown )
464
{
465
// The boundaries of P and Q do not cross.
466
// ...
467
}
468
469
int i, nr = (int)(result - result0);
470
double area = 0;
471
Point2f prev = result0[nr-1];
472
for( i = 1; i < nr; i++ )
473
{
474
result0[i-1] = result0[i];
475
area += (double)prev.x*result0[i].y - (double)prev.y*result0[i].x;
476
prev = result0[i];
477
}
478
479
*_area = (float)(area*0.5);
480
481
if( result0[nr-2] == result0[0] && nr > 1 )
482
nr--;
483
return nr-1;
484
}
485
486
}
487
488
float cv::intersectConvexConvex( InputArray _p1, InputArray _p2, OutputArray _p12, bool handleNested )
489
{
490
CV_INSTRUMENT_REGION();
491
492
Mat p1 = _p1.getMat(), p2 = _p2.getMat();
493
CV_Assert( p1.depth() == CV_32S || p1.depth() == CV_32F );
494
CV_Assert( p2.depth() == CV_32S || p2.depth() == CV_32F );
495
496
int n = p1.checkVector(2, p1.depth(), true);
497
int m = p2.checkVector(2, p2.depth(), true);
498
499
CV_Assert( n >= 0 && m >= 0 );
500
501
if( n < 2 || m < 2 )
502
{
503
_p12.release();
504
return 0.f;
505
}
506
507
AutoBuffer<Point2f> _result(n*2 + m*2 + 1);
508
Point2f *fp1 = _result.data(), *fp2 = fp1 + n;
509
Point2f* result = fp2 + m;
510
int orientation = 0;
511
512
for( int k = 1; k <= 2; k++ )
513
{
514
Mat& p = k == 1 ? p1 : p2;
515
int len = k == 1 ? n : m;
516
Point2f* dst = k == 1 ? fp1 : fp2;
517
518
Mat temp(p.size(), CV_MAKETYPE(CV_32F, p.channels()), dst);
519
p.convertTo(temp, CV_32F);
520
CV_Assert( temp.ptr<Point2f>() == dst );
521
Point2f diff0 = dst[0] - dst[len-1];
522
for( int i = 1; i < len; i++ )
523
{
524
double s = diff0.cross(dst[i] - dst[i-1]);
525
if( s != 0 )
526
{
527
if( s < 0 )
528
{
529
orientation++;
530
flip( temp, temp, temp.rows > 1 ? 0 : 1 );
531
}
532
break;
533
}
534
}
535
}
536
537
float area = 0.f;
538
int nr = intersectConvexConvex_(fp1, n, fp2, m, result, &area);
539
if( nr == 0 )
540
{
541
if( !handleNested )
542
{
543
_p12.release();
544
return 0.f;
545
}
546
547
if( pointPolygonTest(_InputArray(fp1, n), fp2[0], false) >= 0 )
548
{
549
result = fp2;
550
nr = m;
551
}
552
else if( pointPolygonTest(_InputArray(fp2, m), fp1[0], false) >= 0 )
553
{
554
result = fp1;
555
nr = n;
556
}
557
else
558
{
559
_p12.release();
560
return 0.f;
561
}
562
area = (float)contourArea(_InputArray(result, nr), false);
563
}
564
565
if( _p12.needed() )
566
{
567
Mat temp(nr, 1, CV_32FC2, result);
568
// if both input contours were reflected,
569
// let's orient the result as the input vectors
570
if( orientation == 2 )
571
flip(temp, temp, 0);
572
573
temp.copyTo(_p12);
574
}
575
return (float)fabs(area);
576
}
577
578