1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html.
4
5 #ifndef __OPENCV_EDGE_DRAWING_COMMON_HPP__
6 #define __OPENCV_EDGE_DRAWING_COMMON_HPP__
7
8 #include <opencv2/core.hpp>
9
10 #define EDGE_VERTICAL 1
11 #define EDGE_HORIZONTAL 2
12
13 #define ANCHOR_PIXEL 254
14 #define EDGE_PIXEL 255
15
16 #define LEFT 1
17 #define RIGHT 2
18 #define UP 3
19 #define DOWN 4
20
21 #define SOUTH_SOUTH 0
22 #define SOUTH_EAST 1
23 #define EAST_SOUTH 2
24 #define EAST_EAST 3
25
26 // Circular arc, circle thresholds
27 #define VERY_SHORT_ARC_ERROR 0.40 // Used for very short arcs (>= CANDIDATE_CIRCLE_RATIO1 && < CANDIDATE_CIRCLE_RATIO2)
28 #define SHORT_ARC_ERROR 1.00 // Used for short arcs (>= CANDIDATE_CIRCLE_RATIO2 && < HALF_CIRCLE_RATIO)
29 #define HALF_ARC_ERROR 1.25 // Used for arcs with length (>=HALF_CIRCLE_RATIO && < FULL_CIRCLE_RATIO)
30 #define LONG_ARC_ERROR 1.50 // Used for long arcs (>= FULL_CIRCLE_RATIO)
31
32 #define CANDIDATE_CIRCLE_RATIO1 0.25 // 25% -- If only 25% of the circle is detected, it may be a candidate for validation
33 #define CANDIDATE_CIRCLE_RATIO2 0.33 // 33% -- If only 33% of the circle is detected, it may be a candidate for validation
34 #define HALF_CIRCLE_RATIO 0.50 // 50% -- If 50% of a circle is detected at any point during joins, we immediately make it a candidate
35 #define FULL_CIRCLE_RATIO 0.67 // 67% -- If 67% of the circle is detected, we assume that it is fully covered
36
37 // Ellipse thresholds
38 #define CANDIDATE_ELLIPSE_RATIO 0.50 // 50% -- If 50% of the ellipse is detected, it may be candidate for validation
39 #define ELLIPSE_ERROR 1.50 // Used for ellipses. (used to be 1.65 for what reason?)
40 #define MAX_GRAD_VALUE 128*256
41
42 using namespace std;
43 using namespace cv;
44
45 class NFALUT
46 {
47 public:
48
49 NFALUT(int size, double _prob, int _w, int _h);
50 ~NFALUT();
51
52 int* LUT; // look up table
53 int LUTSize;
54
55 double prob;
56 int w, h;
57
58 bool checkValidationByNFA(int n, int k);
59 static double myAtan2(double yy, double xx);
60
61 private:
62 double nfa(int n, int k);
63 static double Comb(double n, double k);
64 };
65
NFALUT(int size,double _prob,int _w,int _h)66 NFALUT::NFALUT(int size, double _prob, int _w, int _h)
67 {
68 LUTSize = size > 60 ? 60 : size;
69 LUT = new int[LUTSize];
70 w = _w;
71 h = _h;
72 prob = _prob;
73
74 LUT[0] = 1;
75 int j = 1;
76 for (int i = 1; i < LUTSize; i++)
77 {
78 LUT[i] = LUTSize + 1;
79 double ret = nfa(i, j);
80 if (ret >= 1.0)
81 {
82 while (j < i)
83 {
84 j++;
85 ret = nfa(i, j);
86 if (ret <= 1.0)
87 break;
88 }
89
90 if (ret >= 1.0)
91 continue;
92 }
93 LUT[i] = j;
94 }
95 }
96
97
~NFALUT()98 NFALUT::~NFALUT()
99 {
100 delete[] LUT;
101 }
102
checkValidationByNFA(int n,int k)103 bool NFALUT::checkValidationByNFA(int n, int k)
104 {
105 if (n >= LUTSize)
106 return nfa(n, k) <= 1.0;
107 else
108 return k >= LUT[n];
109 }
110
myAtan2(double yy,double xx)111 double NFALUT::myAtan2(double yy, double xx)
112 {
113 double angle = fastAtan2((float)yy, (float)xx);
114
115 if (angle > 180)
116 angle = angle - 180;
117
118 return angle / 180 * CV_PI;
119 }
120
Comb(double n,double k)121 double NFALUT::Comb(double n, double k) //fast combination computation
122 {
123 if (k > n)
124 return 0;
125
126 double r = 1;
127 for (double d = 1; d <= k; ++d)
128 {
129 r *= n--;
130 r /= d;
131 }
132 return r;
133 }
134
nfa(int n,int k)135 double NFALUT::nfa(int n, int k)
136 {
137 double sum = 0;
138 double p = 0.125;
139 for (int i = k; i <= n; i++)
140 sum += Comb(n, i) * pow(p, i) * pow(1 - p, n - i);
141
142 return sum * w * w * h * h;
143 }
144
145 struct StackNode
146 {
147 int r, c; // starting pixel
148 int parent; // parent chain (-1 if no parent)
149 int dir; // direction where you are supposed to go
150 };
151
152 // Used during Edge Linking
153 struct Chain
154 {
155 int dir; // Direction of the chain
156 int len; // # of pixels in the chain
157 int parent; // Parent of this node (-1 if no parent)
158 int children[2]; // Children of this node (-1 if no children)
159 Point *pixels; // Pointer to the beginning of the pixels array
160 };
161
162 // light weight struct for Start & End coordinates of the line segment
163 struct LS
164 {
165 Point2d start;
166 Point2d end;
167
LSLS168 LS(Point2d _start, Point2d _end)
169 {
170 start = _start;
171 end = _end;
172 }
173 };
174
175
176 struct EDLineSegment
177 {
178 double a, b; // y = a + bx (if invert = 0) || x = a + by (if invert = 1)
179 int invert;
180
181 double sx, sy; // starting x & y coordinates
182 double ex, ey; // ending x & y coordinates
183
184 int segmentNo; // Edge segment that this line belongs to
185 int firstPixelIndex; // Index of the first pixel within the segment of pixels
186 int len; // No of pixels making up the line segment
187
EDLineSegmentEDLineSegment188 EDLineSegment(double _a, double _b, int _invert, double _sx, double _sy, double _ex, double _ey, int _segmentNo, int _firstPixelIndex, int _len)
189 {
190 a = _a;
191 b = _b;
192 invert = _invert;
193 sx = _sx;
194 sy = _sy;
195 ex = _ex;
196 ey = _ey;
197 segmentNo = _segmentNo;
198 firstPixelIndex = _firstPixelIndex;
199 len = _len;
200 }
201 };
202
203 // Circle equation: (x-xc)^2 + (y-yc)^2 = r^2
204 struct mCircle {
205 Point2d center;
206 double r;
mCirclemCircle207 mCircle(Point2d _center, double _r) { center = _center; r = _r; }
208 };
209
210 // Ellipse equation: Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0
211 struct mEllipse {
212 Point2d center;
213 Size axes;
214 double theta;
mEllipsemEllipse215 mEllipse(Point2d _center, Size _axes, double _theta) { center = _center; axes = _axes; theta = _theta; }
216 };
217
218 //----------------------------------------------------------
219 // Ellipse Equation is of the form:
220 // Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0
221 //
222 struct EllipseEquation {
223 double coeff[7]; // coeff[1] = A
224
EllipseEquationEllipseEquation225 EllipseEquation() {
226 for (int i = 0; i<7; i++) coeff[i] = 0;
227 }
228
AEllipseEquation229 double A() { return coeff[1]; }
BEllipseEquation230 double B() { return coeff[2]; }
CEllipseEquation231 double C() { return coeff[3]; }
DEllipseEquation232 double D() { return coeff[4]; }
EEllipseEquation233 double E() { return coeff[5]; }
FEllipseEquation234 double F() { return coeff[6]; }
235 };
236
237 // ================================ CIRCLES ================================
238 struct Circle {
239 double xc, yc, r; // Center (xc, yc) & radius.
240 double circleFitError; // circle fit error
241 double coverRatio; // Percentage of the circle covered by the arcs making up this circle [0-1]
242
243 double *x, *y; // Pointers to buffers containing the pixels making up this circle
244 int noPixels; // # of pixels making up this circle
245
246 // If this circle is better approximated by an ellipse, we set isEllipse to true & eq contains the ellipse's equation
247 EllipseEquation eq;
248 double ellipseFitError; // ellipse fit error
249 bool isEllipse;
250 double majorAxisLength; // Length of the major axis
251 double minorAxisLength; // Length of the minor axis
252 };
253
254 // ------------------------------------------- ARCS ----------------------------------------------------
255 struct MyArc {
256 double xc, yc, r; // center x, y and radius
257 double circleFitError; // Error during circle fit
258
259 double sTheta, eTheta; // Start & end angle in radius
260 double coverRatio; // Ratio of the pixels covered on the covering circle [0-1] (noPixels/circumference)
261
262 int turn; // Turn direction: 1 or -1
263
264 int segmentNo; // SegmentNo where this arc belongs
265
266 int sx, sy; // Start (x, y) coordinate
267 int ex, ey; // End (x, y) coordinate of the arc
268
269 double *x, *y; // Pointer to buffer containing the pixels making up this arc
270 int noPixels; // # of pixels making up the arc
271
272 bool isEllipse; // Did we fit an ellipse to this arc?
273 EllipseEquation eq; // If an ellipse, then the ellipse's equation
274 double ellipseFitError; // Error during ellipse fit
275 };
276
277 // =============================== AngleSet ==================================
278
279 // add a circular arc to the list of arcs
ArcLength(double sTheta,double eTheta)280 inline double ArcLength(double sTheta, double eTheta)
281 {
282 if (eTheta > sTheta)
283 return eTheta - sTheta;
284 else
285 return CV_2PI - sTheta + eTheta;
286 }
287
288 // A fast implementation of the AngleSet class. The slow implementation is really bad. About 10 times slower than this!
289 struct AngleSetArc {
290 double sTheta;
291 double eTheta;
292 int next; // Next AngleSetArc in the linked list
293 };
294
295 struct AngleSet {
296 AngleSetArc angles[360];
297 int head;
298 int next; // Next AngleSetArc to be allocated
299 double overlapAmount; // Total overlap of the arcs in angleSet. Computed during set() function
300
AngleSetAngleSet301 AngleSet() { clear(); }
clearAngleSet302 void clear() { head = -1; next = 0; overlapAmount = 0; }
overlapRatioAngleSet303 double overlapRatio() { return overlapAmount / CV_2PI; }
304
305 void _set(double sTheta, double eTheta);
306 void set(double sTheta, double eTheta);
307
308 double _overlap(double sTheta, double eTheta);
309 double overlap(double sTheta, double eTheta);
310
311 void computeStartEndTheta(double& sTheta, double& eTheta);
312 double coverRatio();
313 };
314
_set(double sTheta,double eTheta)315 void AngleSet::_set(double sTheta, double eTheta)
316 {
317 int arc = next++;
318
319 angles[arc].sTheta = sTheta;
320 angles[arc].eTheta = eTheta;
321 angles[arc].next = -1;
322
323 // Add the current arc to the linked list
324 int prev = -1;
325 int current = head;
326 while (1)
327 {
328 // Empty list?
329 if (head < 0)
330 {
331 head = arc;
332 break;
333 }
334
335 // End of the list. Add to the end
336 if (current < 0)
337 {
338 CV_Assert(prev >= 0);
339 angles[prev].next = arc;
340 break;
341 }
342
343 if (angles[arc].eTheta <= angles[current].sTheta)
344 {
345 // Add before current
346 if (prev < 0)
347 {
348 angles[arc].next = current;
349 head = arc;
350 }
351 else
352 {
353 angles[arc].next = current;
354 angles[prev].next = arc;
355 }
356 break;
357 }
358 else if (angles[arc].sTheta >= angles[current].eTheta)
359 {
360 // continue
361 prev = current;
362 current = angles[current].next;
363
364 // End of the list?
365 if (current < 0)
366 {
367 angles[prev].next = arc;
368 break;
369 }
370 }
371 else
372 {
373 // overlaps with current. Join
374 // First delete current from the list
375 if (prev < 0)
376 head = angles[head].next;
377 else
378 angles[prev].next = angles[current].next;
379
380 // Update overlap amount.
381 if (angles[arc].eTheta < angles[current].eTheta)
382 {
383 overlapAmount += angles[arc].eTheta - angles[current].sTheta;
384 }
385 else
386 {
387 overlapAmount += angles[current].eTheta - angles[arc].sTheta;
388 }
389
390 // Now join current with arc
391 if (angles[current].sTheta < angles[arc].sTheta)
392 angles[arc].sTheta = angles[current].sTheta;
393 if (angles[current].eTheta > angles[arc].eTheta)
394 angles[arc].eTheta = angles[current].eTheta;
395 current = angles[current].next;
396 }
397 }
398 }
399
set(double sTheta,double eTheta)400 void AngleSet::set(double sTheta, double eTheta)
401 {
402 if (eTheta > sTheta)
403 {
404 _set(sTheta, eTheta);
405 }
406 else
407 {
408 _set(sTheta, CV_2PI);
409 _set(0, eTheta);
410 }
411 }
412
_overlap(double sTheta,double eTheta)413 double AngleSet::_overlap(double sTheta, double eTheta)
414 {
415 double o = 0;
416
417 int current = head;
418 while (current >= 0)
419 {
420 if (sTheta > angles[current].eTheta)
421 {
422 current = angles[current].next;
423 continue;
424 }
425 else if (eTheta < angles[current].sTheta)
426 break;
427
428 // 3 cases.
429 if (sTheta < angles[current].sTheta && eTheta > angles[current].eTheta)
430 {
431 o += angles[current].eTheta - angles[current].sTheta;
432
433 }
434 else if (sTheta < angles[current].sTheta)
435 {
436 o += eTheta - angles[current].sTheta;
437 }
438 else
439 {
440 o += angles[current].eTheta - sTheta;
441 }
442
443 current = angles[current].next;
444 }
445 return o;
446 }
447
overlap(double sTheta,double eTheta)448 double AngleSet::overlap(double sTheta, double eTheta)
449 {
450 double o;
451
452 if (eTheta > sTheta)
453 {
454 o = _overlap(sTheta, eTheta);
455 }
456 else
457 {
458 o = _overlap(sTheta, CV_2PI);
459 o += _overlap(0, eTheta);
460 }
461 return o / ArcLength(sTheta, eTheta);
462 }
463
computeStartEndTheta(double & sTheta,double & eTheta)464 void AngleSet::computeStartEndTheta(double& sTheta, double& eTheta)
465 {
466 // Special case: Just one arc
467 if (angles[head].next < 0)
468 {
469 sTheta = angles[head].sTheta;
470 eTheta = angles[head].eTheta;
471
472 return;
473 }
474
475 // OK. More than one arc. Find the biggest gap
476 int current = head;
477 int nextArc = angles[current].next;
478
479 double biggestGapSTheta = angles[current].eTheta;
480 double biggestGapEtheta = angles[nextArc].sTheta;
481 double biggestGapLength = biggestGapEtheta - biggestGapSTheta;
482
483 double start, end, len;
484 while (1)
485 {
486 current = nextArc;
487 nextArc = angles[nextArc].next;
488 if (nextArc < 0)
489 break;
490
491 start = angles[current].eTheta;
492 end = angles[nextArc].sTheta;
493 len = end - start;
494
495 if (len > biggestGapLength)
496 {
497 biggestGapSTheta = start;
498 biggestGapEtheta = end;
499 biggestGapLength = len;
500 }
501 }
502
503 // Compute the gap between the last arc & the first arc
504 start = angles[current].eTheta;
505 end = angles[head].sTheta;
506 len = CV_2PI - start + end;
507 if (len > biggestGapLength)
508 {
509 biggestGapSTheta = start;
510 biggestGapEtheta = end;
511 }
512 sTheta = biggestGapEtheta;
513 eTheta = biggestGapSTheta;
514 }
515
coverRatio()516 double AngleSet::coverRatio()
517 {
518 int current = head;
519
520 double total = 0;
521 while (current >= 0)
522 {
523 total += angles[current].eTheta - angles[current].sTheta;
524 current = angles[current].next;
525 }
526 return total / CV_2PI;
527 }
528
529 struct EDArcs {
530 MyArc *arcs;
531 int noArcs;
532
533 public:
EDArcsEDArcs534 EDArcs(int size = 10000) {
535 arcs = new MyArc[size];
536 noArcs = 0;
537 }
538
~EDArcsEDArcs539 ~EDArcs() {
540 delete arcs;
541 }
542 };
543
544 struct BufferManager {
545 double *x, *y;
546 int index;
547
BufferManagerBufferManager548 BufferManager(int maxSize) {
549 x = new double[maxSize];
550 y = new double[maxSize];
551 index = 0;
552 }
553
~BufferManagerBufferManager554 ~BufferManager() {
555 delete x;
556 delete y;
557 }
558
getXBufferManager559 double *getX() { return &x[index]; }
getYBufferManager560 double *getY() { return &y[index]; }
moveBufferManager561 void move(int size) { index += size; }
562 };
563
564 struct Info {
565 int sign; // -1 or 1: sign of the cross product
566 double angle; // angle with the next line (in radians)
567 bool taken; // Is this line taken during arc detection
568 };
569
570 #endif
571