Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/imgproc/src/drawing.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
namespace cv
44
{
45
46
enum { XY_SHIFT = 16, XY_ONE = 1 << XY_SHIFT, DRAWING_STORAGE_BLOCK = (1<<12) - 256 };
47
48
static const int MAX_THICKNESS = 32767;
49
50
struct PolyEdge
51
{
52
PolyEdge() : y0(0), y1(0), x(0), dx(0), next(0) {}
53
//PolyEdge(int _y0, int _y1, int _x, int _dx) : y0(_y0), y1(_y1), x(_x), dx(_dx) {}
54
55
int y0, y1;
56
int64 x, dx;
57
PolyEdge *next;
58
};
59
60
static void
61
CollectPolyEdges( Mat& img, const Point2l* v, int npts,
62
std::vector<PolyEdge>& edges, const void* color, int line_type,
63
int shift, Point offset=Point() );
64
65
static void
66
FillEdgeCollection( Mat& img, std::vector<PolyEdge>& edges, const void* color );
67
68
static void
69
PolyLine( Mat& img, const Point2l* v, int npts, bool closed,
70
const void* color, int thickness, int line_type, int shift );
71
72
static void
73
FillConvexPoly( Mat& img, const Point2l* v, int npts,
74
const void* color, int line_type, int shift );
75
76
/****************************************************************************************\
77
* Lines *
78
\****************************************************************************************/
79
80
bool clipLine( Size img_size, Point& pt1, Point& pt2 )
81
{
82
Point2l p1(pt1);
83
Point2l p2(pt2);
84
bool inside = clipLine(Size2l(img_size.width, img_size.height), p1, p2);
85
pt1.x = (int)p1.x;
86
pt1.y = (int)p1.y;
87
pt2.x = (int)p2.x;
88
pt2.y = (int)p2.y;
89
return inside;
90
}
91
92
bool clipLine( Size2l img_size, Point2l& pt1, Point2l& pt2 )
93
{
94
CV_INSTRUMENT_REGION();
95
96
int c1, c2;
97
int64 right = img_size.width-1, bottom = img_size.height-1;
98
99
if( img_size.width <= 0 || img_size.height <= 0 )
100
return false;
101
102
int64 &x1 = pt1.x, &y1 = pt1.y, &x2 = pt2.x, &y2 = pt2.y;
103
c1 = (x1 < 0) + (x1 > right) * 2 + (y1 < 0) * 4 + (y1 > bottom) * 8;
104
c2 = (x2 < 0) + (x2 > right) * 2 + (y2 < 0) * 4 + (y2 > bottom) * 8;
105
106
if( (c1 & c2) == 0 && (c1 | c2) != 0 )
107
{
108
int64 a;
109
if( c1 & 12 )
110
{
111
a = c1 < 8 ? 0 : bottom;
112
x1 += (int64)((double)(a - y1) * (x2 - x1) / (y2 - y1));
113
y1 = a;
114
c1 = (x1 < 0) + (x1 > right) * 2;
115
}
116
if( c2 & 12 )
117
{
118
a = c2 < 8 ? 0 : bottom;
119
x2 += (int64)((double)(a - y2) * (x2 - x1) / (y2 - y1));
120
y2 = a;
121
c2 = (x2 < 0) + (x2 > right) * 2;
122
}
123
if( (c1 & c2) == 0 && (c1 | c2) != 0 )
124
{
125
if( c1 )
126
{
127
a = c1 == 1 ? 0 : right;
128
y1 += (int64)((double)(a - x1) * (y2 - y1) / (x2 - x1));
129
x1 = a;
130
c1 = 0;
131
}
132
if( c2 )
133
{
134
a = c2 == 1 ? 0 : right;
135
y2 += (int64)((double)(a - x2) * (y2 - y1) / (x2 - x1));
136
x2 = a;
137
c2 = 0;
138
}
139
}
140
141
assert( (c1 & c2) != 0 || (x1 | y1 | x2 | y2) >= 0 );
142
}
143
144
return (c1 | c2) == 0;
145
}
146
147
bool clipLine( Rect img_rect, Point& pt1, Point& pt2 )
148
{
149
CV_INSTRUMENT_REGION();
150
151
Point tl = img_rect.tl();
152
pt1 -= tl; pt2 -= tl;
153
bool inside = clipLine(img_rect.size(), pt1, pt2);
154
pt1 += tl; pt2 += tl;
155
156
return inside;
157
}
158
159
/*
160
Initializes line iterator.
161
Returns number of points on the line or negative number if error.
162
*/
163
LineIterator::LineIterator(const Mat& img, Point pt1, Point pt2,
164
int connectivity, bool left_to_right)
165
{
166
count = -1;
167
168
CV_Assert( connectivity == 8 || connectivity == 4 );
169
170
if( (unsigned)pt1.x >= (unsigned)(img.cols) ||
171
(unsigned)pt2.x >= (unsigned)(img.cols) ||
172
(unsigned)pt1.y >= (unsigned)(img.rows) ||
173
(unsigned)pt2.y >= (unsigned)(img.rows) )
174
{
175
if( !clipLine( img.size(), pt1, pt2 ) )
176
{
177
ptr = img.data;
178
err = plusDelta = minusDelta = plusStep = minusStep = count = 0;
179
ptr0 = 0;
180
step = 0;
181
elemSize = 0;
182
return;
183
}
184
}
185
186
size_t bt_pix0 = img.elemSize(), bt_pix = bt_pix0;
187
size_t istep = img.step;
188
189
int dx = pt2.x - pt1.x;
190
int dy = pt2.y - pt1.y;
191
int s = dx < 0 ? -1 : 0;
192
193
if( left_to_right )
194
{
195
dx = (dx ^ s) - s;
196
dy = (dy ^ s) - s;
197
pt1.x ^= (pt1.x ^ pt2.x) & s;
198
pt1.y ^= (pt1.y ^ pt2.y) & s;
199
}
200
else
201
{
202
dx = (dx ^ s) - s;
203
bt_pix = (bt_pix ^ s) - s;
204
}
205
206
ptr = (uchar*)(img.data + pt1.y * istep + pt1.x * bt_pix0);
207
208
s = dy < 0 ? -1 : 0;
209
dy = (dy ^ s) - s;
210
istep = (istep ^ s) - s;
211
212
s = dy > dx ? -1 : 0;
213
214
/* conditional swaps */
215
dx ^= dy & s;
216
dy ^= dx & s;
217
dx ^= dy & s;
218
219
bt_pix ^= istep & s;
220
istep ^= bt_pix & s;
221
bt_pix ^= istep & s;
222
223
if( connectivity == 8 )
224
{
225
assert( dx >= 0 && dy >= 0 );
226
227
err = dx - (dy + dy);
228
plusDelta = dx + dx;
229
minusDelta = -(dy + dy);
230
plusStep = (int)istep;
231
minusStep = (int)bt_pix;
232
count = dx + 1;
233
}
234
else /* connectivity == 4 */
235
{
236
assert( dx >= 0 && dy >= 0 );
237
238
err = 0;
239
plusDelta = (dx + dx) + (dy + dy);
240
minusDelta = -(dy + dy);
241
plusStep = (int)(istep - bt_pix);
242
minusStep = (int)bt_pix;
243
count = dx + dy + 1;
244
}
245
246
this->ptr0 = img.ptr();
247
this->step = (int)img.step;
248
this->elemSize = (int)bt_pix0;
249
}
250
251
static void
252
Line( Mat& img, Point pt1, Point pt2,
253
const void* _color, int connectivity = 8 )
254
{
255
if( connectivity == 0 )
256
connectivity = 8;
257
else if( connectivity == 1 )
258
connectivity = 4;
259
260
LineIterator iterator(img, pt1, pt2, connectivity, true);
261
int i, count = iterator.count;
262
int pix_size = (int)img.elemSize();
263
const uchar* color = (const uchar*)_color;
264
265
for( i = 0; i < count; i++, ++iterator )
266
{
267
uchar* ptr = *iterator;
268
if( pix_size == 1 )
269
ptr[0] = color[0];
270
else if( pix_size == 3 )
271
{
272
ptr[0] = color[0];
273
ptr[1] = color[1];
274
ptr[2] = color[2];
275
}
276
else
277
memcpy( *iterator, color, pix_size );
278
}
279
}
280
281
282
/* Correction table depent on the slope */
283
static const uchar SlopeCorrTable[] = {
284
181, 181, 181, 182, 182, 183, 184, 185, 187, 188, 190, 192, 194, 196, 198, 201,
285
203, 206, 209, 211, 214, 218, 221, 224, 227, 231, 235, 238, 242, 246, 250, 254
286
};
287
288
/* Gaussian for antialiasing filter */
289
static const int FilterTable[] = {
290
168, 177, 185, 194, 202, 210, 218, 224, 231, 236, 241, 246, 249, 252, 254, 254,
291
254, 254, 252, 249, 246, 241, 236, 231, 224, 218, 210, 202, 194, 185, 177, 168,
292
158, 149, 140, 131, 122, 114, 105, 97, 89, 82, 75, 68, 62, 56, 50, 45,
293
40, 36, 32, 28, 25, 22, 19, 16, 14, 12, 11, 9, 8, 7, 5, 5
294
};
295
296
static void
297
LineAA( Mat& img, Point2l pt1, Point2l pt2, const void* color )
298
{
299
int64 dx, dy;
300
int ecount, scount = 0;
301
int slope;
302
int64 ax, ay;
303
int64 x_step, y_step;
304
int64 i, j;
305
int ep_table[9];
306
int cb = ((uchar*)color)[0], cg = ((uchar*)color)[1], cr = ((uchar*)color)[2], ca = ((uchar*)color)[3];
307
int _cb, _cg, _cr, _ca;
308
int nch = img.channels();
309
uchar* ptr = img.ptr();
310
size_t step = img.step;
311
Size2l size(img.size());
312
313
if( !((nch == 1 || nch == 3 || nch == 4) && img.depth() == CV_8U) )
314
{
315
Line(img, Point((int)(pt1.x>>XY_SHIFT), (int)(pt1.y>>XY_SHIFT)), Point((int)(pt2.x>>XY_SHIFT), (int)(pt2.y>>XY_SHIFT)), color);
316
return;
317
}
318
319
pt1.x -= XY_ONE*2;
320
pt1.y -= XY_ONE*2;
321
pt2.x -= XY_ONE*2;
322
pt2.y -= XY_ONE*2;
323
ptr += img.step*2 + 2*nch;
324
325
size.width = ((size.width - 5) << XY_SHIFT) + 1;
326
size.height = ((size.height - 5) << XY_SHIFT) + 1;
327
328
if( !clipLine( size, pt1, pt2 ))
329
return;
330
331
dx = pt2.x - pt1.x;
332
dy = pt2.y - pt1.y;
333
334
j = dx < 0 ? -1 : 0;
335
ax = (dx ^ j) - j;
336
i = dy < 0 ? -1 : 0;
337
ay = (dy ^ i) - i;
338
339
if( ax > ay )
340
{
341
dy = (dy ^ j) - j;
342
pt1.x ^= pt2.x & j;
343
pt2.x ^= pt1.x & j;
344
pt1.x ^= pt2.x & j;
345
pt1.y ^= pt2.y & j;
346
pt2.y ^= pt1.y & j;
347
pt1.y ^= pt2.y & j;
348
349
x_step = XY_ONE;
350
y_step = (dy << XY_SHIFT) / (ax | 1);
351
pt2.x += XY_ONE;
352
ecount = (int)((pt2.x >> XY_SHIFT) - (pt1.x >> XY_SHIFT));
353
j = -(pt1.x & (XY_ONE - 1));
354
pt1.y += ((y_step * j) >> XY_SHIFT) + (XY_ONE >> 1);
355
slope = (y_step >> (XY_SHIFT - 5)) & 0x3f;
356
slope ^= (y_step < 0 ? 0x3f : 0);
357
358
/* Get 4-bit fractions for end-point adjustments */
359
i = (pt1.x >> (XY_SHIFT - 7)) & 0x78;
360
j = (pt2.x >> (XY_SHIFT - 7)) & 0x78;
361
}
362
else
363
{
364
dx = (dx ^ i) - i;
365
pt1.x ^= pt2.x & i;
366
pt2.x ^= pt1.x & i;
367
pt1.x ^= pt2.x & i;
368
pt1.y ^= pt2.y & i;
369
pt2.y ^= pt1.y & i;
370
pt1.y ^= pt2.y & i;
371
372
x_step = (dx << XY_SHIFT) / (ay | 1);
373
y_step = XY_ONE;
374
pt2.y += XY_ONE;
375
ecount = (int)((pt2.y >> XY_SHIFT) - (pt1.y >> XY_SHIFT));
376
j = -(pt1.y & (XY_ONE - 1));
377
pt1.x += ((x_step * j) >> XY_SHIFT) + (XY_ONE >> 1);
378
slope = (x_step >> (XY_SHIFT - 5)) & 0x3f;
379
slope ^= (x_step < 0 ? 0x3f : 0);
380
381
/* Get 4-bit fractions for end-point adjustments */
382
i = (pt1.y >> (XY_SHIFT - 7)) & 0x78;
383
j = (pt2.y >> (XY_SHIFT - 7)) & 0x78;
384
}
385
386
slope = (slope & 0x20) ? 0x100 : SlopeCorrTable[slope];
387
388
/* Calc end point correction table */
389
{
390
int t0 = slope << 7;
391
int t1 = ((0x78 - (int)i) | 4) * slope;
392
int t2 = ((int)j | 4) * slope;
393
394
ep_table[0] = 0;
395
ep_table[8] = slope;
396
ep_table[1] = ep_table[3] = ((((j - i) & 0x78) | 4) * slope >> 8) & 0x1ff;
397
ep_table[2] = (t1 >> 8) & 0x1ff;
398
ep_table[4] = ((((j - i) + 0x80) | 4) * slope >> 8) & 0x1ff;
399
ep_table[5] = ((t1 + t0) >> 8) & 0x1ff;
400
ep_table[6] = (t2 >> 8) & 0x1ff;
401
ep_table[7] = ((t2 + t0) >> 8) & 0x1ff;
402
}
403
404
if( nch == 3 )
405
{
406
#define ICV_PUT_POINT() \
407
{ \
408
_cb = tptr[0]; \
409
_cb += ((cb - _cb)*a + 127)>> 8;\
410
_cg = tptr[1]; \
411
_cg += ((cg - _cg)*a + 127)>> 8;\
412
_cr = tptr[2]; \
413
_cr += ((cr - _cr)*a + 127)>> 8;\
414
tptr[0] = (uchar)_cb; \
415
tptr[1] = (uchar)_cg; \
416
tptr[2] = (uchar)_cr; \
417
}
418
if( ax > ay )
419
{
420
ptr += (pt1.x >> XY_SHIFT) * 3;
421
422
while( ecount >= 0 )
423
{
424
uchar *tptr = ptr + ((pt1.y >> XY_SHIFT) - 1) * step;
425
426
int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
427
(((ecount >= 2) + 1) & (ecount | 2))];
428
int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31;
429
430
a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff;
431
ICV_PUT_POINT();
432
ICV_PUT_POINT();
433
434
tptr += step;
435
a = (ep_corr * FilterTable[dist] >> 8) & 0xff;
436
ICV_PUT_POINT();
437
ICV_PUT_POINT();
438
439
tptr += step;
440
a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff;
441
ICV_PUT_POINT();
442
ICV_PUT_POINT();
443
444
pt1.y += y_step;
445
ptr += 3;
446
scount++;
447
ecount--;
448
}
449
}
450
else
451
{
452
ptr += (pt1.y >> XY_SHIFT) * step;
453
454
while( ecount >= 0 )
455
{
456
uchar *tptr = ptr + ((pt1.x >> XY_SHIFT) - 1) * 3;
457
458
int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
459
(((ecount >= 2) + 1) & (ecount | 2))];
460
int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31;
461
462
a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff;
463
ICV_PUT_POINT();
464
ICV_PUT_POINT();
465
466
tptr += 3;
467
a = (ep_corr * FilterTable[dist] >> 8) & 0xff;
468
ICV_PUT_POINT();
469
ICV_PUT_POINT();
470
471
tptr += 3;
472
a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff;
473
ICV_PUT_POINT();
474
ICV_PUT_POINT();
475
476
pt1.x += x_step;
477
ptr += step;
478
scount++;
479
ecount--;
480
}
481
}
482
#undef ICV_PUT_POINT
483
}
484
else if(nch == 1)
485
{
486
#define ICV_PUT_POINT() \
487
{ \
488
_cb = tptr[0]; \
489
_cb += ((cb - _cb)*a + 127)>> 8;\
490
tptr[0] = (uchar)_cb; \
491
}
492
493
if( ax > ay )
494
{
495
ptr += (pt1.x >> XY_SHIFT);
496
497
while( ecount >= 0 )
498
{
499
uchar *tptr = ptr + ((pt1.y >> XY_SHIFT) - 1) * step;
500
501
int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
502
(((ecount >= 2) + 1) & (ecount | 2))];
503
int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31;
504
505
a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff;
506
ICV_PUT_POINT();
507
ICV_PUT_POINT();
508
509
tptr += step;
510
a = (ep_corr * FilterTable[dist] >> 8) & 0xff;
511
ICV_PUT_POINT();
512
ICV_PUT_POINT();
513
514
tptr += step;
515
a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff;
516
ICV_PUT_POINT();
517
ICV_PUT_POINT();
518
519
pt1.y += y_step;
520
ptr++;
521
scount++;
522
ecount--;
523
}
524
}
525
else
526
{
527
ptr += (pt1.y >> XY_SHIFT) * step;
528
529
while( ecount >= 0 )
530
{
531
uchar *tptr = ptr + ((pt1.x >> XY_SHIFT) - 1);
532
533
int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
534
(((ecount >= 2) + 1) & (ecount | 2))];
535
int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31;
536
537
a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff;
538
ICV_PUT_POINT();
539
ICV_PUT_POINT();
540
541
tptr++;
542
a = (ep_corr * FilterTable[dist] >> 8) & 0xff;
543
ICV_PUT_POINT();
544
ICV_PUT_POINT();
545
546
tptr++;
547
a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff;
548
ICV_PUT_POINT();
549
ICV_PUT_POINT();
550
551
pt1.x += x_step;
552
ptr += step;
553
scount++;
554
ecount--;
555
}
556
}
557
#undef ICV_PUT_POINT
558
}
559
else
560
{
561
#define ICV_PUT_POINT() \
562
{ \
563
_cb = tptr[0]; \
564
_cb += ((cb - _cb)*a + 127)>> 8;\
565
_cg = tptr[1]; \
566
_cg += ((cg - _cg)*a + 127)>> 8;\
567
_cr = tptr[2]; \
568
_cr += ((cr - _cr)*a + 127)>> 8;\
569
_ca = tptr[3]; \
570
_ca += ((ca - _ca)*a + 127)>> 8;\
571
tptr[0] = (uchar)_cb; \
572
tptr[1] = (uchar)_cg; \
573
tptr[2] = (uchar)_cr; \
574
tptr[3] = (uchar)_ca; \
575
}
576
if( ax > ay )
577
{
578
ptr += (pt1.x >> XY_SHIFT) * 4;
579
580
while( ecount >= 0 )
581
{
582
uchar *tptr = ptr + ((pt1.y >> XY_SHIFT) - 1) * step;
583
584
int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
585
(((ecount >= 2) + 1) & (ecount | 2))];
586
int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31;
587
588
a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff;
589
ICV_PUT_POINT();
590
ICV_PUT_POINT();
591
592
tptr += step;
593
a = (ep_corr * FilterTable[dist] >> 8) & 0xff;
594
ICV_PUT_POINT();
595
ICV_PUT_POINT();
596
597
tptr += step;
598
a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff;
599
ICV_PUT_POINT();
600
ICV_PUT_POINT();
601
602
pt1.y += y_step;
603
ptr += 4;
604
scount++;
605
ecount--;
606
}
607
}
608
else
609
{
610
ptr += (pt1.y >> XY_SHIFT) * step;
611
612
while( ecount >= 0 )
613
{
614
uchar *tptr = ptr + ((pt1.x >> XY_SHIFT) - 1) * 4;
615
616
int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
617
(((ecount >= 2) + 1) & (ecount | 2))];
618
int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31;
619
620
a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff;
621
ICV_PUT_POINT();
622
ICV_PUT_POINT();
623
624
tptr += 4;
625
a = (ep_corr * FilterTable[dist] >> 8) & 0xff;
626
ICV_PUT_POINT();
627
ICV_PUT_POINT();
628
629
tptr += 4;
630
a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff;
631
ICV_PUT_POINT();
632
ICV_PUT_POINT();
633
634
pt1.x += x_step;
635
ptr += step;
636
scount++;
637
ecount--;
638
}
639
}
640
#undef ICV_PUT_POINT
641
}
642
}
643
644
645
static void
646
Line2( Mat& img, Point2l pt1, Point2l pt2, const void* color)
647
{
648
int64 dx, dy;
649
int ecount;
650
int64 ax, ay;
651
int64 i, j;
652
int x, y;
653
int64 x_step, y_step;
654
int cb = ((uchar*)color)[0];
655
int cg = ((uchar*)color)[1];
656
int cr = ((uchar*)color)[2];
657
int pix_size = (int)img.elemSize();
658
uchar *ptr = img.ptr(), *tptr;
659
size_t step = img.step;
660
Size size = img.size();
661
662
//assert( img && (nch == 1 || nch == 3) && img.depth() == CV_8U );
663
664
Size2l sizeScaled(((int64)size.width) << XY_SHIFT, ((int64)size.height) << XY_SHIFT);
665
if( !clipLine( sizeScaled, pt1, pt2 ))
666
return;
667
668
dx = pt2.x - pt1.x;
669
dy = pt2.y - pt1.y;
670
671
j = dx < 0 ? -1 : 0;
672
ax = (dx ^ j) - j;
673
i = dy < 0 ? -1 : 0;
674
ay = (dy ^ i) - i;
675
676
if( ax > ay )
677
{
678
dy = (dy ^ j) - j;
679
pt1.x ^= pt2.x & j;
680
pt2.x ^= pt1.x & j;
681
pt1.x ^= pt2.x & j;
682
pt1.y ^= pt2.y & j;
683
pt2.y ^= pt1.y & j;
684
pt1.y ^= pt2.y & j;
685
686
x_step = XY_ONE;
687
y_step = (dy << XY_SHIFT) / (ax | 1);
688
ecount = (int)((pt2.x - pt1.x) >> XY_SHIFT);
689
}
690
else
691
{
692
dx = (dx ^ i) - i;
693
pt1.x ^= pt2.x & i;
694
pt2.x ^= pt1.x & i;
695
pt1.x ^= pt2.x & i;
696
pt1.y ^= pt2.y & i;
697
pt2.y ^= pt1.y & i;
698
pt1.y ^= pt2.y & i;
699
700
x_step = (dx << XY_SHIFT) / (ay | 1);
701
y_step = XY_ONE;
702
ecount = (int)((pt2.y - pt1.y) >> XY_SHIFT);
703
}
704
705
pt1.x += (XY_ONE >> 1);
706
pt1.y += (XY_ONE >> 1);
707
708
if( pix_size == 3 )
709
{
710
#define ICV_PUT_POINT(_x,_y) \
711
x = (_x); y = (_y); \
712
if( 0 <= x && x < size.width && \
713
0 <= y && y < size.height ) \
714
{ \
715
tptr = ptr + y*step + x*3; \
716
tptr[0] = (uchar)cb; \
717
tptr[1] = (uchar)cg; \
718
tptr[2] = (uchar)cr; \
719
}
720
721
ICV_PUT_POINT((int)((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT),
722
(int)((pt2.y + (XY_ONE >> 1)) >> XY_SHIFT));
723
724
if( ax > ay )
725
{
726
pt1.x >>= XY_SHIFT;
727
728
while( ecount >= 0 )
729
{
730
ICV_PUT_POINT((int)(pt1.x), (int)(pt1.y >> XY_SHIFT));
731
pt1.x++;
732
pt1.y += y_step;
733
ecount--;
734
}
735
}
736
else
737
{
738
pt1.y >>= XY_SHIFT;
739
740
while( ecount >= 0 )
741
{
742
ICV_PUT_POINT((int)(pt1.x >> XY_SHIFT), (int)(pt1.y));
743
pt1.x += x_step;
744
pt1.y++;
745
ecount--;
746
}
747
}
748
749
#undef ICV_PUT_POINT
750
}
751
else if( pix_size == 1 )
752
{
753
#define ICV_PUT_POINT(_x,_y) \
754
x = (_x); y = (_y); \
755
if( 0 <= x && x < size.width && \
756
0 <= y && y < size.height ) \
757
{ \
758
tptr = ptr + y*step + x;\
759
tptr[0] = (uchar)cb; \
760
}
761
762
ICV_PUT_POINT((int)((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT),
763
(int)((pt2.y + (XY_ONE >> 1)) >> XY_SHIFT));
764
765
if( ax > ay )
766
{
767
pt1.x >>= XY_SHIFT;
768
769
while( ecount >= 0 )
770
{
771
ICV_PUT_POINT((int)(pt1.x), (int)(pt1.y >> XY_SHIFT));
772
pt1.x++;
773
pt1.y += y_step;
774
ecount--;
775
}
776
}
777
else
778
{
779
pt1.y >>= XY_SHIFT;
780
781
while( ecount >= 0 )
782
{
783
ICV_PUT_POINT((int)(pt1.x >> XY_SHIFT), (int)(pt1.y));
784
pt1.x += x_step;
785
pt1.y++;
786
ecount--;
787
}
788
}
789
790
#undef ICV_PUT_POINT
791
}
792
else
793
{
794
#define ICV_PUT_POINT(_x,_y) \
795
x = (_x); y = (_y); \
796
if( 0 <= x && x < size.width && \
797
0 <= y && y < size.height ) \
798
{ \
799
tptr = ptr + y*step + x*pix_size;\
800
for( j = 0; j < pix_size; j++ ) \
801
tptr[j] = ((uchar*)color)[j]; \
802
}
803
804
ICV_PUT_POINT((int)((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT),
805
(int)((pt2.y + (XY_ONE >> 1)) >> XY_SHIFT));
806
807
if( ax > ay )
808
{
809
pt1.x >>= XY_SHIFT;
810
811
while( ecount >= 0 )
812
{
813
ICV_PUT_POINT((int)(pt1.x), (int)(pt1.y >> XY_SHIFT));
814
pt1.x++;
815
pt1.y += y_step;
816
ecount--;
817
}
818
}
819
else
820
{
821
pt1.y >>= XY_SHIFT;
822
823
while( ecount >= 0 )
824
{
825
ICV_PUT_POINT((int)(pt1.x >> XY_SHIFT), (int)(pt1.y));
826
pt1.x += x_step;
827
pt1.y++;
828
ecount--;
829
}
830
}
831
832
#undef ICV_PUT_POINT
833
}
834
}
835
836
837
/****************************************************************************************\
838
* Antialiazed Elliptic Arcs via Antialiazed Lines *
839
\****************************************************************************************/
840
841
static const float SinTable[] =
842
{ 0.0000000f, 0.0174524f, 0.0348995f, 0.0523360f, 0.0697565f, 0.0871557f,
843
0.1045285f, 0.1218693f, 0.1391731f, 0.1564345f, 0.1736482f, 0.1908090f,
844
0.2079117f, 0.2249511f, 0.2419219f, 0.2588190f, 0.2756374f, 0.2923717f,
845
0.3090170f, 0.3255682f, 0.3420201f, 0.3583679f, 0.3746066f, 0.3907311f,
846
0.4067366f, 0.4226183f, 0.4383711f, 0.4539905f, 0.4694716f, 0.4848096f,
847
0.5000000f, 0.5150381f, 0.5299193f, 0.5446390f, 0.5591929f, 0.5735764f,
848
0.5877853f, 0.6018150f, 0.6156615f, 0.6293204f, 0.6427876f, 0.6560590f,
849
0.6691306f, 0.6819984f, 0.6946584f, 0.7071068f, 0.7193398f, 0.7313537f,
850
0.7431448f, 0.7547096f, 0.7660444f, 0.7771460f, 0.7880108f, 0.7986355f,
851
0.8090170f, 0.8191520f, 0.8290376f, 0.8386706f, 0.8480481f, 0.8571673f,
852
0.8660254f, 0.8746197f, 0.8829476f, 0.8910065f, 0.8987940f, 0.9063078f,
853
0.9135455f, 0.9205049f, 0.9271839f, 0.9335804f, 0.9396926f, 0.9455186f,
854
0.9510565f, 0.9563048f, 0.9612617f, 0.9659258f, 0.9702957f, 0.9743701f,
855
0.9781476f, 0.9816272f, 0.9848078f, 0.9876883f, 0.9902681f, 0.9925462f,
856
0.9945219f, 0.9961947f, 0.9975641f, 0.9986295f, 0.9993908f, 0.9998477f,
857
1.0000000f, 0.9998477f, 0.9993908f, 0.9986295f, 0.9975641f, 0.9961947f,
858
0.9945219f, 0.9925462f, 0.9902681f, 0.9876883f, 0.9848078f, 0.9816272f,
859
0.9781476f, 0.9743701f, 0.9702957f, 0.9659258f, 0.9612617f, 0.9563048f,
860
0.9510565f, 0.9455186f, 0.9396926f, 0.9335804f, 0.9271839f, 0.9205049f,
861
0.9135455f, 0.9063078f, 0.8987940f, 0.8910065f, 0.8829476f, 0.8746197f,
862
0.8660254f, 0.8571673f, 0.8480481f, 0.8386706f, 0.8290376f, 0.8191520f,
863
0.8090170f, 0.7986355f, 0.7880108f, 0.7771460f, 0.7660444f, 0.7547096f,
864
0.7431448f, 0.7313537f, 0.7193398f, 0.7071068f, 0.6946584f, 0.6819984f,
865
0.6691306f, 0.6560590f, 0.6427876f, 0.6293204f, 0.6156615f, 0.6018150f,
866
0.5877853f, 0.5735764f, 0.5591929f, 0.5446390f, 0.5299193f, 0.5150381f,
867
0.5000000f, 0.4848096f, 0.4694716f, 0.4539905f, 0.4383711f, 0.4226183f,
868
0.4067366f, 0.3907311f, 0.3746066f, 0.3583679f, 0.3420201f, 0.3255682f,
869
0.3090170f, 0.2923717f, 0.2756374f, 0.2588190f, 0.2419219f, 0.2249511f,
870
0.2079117f, 0.1908090f, 0.1736482f, 0.1564345f, 0.1391731f, 0.1218693f,
871
0.1045285f, 0.0871557f, 0.0697565f, 0.0523360f, 0.0348995f, 0.0174524f,
872
0.0000000f, -0.0174524f, -0.0348995f, -0.0523360f, -0.0697565f, -0.0871557f,
873
-0.1045285f, -0.1218693f, -0.1391731f, -0.1564345f, -0.1736482f, -0.1908090f,
874
-0.2079117f, -0.2249511f, -0.2419219f, -0.2588190f, -0.2756374f, -0.2923717f,
875
-0.3090170f, -0.3255682f, -0.3420201f, -0.3583679f, -0.3746066f, -0.3907311f,
876
-0.4067366f, -0.4226183f, -0.4383711f, -0.4539905f, -0.4694716f, -0.4848096f,
877
-0.5000000f, -0.5150381f, -0.5299193f, -0.5446390f, -0.5591929f, -0.5735764f,
878
-0.5877853f, -0.6018150f, -0.6156615f, -0.6293204f, -0.6427876f, -0.6560590f,
879
-0.6691306f, -0.6819984f, -0.6946584f, -0.7071068f, -0.7193398f, -0.7313537f,
880
-0.7431448f, -0.7547096f, -0.7660444f, -0.7771460f, -0.7880108f, -0.7986355f,
881
-0.8090170f, -0.8191520f, -0.8290376f, -0.8386706f, -0.8480481f, -0.8571673f,
882
-0.8660254f, -0.8746197f, -0.8829476f, -0.8910065f, -0.8987940f, -0.9063078f,
883
-0.9135455f, -0.9205049f, -0.9271839f, -0.9335804f, -0.9396926f, -0.9455186f,
884
-0.9510565f, -0.9563048f, -0.9612617f, -0.9659258f, -0.9702957f, -0.9743701f,
885
-0.9781476f, -0.9816272f, -0.9848078f, -0.9876883f, -0.9902681f, -0.9925462f,
886
-0.9945219f, -0.9961947f, -0.9975641f, -0.9986295f, -0.9993908f, -0.9998477f,
887
-1.0000000f, -0.9998477f, -0.9993908f, -0.9986295f, -0.9975641f, -0.9961947f,
888
-0.9945219f, -0.9925462f, -0.9902681f, -0.9876883f, -0.9848078f, -0.9816272f,
889
-0.9781476f, -0.9743701f, -0.9702957f, -0.9659258f, -0.9612617f, -0.9563048f,
890
-0.9510565f, -0.9455186f, -0.9396926f, -0.9335804f, -0.9271839f, -0.9205049f,
891
-0.9135455f, -0.9063078f, -0.8987940f, -0.8910065f, -0.8829476f, -0.8746197f,
892
-0.8660254f, -0.8571673f, -0.8480481f, -0.8386706f, -0.8290376f, -0.8191520f,
893
-0.8090170f, -0.7986355f, -0.7880108f, -0.7771460f, -0.7660444f, -0.7547096f,
894
-0.7431448f, -0.7313537f, -0.7193398f, -0.7071068f, -0.6946584f, -0.6819984f,
895
-0.6691306f, -0.6560590f, -0.6427876f, -0.6293204f, -0.6156615f, -0.6018150f,
896
-0.5877853f, -0.5735764f, -0.5591929f, -0.5446390f, -0.5299193f, -0.5150381f,
897
-0.5000000f, -0.4848096f, -0.4694716f, -0.4539905f, -0.4383711f, -0.4226183f,
898
-0.4067366f, -0.3907311f, -0.3746066f, -0.3583679f, -0.3420201f, -0.3255682f,
899
-0.3090170f, -0.2923717f, -0.2756374f, -0.2588190f, -0.2419219f, -0.2249511f,
900
-0.2079117f, -0.1908090f, -0.1736482f, -0.1564345f, -0.1391731f, -0.1218693f,
901
-0.1045285f, -0.0871557f, -0.0697565f, -0.0523360f, -0.0348995f, -0.0174524f,
902
-0.0000000f, 0.0174524f, 0.0348995f, 0.0523360f, 0.0697565f, 0.0871557f,
903
0.1045285f, 0.1218693f, 0.1391731f, 0.1564345f, 0.1736482f, 0.1908090f,
904
0.2079117f, 0.2249511f, 0.2419219f, 0.2588190f, 0.2756374f, 0.2923717f,
905
0.3090170f, 0.3255682f, 0.3420201f, 0.3583679f, 0.3746066f, 0.3907311f,
906
0.4067366f, 0.4226183f, 0.4383711f, 0.4539905f, 0.4694716f, 0.4848096f,
907
0.5000000f, 0.5150381f, 0.5299193f, 0.5446390f, 0.5591929f, 0.5735764f,
908
0.5877853f, 0.6018150f, 0.6156615f, 0.6293204f, 0.6427876f, 0.6560590f,
909
0.6691306f, 0.6819984f, 0.6946584f, 0.7071068f, 0.7193398f, 0.7313537f,
910
0.7431448f, 0.7547096f, 0.7660444f, 0.7771460f, 0.7880108f, 0.7986355f,
911
0.8090170f, 0.8191520f, 0.8290376f, 0.8386706f, 0.8480481f, 0.8571673f,
912
0.8660254f, 0.8746197f, 0.8829476f, 0.8910065f, 0.8987940f, 0.9063078f,
913
0.9135455f, 0.9205049f, 0.9271839f, 0.9335804f, 0.9396926f, 0.9455186f,
914
0.9510565f, 0.9563048f, 0.9612617f, 0.9659258f, 0.9702957f, 0.9743701f,
915
0.9781476f, 0.9816272f, 0.9848078f, 0.9876883f, 0.9902681f, 0.9925462f,
916
0.9945219f, 0.9961947f, 0.9975641f, 0.9986295f, 0.9993908f, 0.9998477f,
917
1.0000000f
918
};
919
920
921
static void
922
sincos( int angle, float& cosval, float& sinval )
923
{
924
angle += (angle < 0 ? 360 : 0);
925
sinval = SinTable[angle];
926
cosval = SinTable[450 - angle];
927
}
928
929
/*
930
constructs polygon that represents elliptic arc.
931
*/
932
void ellipse2Poly( Point center, Size axes, int angle,
933
int arcStart, int arcEnd,
934
int delta, CV_OUT std::vector<Point>& pts )
935
{
936
std::vector<Point2d> _pts;
937
ellipse2Poly(Point2d(center.x, center.y), Size2d(axes.width, axes.height), angle,
938
arcStart, arcEnd, delta, _pts);
939
Point prevPt(INT_MIN, INT_MIN);
940
pts.resize(0);
941
for (unsigned int i = 0; i < _pts.size(); ++i)
942
{
943
Point pt;
944
pt.x = cvRound(_pts[i].x);
945
pt.y = cvRound(_pts[i].y);
946
if (pt != prevPt) {
947
pts.push_back(pt);
948
prevPt = pt;
949
}
950
}
951
952
// If there are no points, it's a zero-size polygon
953
if (pts.size() == 1) {
954
pts.assign(2, center);
955
}
956
}
957
958
void ellipse2Poly( Point2d center, Size2d axes, int angle,
959
int arc_start, int arc_end,
960
int delta, std::vector<Point2d>& pts )
961
{
962
CV_INSTRUMENT_REGION();
963
964
float alpha, beta;
965
int i;
966
967
while( angle < 0 )
968
angle += 360;
969
while( angle > 360 )
970
angle -= 360;
971
972
if( arc_start > arc_end )
973
{
974
i = arc_start;
975
arc_start = arc_end;
976
arc_end = i;
977
}
978
while( arc_start < 0 )
979
{
980
arc_start += 360;
981
arc_end += 360;
982
}
983
while( arc_end > 360 )
984
{
985
arc_end -= 360;
986
arc_start -= 360;
987
}
988
if( arc_end - arc_start > 360 )
989
{
990
arc_start = 0;
991
arc_end = 360;
992
}
993
sincos( angle, alpha, beta );
994
pts.resize(0);
995
996
for( i = arc_start; i < arc_end + delta; i += delta )
997
{
998
double x, y;
999
angle = i;
1000
if( angle > arc_end )
1001
angle = arc_end;
1002
if( angle < 0 )
1003
angle += 360;
1004
1005
x = axes.width * SinTable[450-angle];
1006
y = axes.height * SinTable[angle];
1007
Point2d pt;
1008
pt.x = center.x + x * alpha - y * beta;
1009
pt.y = center.y + x * beta + y * alpha;
1010
pts.push_back(pt);
1011
}
1012
1013
// If there are no points, it's a zero-size polygon
1014
if( pts.size() == 1) {
1015
pts.assign(2,center);
1016
}
1017
}
1018
1019
1020
static void
1021
EllipseEx( Mat& img, Point2l center, Size2l axes,
1022
int angle, int arc_start, int arc_end,
1023
const void* color, int thickness, int line_type )
1024
{
1025
axes.width = std::abs(axes.width), axes.height = std::abs(axes.height);
1026
int delta = (int)((std::max(axes.width,axes.height)+(XY_ONE>>1))>>XY_SHIFT);
1027
delta = delta < 3 ? 90 : delta < 10 ? 30 : delta < 15 ? 18 : 5;
1028
1029
std::vector<Point2d> _v;
1030
ellipse2Poly( Point2d((double)center.x, (double)center.y), Size2d((double)axes.width, (double)axes.height), angle, arc_start, arc_end, delta, _v );
1031
1032
std::vector<Point2l> v;
1033
Point2l prevPt(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF);
1034
v.resize(0);
1035
for (unsigned int i = 0; i < _v.size(); ++i)
1036
{
1037
Point2l pt;
1038
pt.x = (int64)cvRound(_v[i].x / XY_ONE) << XY_SHIFT;
1039
pt.y = (int64)cvRound(_v[i].y / XY_ONE) << XY_SHIFT;
1040
pt.x += cvRound(_v[i].x - pt.x);
1041
pt.y += cvRound(_v[i].y - pt.y);
1042
if (pt != prevPt) {
1043
v.push_back(pt);
1044
prevPt = pt;
1045
}
1046
}
1047
1048
// If there are no points, it's a zero-size polygon
1049
if (v.size() == 1) {
1050
v.assign(2, center);
1051
}
1052
1053
if( thickness >= 0 )
1054
PolyLine( img, &v[0], (int)v.size(), false, color, thickness, line_type, XY_SHIFT );
1055
else if( arc_end - arc_start >= 360 )
1056
FillConvexPoly( img, &v[0], (int)v.size(), color, line_type, XY_SHIFT );
1057
else
1058
{
1059
v.push_back(center);
1060
std::vector<PolyEdge> edges;
1061
CollectPolyEdges( img, &v[0], (int)v.size(), edges, color, line_type, XY_SHIFT );
1062
FillEdgeCollection( img, edges, color );
1063
}
1064
}
1065
1066
1067
/****************************************************************************************\
1068
* Polygons filling *
1069
\****************************************************************************************/
1070
1071
static inline void ICV_HLINE_X(uchar* ptr, int xl, int xr, const uchar* color, int pix_size)
1072
{
1073
uchar* hline_min_ptr = (uchar*)(ptr) + (xl)*(pix_size);
1074
uchar* hline_end_ptr = (uchar*)(ptr) + (xr+1)*(pix_size);
1075
uchar* hline_ptr = hline_min_ptr;
1076
if (pix_size == 1)
1077
memset(hline_min_ptr, *color, hline_end_ptr-hline_min_ptr);
1078
else//if (pix_size != 1)
1079
{
1080
if (hline_min_ptr < hline_end_ptr)
1081
{
1082
memcpy(hline_ptr, color, pix_size);
1083
hline_ptr += pix_size;
1084
}//end if (hline_min_ptr < hline_end_ptr)
1085
size_t sizeToCopy = pix_size;
1086
while(hline_ptr < hline_end_ptr)
1087
{
1088
memcpy(hline_ptr, hline_min_ptr, sizeToCopy);
1089
hline_ptr += sizeToCopy;
1090
sizeToCopy = std::min(2*sizeToCopy, static_cast<size_t>(hline_end_ptr-hline_ptr));
1091
}//end while(hline_ptr < hline_end_ptr)
1092
}//end if (pix_size != 1)
1093
}
1094
//end ICV_HLINE_X()
1095
1096
static inline void ICV_HLINE(uchar* ptr, int xl, int xr, const void* color, int pix_size)
1097
{
1098
ICV_HLINE_X(ptr, xl, xr, reinterpret_cast<const uchar*>(color), pix_size);
1099
}
1100
//end ICV_HLINE()
1101
1102
/* filling convex polygon. v - array of vertices, ntps - number of points */
1103
static void
1104
FillConvexPoly( Mat& img, const Point2l* v, int npts, const void* color, int line_type, int shift )
1105
{
1106
struct
1107
{
1108
int idx, di;
1109
int64 x, dx;
1110
int ye;
1111
}
1112
edge[2];
1113
1114
int delta = 1 << shift >> 1;
1115
int i, y, imin = 0;
1116
int edges = npts;
1117
int64 xmin, xmax, ymin, ymax;
1118
uchar* ptr = img.ptr();
1119
Size size = img.size();
1120
int pix_size = (int)img.elemSize();
1121
Point2l p0;
1122
int delta1, delta2;
1123
1124
if( line_type < CV_AA )
1125
delta1 = delta2 = XY_ONE >> 1;
1126
else
1127
delta1 = XY_ONE - 1, delta2 = 0;
1128
1129
p0 = v[npts - 1];
1130
p0.x <<= XY_SHIFT - shift;
1131
p0.y <<= XY_SHIFT - shift;
1132
1133
assert( 0 <= shift && shift <= XY_SHIFT );
1134
xmin = xmax = v[0].x;
1135
ymin = ymax = v[0].y;
1136
1137
for( i = 0; i < npts; i++ )
1138
{
1139
Point2l p = v[i];
1140
if( p.y < ymin )
1141
{
1142
ymin = p.y;
1143
imin = i;
1144
}
1145
1146
ymax = std::max( ymax, p.y );
1147
xmax = std::max( xmax, p.x );
1148
xmin = MIN( xmin, p.x );
1149
1150
p.x <<= XY_SHIFT - shift;
1151
p.y <<= XY_SHIFT - shift;
1152
1153
if( line_type <= 8 )
1154
{
1155
if( shift == 0 )
1156
{
1157
Point pt0, pt1;
1158
pt0.x = (int)(p0.x >> XY_SHIFT);
1159
pt0.y = (int)(p0.y >> XY_SHIFT);
1160
pt1.x = (int)(p.x >> XY_SHIFT);
1161
pt1.y = (int)(p.y >> XY_SHIFT);
1162
Line( img, pt0, pt1, color, line_type );
1163
}
1164
else
1165
Line2( img, p0, p, color );
1166
}
1167
else
1168
LineAA( img, p0, p, color );
1169
p0 = p;
1170
}
1171
1172
xmin = (xmin + delta) >> shift;
1173
xmax = (xmax + delta) >> shift;
1174
ymin = (ymin + delta) >> shift;
1175
ymax = (ymax + delta) >> shift;
1176
1177
if( npts < 3 || (int)xmax < 0 || (int)ymax < 0 || (int)xmin >= size.width || (int)ymin >= size.height )
1178
return;
1179
1180
ymax = MIN( ymax, size.height - 1 );
1181
edge[0].idx = edge[1].idx = imin;
1182
1183
edge[0].ye = edge[1].ye = y = (int)ymin;
1184
edge[0].di = 1;
1185
edge[1].di = npts - 1;
1186
1187
edge[0].x = edge[1].x = -XY_ONE;
1188
edge[0].dx = edge[1].dx = 0;
1189
1190
ptr += img.step*y;
1191
1192
do
1193
{
1194
if( line_type < CV_AA || y < (int)ymax || y == (int)ymin )
1195
{
1196
for( i = 0; i < 2; i++ )
1197
{
1198
if( y >= edge[i].ye )
1199
{
1200
int idx0 = edge[i].idx, di = edge[i].di;
1201
int idx = idx0 + di;
1202
if (idx >= npts) idx -= npts;
1203
int ty = 0;
1204
1205
for (; edges-- > 0; )
1206
{
1207
ty = (int)((v[idx].y + delta) >> shift);
1208
if (ty > y)
1209
{
1210
int64 xs = v[idx0].x;
1211
int64 xe = v[idx].x;
1212
if (shift != XY_SHIFT)
1213
{
1214
xs <<= XY_SHIFT - shift;
1215
xe <<= XY_SHIFT - shift;
1216
}
1217
1218
edge[i].ye = ty;
1219
edge[i].dx = ((xe - xs)*2 + (ty - y)) / (2 * (ty - y));
1220
edge[i].x = xs;
1221
edge[i].idx = idx;
1222
break;
1223
}
1224
idx0 = idx;
1225
idx += di;
1226
if (idx >= npts) idx -= npts;
1227
}
1228
}
1229
}
1230
}
1231
1232
if (edges < 0)
1233
break;
1234
1235
if (y >= 0)
1236
{
1237
int left = 0, right = 1;
1238
if (edge[0].x > edge[1].x)
1239
{
1240
left = 1, right = 0;
1241
}
1242
1243
int xx1 = (int)((edge[left].x + delta1) >> XY_SHIFT);
1244
int xx2 = (int)((edge[right].x + delta2) >> XY_SHIFT);
1245
1246
if( xx2 >= 0 && xx1 < size.width )
1247
{
1248
if( xx1 < 0 )
1249
xx1 = 0;
1250
if( xx2 >= size.width )
1251
xx2 = size.width - 1;
1252
ICV_HLINE( ptr, xx1, xx2, color, pix_size );
1253
}
1254
}
1255
else
1256
{
1257
// TODO optimize scan for negative y
1258
}
1259
1260
edge[0].x += edge[0].dx;
1261
edge[1].x += edge[1].dx;
1262
ptr += img.step;
1263
}
1264
while( ++y <= (int)ymax );
1265
}
1266
1267
1268
/******** Arbitrary polygon **********/
1269
1270
static void
1271
CollectPolyEdges( Mat& img, const Point2l* v, int count, std::vector<PolyEdge>& edges,
1272
const void* color, int line_type, int shift, Point offset )
1273
{
1274
int i, delta = offset.y + ((1 << shift) >> 1);
1275
Point2l pt0 = v[count-1], pt1;
1276
pt0.x = (pt0.x + offset.x) << (XY_SHIFT - shift);
1277
pt0.y = (pt0.y + delta) >> shift;
1278
1279
edges.reserve( edges.size() + count );
1280
1281
for( i = 0; i < count; i++, pt0 = pt1 )
1282
{
1283
Point2l t0, t1;
1284
PolyEdge edge;
1285
1286
pt1 = v[i];
1287
pt1.x = (pt1.x + offset.x) << (XY_SHIFT - shift);
1288
pt1.y = (pt1.y + delta) >> shift;
1289
1290
if( line_type < CV_AA )
1291
{
1292
t0.y = pt0.y; t1.y = pt1.y;
1293
t0.x = (pt0.x + (XY_ONE >> 1)) >> XY_SHIFT;
1294
t1.x = (pt1.x + (XY_ONE >> 1)) >> XY_SHIFT;
1295
Line( img, t0, t1, color, line_type );
1296
}
1297
else
1298
{
1299
t0.x = pt0.x; t1.x = pt1.x;
1300
t0.y = pt0.y << XY_SHIFT;
1301
t1.y = pt1.y << XY_SHIFT;
1302
LineAA( img, t0, t1, color );
1303
}
1304
1305
if( pt0.y == pt1.y )
1306
continue;
1307
1308
if( pt0.y < pt1.y )
1309
{
1310
edge.y0 = (int)(pt0.y);
1311
edge.y1 = (int)(pt1.y);
1312
edge.x = pt0.x;
1313
}
1314
else
1315
{
1316
edge.y0 = (int)(pt1.y);
1317
edge.y1 = (int)(pt0.y);
1318
edge.x = pt1.x;
1319
}
1320
edge.dx = (pt1.x - pt0.x) / (pt1.y - pt0.y);
1321
edges.push_back(edge);
1322
}
1323
}
1324
1325
struct CmpEdges
1326
{
1327
bool operator ()(const PolyEdge& e1, const PolyEdge& e2)
1328
{
1329
return e1.y0 - e2.y0 ? e1.y0 < e2.y0 :
1330
e1.x - e2.x ? e1.x < e2.x : e1.dx < e2.dx;
1331
}
1332
};
1333
1334
/**************** helper macros and functions for sequence/contour processing ***********/
1335
1336
static void
1337
FillEdgeCollection( Mat& img, std::vector<PolyEdge>& edges, const void* color )
1338
{
1339
PolyEdge tmp;
1340
int i, y, total = (int)edges.size();
1341
Size size = img.size();
1342
PolyEdge* e;
1343
int y_max = INT_MIN, y_min = INT_MAX;
1344
int64 x_max = 0xFFFFFFFFFFFFFFFF, x_min = 0x7FFFFFFFFFFFFFFF;
1345
int pix_size = (int)img.elemSize();
1346
1347
if( total < 2 )
1348
return;
1349
1350
for( i = 0; i < total; i++ )
1351
{
1352
PolyEdge& e1 = edges[i];
1353
assert( e1.y0 < e1.y1 );
1354
// Determine x-coordinate of the end of the edge.
1355
// (This is not necessary x-coordinate of any vertex in the array.)
1356
int64 x1 = e1.x + (e1.y1 - e1.y0) * e1.dx;
1357
y_min = std::min( y_min, e1.y0 );
1358
y_max = std::max( y_max, e1.y1 );
1359
x_min = std::min( x_min, e1.x );
1360
x_max = std::max( x_max, e1.x );
1361
x_min = std::min( x_min, x1 );
1362
x_max = std::max( x_max, x1 );
1363
}
1364
1365
if( y_max < 0 || y_min >= size.height || x_max < 0 || x_min >= ((int64)size.width<<XY_SHIFT) )
1366
return;
1367
1368
std::sort( edges.begin(), edges.end(), CmpEdges() );
1369
1370
// start drawing
1371
tmp.y0 = INT_MAX;
1372
edges.push_back(tmp); // after this point we do not add
1373
// any elements to edges, thus we can use pointers
1374
i = 0;
1375
tmp.next = 0;
1376
e = &edges[i];
1377
y_max = MIN( y_max, size.height );
1378
1379
for( y = e->y0; y < y_max; y++ )
1380
{
1381
PolyEdge *last, *prelast, *keep_prelast;
1382
int sort_flag = 0;
1383
int draw = 0;
1384
int clipline = y < 0;
1385
1386
prelast = &tmp;
1387
last = tmp.next;
1388
while( last || e->y0 == y )
1389
{
1390
if( last && last->y1 == y )
1391
{
1392
// exclude edge if y reaches its lower point
1393
prelast->next = last->next;
1394
last = last->next;
1395
continue;
1396
}
1397
keep_prelast = prelast;
1398
if( last && (e->y0 > y || last->x < e->x) )
1399
{
1400
// go to the next edge in active list
1401
prelast = last;
1402
last = last->next;
1403
}
1404
else if( i < total )
1405
{
1406
// insert new edge into active list if y reaches its upper point
1407
prelast->next = e;
1408
e->next = last;
1409
prelast = e;
1410
e = &edges[++i];
1411
}
1412
else
1413
break;
1414
1415
if( draw )
1416
{
1417
if( !clipline )
1418
{
1419
// convert x's from fixed-point to image coordinates
1420
uchar *timg = img.ptr(y);
1421
int x1, x2;
1422
1423
if (keep_prelast->x > prelast->x)
1424
{
1425
x1 = (int)((prelast->x + XY_ONE - 1) >> XY_SHIFT);
1426
x2 = (int)(keep_prelast->x >> XY_SHIFT);
1427
}
1428
else
1429
{
1430
x1 = (int)((keep_prelast->x + XY_ONE - 1) >> XY_SHIFT);
1431
x2 = (int)(prelast->x >> XY_SHIFT);
1432
}
1433
1434
// clip and draw the line
1435
if( x1 < size.width && x2 >= 0 )
1436
{
1437
if( x1 < 0 )
1438
x1 = 0;
1439
if( x2 >= size.width )
1440
x2 = size.width - 1;
1441
ICV_HLINE( timg, x1, x2, color, pix_size );
1442
}
1443
}
1444
keep_prelast->x += keep_prelast->dx;
1445
prelast->x += prelast->dx;
1446
}
1447
draw ^= 1;
1448
}
1449
1450
// sort edges (using bubble sort)
1451
keep_prelast = 0;
1452
1453
do
1454
{
1455
prelast = &tmp;
1456
last = tmp.next;
1457
1458
while( last != keep_prelast && last->next != 0 )
1459
{
1460
PolyEdge *te = last->next;
1461
1462
// swap edges
1463
if( last->x > te->x )
1464
{
1465
prelast->next = te;
1466
last->next = te->next;
1467
te->next = last;
1468
prelast = te;
1469
sort_flag = 1;
1470
}
1471
else
1472
{
1473
prelast = last;
1474
last = te;
1475
}
1476
}
1477
keep_prelast = prelast;
1478
}
1479
while( sort_flag && keep_prelast != tmp.next && keep_prelast != &tmp );
1480
}
1481
}
1482
1483
1484
/* draws simple or filled circle */
1485
static void
1486
Circle( Mat& img, Point center, int radius, const void* color, int fill )
1487
{
1488
Size size = img.size();
1489
size_t step = img.step;
1490
int pix_size = (int)img.elemSize();
1491
uchar* ptr = img.ptr();
1492
int err = 0, dx = radius, dy = 0, plus = 1, minus = (radius << 1) - 1;
1493
int inside = center.x >= radius && center.x < size.width - radius &&
1494
center.y >= radius && center.y < size.height - radius;
1495
1496
#define ICV_PUT_POINT( ptr, x ) \
1497
memcpy( ptr + (x)*pix_size, color, pix_size );
1498
1499
while( dx >= dy )
1500
{
1501
int mask;
1502
int y11 = center.y - dy, y12 = center.y + dy, y21 = center.y - dx, y22 = center.y + dx;
1503
int x11 = center.x - dx, x12 = center.x + dx, x21 = center.x - dy, x22 = center.x + dy;
1504
1505
if( inside )
1506
{
1507
uchar *tptr0 = ptr + y11 * step;
1508
uchar *tptr1 = ptr + y12 * step;
1509
1510
if( !fill )
1511
{
1512
ICV_PUT_POINT( tptr0, x11 );
1513
ICV_PUT_POINT( tptr1, x11 );
1514
ICV_PUT_POINT( tptr0, x12 );
1515
ICV_PUT_POINT( tptr1, x12 );
1516
}
1517
else
1518
{
1519
ICV_HLINE( tptr0, x11, x12, color, pix_size );
1520
ICV_HLINE( tptr1, x11, x12, color, pix_size );
1521
}
1522
1523
tptr0 = ptr + y21 * step;
1524
tptr1 = ptr + y22 * step;
1525
1526
if( !fill )
1527
{
1528
ICV_PUT_POINT( tptr0, x21 );
1529
ICV_PUT_POINT( tptr1, x21 );
1530
ICV_PUT_POINT( tptr0, x22 );
1531
ICV_PUT_POINT( tptr1, x22 );
1532
}
1533
else
1534
{
1535
ICV_HLINE( tptr0, x21, x22, color, pix_size );
1536
ICV_HLINE( tptr1, x21, x22, color, pix_size );
1537
}
1538
}
1539
else if( x11 < size.width && x12 >= 0 && y21 < size.height && y22 >= 0 )
1540
{
1541
if( fill )
1542
{
1543
x11 = std::max( x11, 0 );
1544
x12 = MIN( x12, size.width - 1 );
1545
}
1546
1547
if( (unsigned)y11 < (unsigned)size.height )
1548
{
1549
uchar *tptr = ptr + y11 * step;
1550
1551
if( !fill )
1552
{
1553
if( x11 >= 0 )
1554
ICV_PUT_POINT( tptr, x11 );
1555
if( x12 < size.width )
1556
ICV_PUT_POINT( tptr, x12 );
1557
}
1558
else
1559
ICV_HLINE( tptr, x11, x12, color, pix_size );
1560
}
1561
1562
if( (unsigned)y12 < (unsigned)size.height )
1563
{
1564
uchar *tptr = ptr + y12 * step;
1565
1566
if( !fill )
1567
{
1568
if( x11 >= 0 )
1569
ICV_PUT_POINT( tptr, x11 );
1570
if( x12 < size.width )
1571
ICV_PUT_POINT( tptr, x12 );
1572
}
1573
else
1574
ICV_HLINE( tptr, x11, x12, color, pix_size );
1575
}
1576
1577
if( x21 < size.width && x22 >= 0 )
1578
{
1579
if( fill )
1580
{
1581
x21 = std::max( x21, 0 );
1582
x22 = MIN( x22, size.width - 1 );
1583
}
1584
1585
if( (unsigned)y21 < (unsigned)size.height )
1586
{
1587
uchar *tptr = ptr + y21 * step;
1588
1589
if( !fill )
1590
{
1591
if( x21 >= 0 )
1592
ICV_PUT_POINT( tptr, x21 );
1593
if( x22 < size.width )
1594
ICV_PUT_POINT( tptr, x22 );
1595
}
1596
else
1597
ICV_HLINE( tptr, x21, x22, color, pix_size );
1598
}
1599
1600
if( (unsigned)y22 < (unsigned)size.height )
1601
{
1602
uchar *tptr = ptr + y22 * step;
1603
1604
if( !fill )
1605
{
1606
if( x21 >= 0 )
1607
ICV_PUT_POINT( tptr, x21 );
1608
if( x22 < size.width )
1609
ICV_PUT_POINT( tptr, x22 );
1610
}
1611
else
1612
ICV_HLINE( tptr, x21, x22, color, pix_size );
1613
}
1614
}
1615
}
1616
dy++;
1617
err += plus;
1618
plus += 2;
1619
1620
mask = (err <= 0) - 1;
1621
1622
err -= minus & mask;
1623
dx += mask;
1624
minus -= mask & 2;
1625
}
1626
1627
#undef ICV_PUT_POINT
1628
}
1629
1630
1631
static void
1632
ThickLine( Mat& img, Point2l p0, Point2l p1, const void* color,
1633
int thickness, int line_type, int flags, int shift )
1634
{
1635
static const double INV_XY_ONE = 1./XY_ONE;
1636
1637
p0.x <<= XY_SHIFT - shift;
1638
p0.y <<= XY_SHIFT - shift;
1639
p1.x <<= XY_SHIFT - shift;
1640
p1.y <<= XY_SHIFT - shift;
1641
1642
if( thickness <= 1 )
1643
{
1644
if( line_type < CV_AA )
1645
{
1646
if( line_type == 1 || line_type == 4 || shift == 0 )
1647
{
1648
p0.x = (p0.x + (XY_ONE>>1)) >> XY_SHIFT;
1649
p0.y = (p0.y + (XY_ONE>>1)) >> XY_SHIFT;
1650
p1.x = (p1.x + (XY_ONE>>1)) >> XY_SHIFT;
1651
p1.y = (p1.y + (XY_ONE>>1)) >> XY_SHIFT;
1652
Line( img, p0, p1, color, line_type );
1653
}
1654
else
1655
Line2( img, p0, p1, color );
1656
}
1657
else
1658
LineAA( img, p0, p1, color );
1659
}
1660
else
1661
{
1662
Point2l pt[4], dp = Point2l(0,0);
1663
double dx = (p0.x - p1.x)*INV_XY_ONE, dy = (p1.y - p0.y)*INV_XY_ONE;
1664
double r = dx * dx + dy * dy;
1665
int i, oddThickness = thickness & 1;
1666
thickness <<= XY_SHIFT - 1;
1667
1668
if( fabs(r) > DBL_EPSILON )
1669
{
1670
r = (thickness + oddThickness*XY_ONE*0.5)/std::sqrt(r);
1671
dp.x = cvRound( dy * r );
1672
dp.y = cvRound( dx * r );
1673
1674
pt[0].x = p0.x + dp.x;
1675
pt[0].y = p0.y + dp.y;
1676
pt[1].x = p0.x - dp.x;
1677
pt[1].y = p0.y - dp.y;
1678
pt[2].x = p1.x - dp.x;
1679
pt[2].y = p1.y - dp.y;
1680
pt[3].x = p1.x + dp.x;
1681
pt[3].y = p1.y + dp.y;
1682
1683
FillConvexPoly( img, pt, 4, color, line_type, XY_SHIFT );
1684
}
1685
1686
for( i = 0; i < 2; i++ )
1687
{
1688
if( flags & (i+1) )
1689
{
1690
if( line_type < CV_AA )
1691
{
1692
Point center;
1693
center.x = (int)((p0.x + (XY_ONE>>1)) >> XY_SHIFT);
1694
center.y = (int)((p0.y + (XY_ONE>>1)) >> XY_SHIFT);
1695
Circle( img, center, (thickness + (XY_ONE>>1)) >> XY_SHIFT, color, 1 );
1696
}
1697
else
1698
{
1699
EllipseEx( img, p0, Size2l(thickness, thickness),
1700
0, 0, 360, color, -1, line_type );
1701
}
1702
}
1703
p0 = p1;
1704
}
1705
}
1706
}
1707
1708
1709
static void
1710
PolyLine( Mat& img, const Point2l* v, int count, bool is_closed,
1711
const void* color, int thickness,
1712
int line_type, int shift )
1713
{
1714
if( !v || count <= 0 )
1715
return;
1716
1717
int i = is_closed ? count - 1 : 0;
1718
int flags = 2 + !is_closed;
1719
Point2l p0;
1720
CV_Assert( 0 <= shift && shift <= XY_SHIFT && thickness >= 0 );
1721
1722
p0 = v[i];
1723
for( i = !is_closed; i < count; i++ )
1724
{
1725
Point2l p = v[i];
1726
ThickLine( img, p0, p, color, thickness, line_type, flags, shift );
1727
p0 = p;
1728
flags = 2;
1729
}
1730
}
1731
1732
/* ----------------------------------------------------------------------------------------- */
1733
/* ADDING A SET OF PREDEFINED MARKERS WHICH COULD BE USED TO HIGHLIGHT POSITIONS IN AN IMAGE */
1734
/* ----------------------------------------------------------------------------------------- */
1735
1736
void drawMarker(InputOutputArray img, Point position, const Scalar& color, int markerType, int markerSize, int thickness, int line_type)
1737
{
1738
switch(markerType)
1739
{
1740
// The cross marker case
1741
case MARKER_CROSS:
1742
line(img, Point(position.x-(markerSize/2), position.y), Point(position.x+(markerSize/2), position.y), color, thickness, line_type);
1743
line(img, Point(position.x, position.y-(markerSize/2)), Point(position.x, position.y+(markerSize/2)), color, thickness, line_type);
1744
break;
1745
1746
// The tilted cross marker case
1747
case MARKER_TILTED_CROSS:
1748
line(img, Point(position.x-(markerSize/2), position.y-(markerSize/2)), Point(position.x+(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type);
1749
line(img, Point(position.x+(markerSize/2), position.y-(markerSize/2)), Point(position.x-(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type);
1750
break;
1751
1752
// The star marker case
1753
case MARKER_STAR:
1754
line(img, Point(position.x-(markerSize/2), position.y), Point(position.x+(markerSize/2), position.y), color, thickness, line_type);
1755
line(img, Point(position.x, position.y-(markerSize/2)), Point(position.x, position.y+(markerSize/2)), color, thickness, line_type);
1756
line(img, Point(position.x-(markerSize/2), position.y-(markerSize/2)), Point(position.x+(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type);
1757
line(img, Point(position.x+(markerSize/2), position.y-(markerSize/2)), Point(position.x-(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type);
1758
break;
1759
1760
// The diamond marker case
1761
case MARKER_DIAMOND:
1762
line(img, Point(position.x, position.y-(markerSize/2)), Point(position.x+(markerSize/2), position.y), color, thickness, line_type);
1763
line(img, Point(position.x+(markerSize/2), position.y), Point(position.x, position.y+(markerSize/2)), color, thickness, line_type);
1764
line(img, Point(position.x, position.y+(markerSize/2)), Point(position.x-(markerSize/2), position.y), color, thickness, line_type);
1765
line(img, Point(position.x-(markerSize/2), position.y), Point(position.x, position.y-(markerSize/2)), color, thickness, line_type);
1766
break;
1767
1768
// The square marker case
1769
case MARKER_SQUARE:
1770
line(img, Point(position.x-(markerSize/2), position.y-(markerSize/2)), Point(position.x+(markerSize/2), position.y-(markerSize/2)), color, thickness, line_type);
1771
line(img, Point(position.x+(markerSize/2), position.y-(markerSize/2)), Point(position.x+(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type);
1772
line(img, Point(position.x+(markerSize/2), position.y+(markerSize/2)), Point(position.x-(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type);
1773
line(img, Point(position.x-(markerSize/2), position.y+(markerSize/2)), Point(position.x-(markerSize/2), position.y-(markerSize/2)), color, thickness, line_type);
1774
break;
1775
1776
// The triangle up marker case
1777
case MARKER_TRIANGLE_UP:
1778
line(img, Point(position.x-(markerSize/2), position.y+(markerSize/2)), Point(position.x+(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type);
1779
line(img, Point(position.x+(markerSize/2), position.y+(markerSize/2)), Point(position.x, position.y-(markerSize/2)), color, thickness, line_type);
1780
line(img, Point(position.x, position.y-(markerSize/2)), Point(position.x-(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type);
1781
break;
1782
1783
// The triangle down marker case
1784
case MARKER_TRIANGLE_DOWN:
1785
line(img, Point(position.x-(markerSize/2), position.y-(markerSize/2)), Point(position.x+(markerSize/2), position.y-(markerSize/2)), color, thickness, line_type);
1786
line(img, Point(position.x+(markerSize/2), position.y-(markerSize/2)), Point(position.x, position.y+(markerSize/2)), color, thickness, line_type);
1787
line(img, Point(position.x, position.y+(markerSize/2)), Point(position.x-(markerSize/2), position.y-(markerSize/2)), color, thickness, line_type);
1788
break;
1789
1790
// If any number that doesn't exist is entered as marker type, draw a cross marker, to avoid crashes
1791
default:
1792
drawMarker(img, position, color, MARKER_CROSS, markerSize, thickness, line_type);
1793
break;
1794
}
1795
}
1796
1797
/****************************************************************************************\
1798
* External functions *
1799
\****************************************************************************************/
1800
1801
void line( InputOutputArray _img, Point pt1, Point pt2, const Scalar& color,
1802
int thickness, int line_type, int shift )
1803
{
1804
CV_INSTRUMENT_REGION();
1805
1806
Mat img = _img.getMat();
1807
1808
if( line_type == CV_AA && img.depth() != CV_8U )
1809
line_type = 8;
1810
1811
CV_Assert( 0 < thickness && thickness <= MAX_THICKNESS );
1812
CV_Assert( 0 <= shift && shift <= XY_SHIFT );
1813
1814
double buf[4];
1815
scalarToRawData( color, buf, img.type(), 0 );
1816
ThickLine( img, pt1, pt2, buf, thickness, line_type, 3, shift );
1817
}
1818
1819
void arrowedLine(InputOutputArray img, Point pt1, Point pt2, const Scalar& color,
1820
int thickness, int line_type, int shift, double tipLength)
1821
{
1822
CV_INSTRUMENT_REGION();
1823
1824
const double tipSize = norm(pt1-pt2)*tipLength; // Factor to normalize the size of the tip depending on the length of the arrow
1825
1826
line(img, pt1, pt2, color, thickness, line_type, shift);
1827
1828
const double angle = atan2( (double) pt1.y - pt2.y, (double) pt1.x - pt2.x );
1829
1830
Point p(cvRound(pt2.x + tipSize * cos(angle + CV_PI / 4)),
1831
cvRound(pt2.y + tipSize * sin(angle + CV_PI / 4)));
1832
line(img, p, pt2, color, thickness, line_type, shift);
1833
1834
p.x = cvRound(pt2.x + tipSize * cos(angle - CV_PI / 4));
1835
p.y = cvRound(pt2.y + tipSize * sin(angle - CV_PI / 4));
1836
line(img, p, pt2, color, thickness, line_type, shift);
1837
}
1838
1839
void rectangle( InputOutputArray _img, Point pt1, Point pt2,
1840
const Scalar& color, int thickness,
1841
int lineType, int shift )
1842
{
1843
CV_INSTRUMENT_REGION();
1844
1845
Mat img = _img.getMat();
1846
1847
if( lineType == CV_AA && img.depth() != CV_8U )
1848
lineType = 8;
1849
1850
CV_Assert( thickness <= MAX_THICKNESS );
1851
CV_Assert( 0 <= shift && shift <= XY_SHIFT );
1852
1853
double buf[4];
1854
scalarToRawData(color, buf, img.type(), 0);
1855
1856
Point2l pt[4];
1857
1858
pt[0] = pt1;
1859
pt[1].x = pt2.x;
1860
pt[1].y = pt1.y;
1861
pt[2] = pt2;
1862
pt[3].x = pt1.x;
1863
pt[3].y = pt2.y;
1864
1865
if( thickness >= 0 )
1866
PolyLine( img, pt, 4, true, buf, thickness, lineType, shift );
1867
else
1868
FillConvexPoly( img, pt, 4, buf, lineType, shift );
1869
}
1870
1871
1872
void rectangle( InputOutputArray img, Rect rec,
1873
const Scalar& color, int thickness,
1874
int lineType, int shift )
1875
{
1876
CV_INSTRUMENT_REGION();
1877
1878
if( !rec.empty() )
1879
rectangle( img, rec.tl(), rec.br() - Point(1<<shift,1<<shift),
1880
color, thickness, lineType, shift );
1881
}
1882
1883
1884
void circle( InputOutputArray _img, Point center, int radius,
1885
const Scalar& color, int thickness, int line_type, int shift )
1886
{
1887
CV_INSTRUMENT_REGION();
1888
1889
Mat img = _img.getMat();
1890
1891
if( line_type == CV_AA && img.depth() != CV_8U )
1892
line_type = 8;
1893
1894
CV_Assert( radius >= 0 && thickness <= MAX_THICKNESS &&
1895
0 <= shift && shift <= XY_SHIFT );
1896
1897
double buf[4];
1898
scalarToRawData(color, buf, img.type(), 0);
1899
1900
if( thickness > 1 || line_type != LINE_8 || shift > 0 )
1901
{
1902
Point2l _center(center);
1903
int64 _radius(radius);
1904
_center.x <<= XY_SHIFT - shift;
1905
_center.y <<= XY_SHIFT - shift;
1906
_radius <<= XY_SHIFT - shift;
1907
EllipseEx( img, _center, Size2l(_radius, _radius),
1908
0, 0, 360, buf, thickness, line_type );
1909
}
1910
else
1911
Circle( img, center, radius, buf, thickness < 0 );
1912
}
1913
1914
1915
void ellipse( InputOutputArray _img, Point center, Size axes,
1916
double angle, double start_angle, double end_angle,
1917
const Scalar& color, int thickness, int line_type, int shift )
1918
{
1919
CV_INSTRUMENT_REGION();
1920
1921
Mat img = _img.getMat();
1922
1923
if( line_type == CV_AA && img.depth() != CV_8U )
1924
line_type = 8;
1925
1926
CV_Assert( axes.width >= 0 && axes.height >= 0 &&
1927
thickness <= MAX_THICKNESS && 0 <= shift && shift <= XY_SHIFT );
1928
1929
double buf[4];
1930
scalarToRawData(color, buf, img.type(), 0);
1931
1932
int _angle = cvRound(angle);
1933
int _start_angle = cvRound(start_angle);
1934
int _end_angle = cvRound(end_angle);
1935
Point2l _center(center);
1936
Size2l _axes(axes);
1937
_center.x <<= XY_SHIFT - shift;
1938
_center.y <<= XY_SHIFT - shift;
1939
_axes.width <<= XY_SHIFT - shift;
1940
_axes.height <<= XY_SHIFT - shift;
1941
1942
EllipseEx( img, _center, _axes, _angle, _start_angle,
1943
_end_angle, buf, thickness, line_type );
1944
}
1945
1946
void ellipse(InputOutputArray _img, const RotatedRect& box, const Scalar& color,
1947
int thickness, int lineType)
1948
{
1949
CV_INSTRUMENT_REGION();
1950
1951
Mat img = _img.getMat();
1952
1953
if( lineType == CV_AA && img.depth() != CV_8U )
1954
lineType = 8;
1955
1956
CV_Assert( box.size.width >= 0 && box.size.height >= 0 &&
1957
thickness <= MAX_THICKNESS );
1958
1959
double buf[4];
1960
scalarToRawData(color, buf, img.type(), 0);
1961
1962
int _angle = cvRound(box.angle);
1963
Point2l center(cvRound(box.center.x),
1964
cvRound(box.center.y));
1965
center.x = (center.x << XY_SHIFT) + cvRound((box.center.x - center.x)*XY_ONE);
1966
center.y = (center.y << XY_SHIFT) + cvRound((box.center.y - center.y)*XY_ONE);
1967
Size2l axes(cvRound(box.size.width),
1968
cvRound(box.size.height));
1969
axes.width = (axes.width << (XY_SHIFT - 1)) + cvRound((box.size.width - axes.width)*(XY_ONE>>1));
1970
axes.height = (axes.height << (XY_SHIFT - 1)) + cvRound((box.size.height - axes.height)*(XY_ONE>>1));
1971
EllipseEx( img, center, axes, _angle, 0, 360, buf, thickness, lineType );
1972
}
1973
1974
void fillConvexPoly( Mat& img, const Point* pts, int npts,
1975
const Scalar& color, int line_type, int shift )
1976
{
1977
CV_INSTRUMENT_REGION();
1978
1979
if( !pts || npts <= 0 )
1980
return;
1981
1982
if( line_type == CV_AA && img.depth() != CV_8U )
1983
line_type = 8;
1984
1985
double buf[4];
1986
CV_Assert( 0 <= shift && shift <= XY_SHIFT );
1987
scalarToRawData(color, buf, img.type(), 0);
1988
std::vector<Point2l> _pts(pts, pts + npts);
1989
FillConvexPoly( img, _pts.data(), npts, buf, line_type, shift );
1990
}
1991
1992
1993
void fillPoly( Mat& img, const Point** pts, const int* npts, int ncontours,
1994
const Scalar& color, int line_type,
1995
int shift, Point offset )
1996
{
1997
CV_INSTRUMENT_REGION();
1998
1999
if( line_type == CV_AA && img.depth() != CV_8U )
2000
line_type = 8;
2001
2002
CV_Assert( pts && npts && ncontours >= 0 && 0 <= shift && shift <= XY_SHIFT );
2003
2004
double buf[4];
2005
scalarToRawData(color, buf, img.type(), 0);
2006
2007
std::vector<PolyEdge> edges;
2008
2009
int i, total = 0;
2010
for( i = 0; i < ncontours; i++ )
2011
total += npts[i];
2012
2013
edges.reserve( total + 1 );
2014
for (i = 0; i < ncontours; i++)
2015
{
2016
std::vector<Point2l> _pts(pts[i], pts[i] + npts[i]);
2017
CollectPolyEdges(img, _pts.data(), npts[i], edges, buf, line_type, shift, offset);
2018
}
2019
2020
FillEdgeCollection(img, edges, buf);
2021
}
2022
2023
2024
void polylines( Mat& img, const Point* const* pts, const int* npts, int ncontours, bool isClosed,
2025
const Scalar& color, int thickness, int line_type, int shift )
2026
{
2027
CV_INSTRUMENT_REGION();
2028
2029
if( line_type == CV_AA && img.depth() != CV_8U )
2030
line_type = 8;
2031
2032
CV_Assert( pts && npts && ncontours >= 0 &&
2033
0 <= thickness && thickness <= MAX_THICKNESS &&
2034
0 <= shift && shift <= XY_SHIFT );
2035
2036
double buf[4];
2037
scalarToRawData( color, buf, img.type(), 0 );
2038
2039
for( int i = 0; i < ncontours; i++ )
2040
{
2041
std::vector<Point2l> _pts(pts[i], pts[i]+npts[i]);
2042
PolyLine( img, _pts.data(), npts[i], isClosed, buf, thickness, line_type, shift );
2043
}
2044
}
2045
2046
2047
enum { FONT_SIZE_SHIFT=8, FONT_ITALIC_ALPHA=(1 << 8),
2048
FONT_ITALIC_DIGIT=(2 << 8), FONT_ITALIC_PUNCT=(4 << 8),
2049
FONT_ITALIC_BRACES=(8 << 8), FONT_HAVE_GREEK=(16 << 8),
2050
FONT_HAVE_CYRILLIC=(32 << 8) };
2051
2052
static const int HersheyPlain[] = {
2053
(5 + 4*16) + FONT_HAVE_GREEK,
2054
199, 214, 217, 233, 219, 197, 234, 216, 221, 222, 228, 225, 211, 224, 210, 220,
2055
200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 212, 213, 191, 226, 192,
2056
215, 190, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
2057
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 193, 84,
2058
194, 85, 86, 87, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
2059
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
2060
195, 223, 196, 88 };
2061
2062
static const int HersheyPlainItalic[] = {
2063
(5 + 4*16) + FONT_ITALIC_ALPHA + FONT_HAVE_GREEK,
2064
199, 214, 217, 233, 219, 197, 234, 216, 221, 222, 228, 225, 211, 224, 210, 220,
2065
200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 212, 213, 191, 226, 192,
2066
215, 190, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
2067
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 193, 84,
2068
194, 85, 86, 87, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161,
2069
162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176,
2070
195, 223, 196, 88 };
2071
2072
static const int HersheyComplexSmall[] = {
2073
(6 + 7*16) + FONT_HAVE_GREEK,
2074
1199, 1214, 1217, 1275, 1274, 1271, 1272, 1216, 1221, 1222, 1219, 1232, 1211, 1231, 1210, 1220,
2075
1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1212, 2213, 1241, 1238, 1242,
2076
1215, 1273, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013,
2077
1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1223, 1084,
2078
1224, 1247, 586, 1249, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111,
2079
1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126,
2080
1225, 1229, 1226, 1246 };
2081
2082
static const int HersheyComplexSmallItalic[] = {
2083
(6 + 7*16) + FONT_ITALIC_ALPHA + FONT_HAVE_GREEK,
2084
1199, 1214, 1217, 1275, 1274, 1271, 1272, 1216, 1221, 1222, 1219, 1232, 1211, 1231, 1210, 1220,
2085
1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1212, 1213, 1241, 1238, 1242,
2086
1215, 1273, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063,
2087
1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1223, 1084,
2088
1224, 1247, 586, 1249, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161,
2089
1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176,
2090
1225, 1229, 1226, 1246 };
2091
2092
static const int HersheySimplex[] = {
2093
(9 + 12*16) + FONT_HAVE_GREEK,
2094
2199, 714, 717, 733, 719, 697, 734, 716, 721, 722, 728, 725, 711, 724, 710, 720,
2095
700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 712, 713, 691, 726, 692,
2096
715, 690, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513,
2097
514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 693, 584,
2098
694, 2247, 586, 2249, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611,
2099
612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626,
2100
695, 723, 696, 2246 };
2101
2102
static const int HersheyDuplex[] = {
2103
(9 + 12*16) + FONT_HAVE_GREEK,
2104
2199, 2714, 2728, 2732, 2719, 2733, 2718, 2727, 2721, 2722, 2723, 2725, 2711, 2724, 2710, 2720,
2105
2700, 2701, 2702, 2703, 2704, 2705, 2706, 2707, 2708, 2709, 2712, 2713, 2730, 2726, 2731,
2106
2715, 2734, 2501, 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2509, 2510, 2511, 2512, 2513,
2107
2514, 2515, 2516, 2517, 2518, 2519, 2520, 2521, 2522, 2523, 2524, 2525, 2526, 2223, 2084,
2108
2224, 2247, 587, 2249, 2601, 2602, 2603, 2604, 2605, 2606, 2607, 2608, 2609, 2610, 2611,
2109
2612, 2613, 2614, 2615, 2616, 2617, 2618, 2619, 2620, 2621, 2622, 2623, 2624, 2625, 2626,
2110
2225, 2229, 2226, 2246 };
2111
2112
static const int HersheyComplex[] = {
2113
(9 + 12*16) + FONT_HAVE_GREEK + FONT_HAVE_CYRILLIC,
2114
2199, 2214, 2217, 2275, 2274, 2271, 2272, 2216, 2221, 2222, 2219, 2232, 2211, 2231, 2210, 2220,
2115
2200, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2212, 2213, 2241, 2238, 2242,
2116
2215, 2273, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
2117
2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2223, 2084,
2118
2224, 2247, 587, 2249, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111,
2119
2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 2122, 2123, 2124, 2125, 2126,
2120
2225, 2229, 2226, 2246, 2801, 2802, 2803, 2804, 2805, 2806, 2807, 2808, 2809, 2810, 2811,
2121
2812, 2813, 2814, 2815, 2816, 2817, 2818, 2819, 2820, 2821, 2822, 2823, 2824, 2825, 2826,
2122
2827, 2828, 2829, 2830, 2831, 2832, 2901, 2902, 2903, 2904, 2905, 2906, 2907, 2908, 2909,
2123
2910, 2911, 2912, 2913, 2914, 2915, 2916, 2917, 2918, 2919, 2920, 2921, 2922, 2923, 2924,
2124
2925, 2926, 2927, 2928, 2929, 2930, 2931, 2932};
2125
2126
static const int HersheyComplexItalic[] = {
2127
(9 + 12*16) + FONT_ITALIC_ALPHA + FONT_ITALIC_DIGIT + FONT_ITALIC_PUNCT +
2128
FONT_HAVE_GREEK + FONT_HAVE_CYRILLIC,
2129
2199, 2764, 2778, 2782, 2769, 2783, 2768, 2777, 2771, 2772, 2219, 2232, 2211, 2231, 2210, 2220,
2130
2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2212, 2213, 2241, 2238, 2242,
2131
2765, 2273, 2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063,
2132
2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2223, 2084,
2133
2224, 2247, 587, 2249, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161,
2134
2162, 2163, 2164, 2165, 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2176,
2135
2225, 2229, 2226, 2246 };
2136
2137
static const int HersheyTriplex[] = {
2138
(9 + 12*16) + FONT_HAVE_GREEK,
2139
2199, 3214, 3228, 3232, 3219, 3233, 3218, 3227, 3221, 3222, 3223, 3225, 3211, 3224, 3210, 3220,
2140
3200, 3201, 3202, 3203, 3204, 3205, 3206, 3207, 3208, 3209, 3212, 3213, 3230, 3226, 3231,
2141
3215, 3234, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011, 3012, 3013,
2142
2014, 3015, 3016, 3017, 3018, 3019, 3020, 3021, 3022, 3023, 3024, 3025, 3026, 2223, 2084,
2143
2224, 2247, 587, 2249, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, 3111,
2144
3112, 3113, 3114, 3115, 3116, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124, 3125, 3126,
2145
2225, 2229, 2226, 2246 };
2146
2147
static const int HersheyTriplexItalic[] = {
2148
(9 + 12*16) + FONT_ITALIC_ALPHA + FONT_ITALIC_DIGIT +
2149
FONT_ITALIC_PUNCT + FONT_HAVE_GREEK,
2150
2199, 3264, 3278, 3282, 3269, 3233, 3268, 3277, 3271, 3272, 3223, 3225, 3261, 3224, 3260, 3270,
2151
3250, 3251, 3252, 3253, 3254, 3255, 3256, 3257, 3258, 3259, 3262, 3263, 3230, 3226, 3231,
2152
3265, 3234, 3051, 3052, 3053, 3054, 3055, 3056, 3057, 3058, 3059, 3060, 3061, 3062, 3063,
2153
2064, 3065, 3066, 3067, 3068, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3076, 2223, 2084,
2154
2224, 2247, 587, 2249, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3159, 3160, 3161,
2155
3162, 3163, 3164, 3165, 3166, 3167, 3168, 3169, 3170, 3171, 3172, 3173, 3174, 3175, 3176,
2156
2225, 2229, 2226, 2246 };
2157
2158
static const int HersheyScriptSimplex[] = {
2159
(9 + 12*16) + FONT_ITALIC_ALPHA + FONT_HAVE_GREEK,
2160
2199, 714, 717, 733, 719, 697, 734, 716, 721, 722, 728, 725, 711, 724, 710, 720,
2161
700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 712, 713, 691, 726, 692,
2162
715, 690, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563,
2163
564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 693, 584,
2164
694, 2247, 586, 2249, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661,
2165
662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676,
2166
695, 723, 696, 2246 };
2167
2168
static const int HersheyScriptComplex[] = {
2169
(9 + 12*16) + FONT_ITALIC_ALPHA + FONT_ITALIC_DIGIT + FONT_ITALIC_PUNCT + FONT_HAVE_GREEK,
2170
2199, 2764, 2778, 2782, 2769, 2783, 2768, 2777, 2771, 2772, 2219, 2232, 2211, 2231, 2210, 2220,
2171
2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2212, 2213, 2241, 2238, 2242,
2172
2215, 2273, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563,
2173
2564, 2565, 2566, 2567, 2568, 2569, 2570, 2571, 2572, 2573, 2574, 2575, 2576, 2223, 2084,
2174
2224, 2247, 586, 2249, 2651, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661,
2175
2662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2676,
2176
2225, 2229, 2226, 2246 };
2177
2178
2179
static const int* getFontData(int fontFace)
2180
{
2181
bool isItalic = (fontFace & FONT_ITALIC) != 0;
2182
const int* ascii = 0;
2183
2184
switch( fontFace & 15 )
2185
{
2186
case FONT_HERSHEY_SIMPLEX:
2187
ascii = HersheySimplex;
2188
break;
2189
case FONT_HERSHEY_PLAIN:
2190
ascii = !isItalic ? HersheyPlain : HersheyPlainItalic;
2191
break;
2192
case FONT_HERSHEY_DUPLEX:
2193
ascii = HersheyDuplex;
2194
break;
2195
case FONT_HERSHEY_COMPLEX:
2196
ascii = !isItalic ? HersheyComplex : HersheyComplexItalic;
2197
break;
2198
case FONT_HERSHEY_TRIPLEX:
2199
ascii = !isItalic ? HersheyTriplex : HersheyTriplexItalic;
2200
break;
2201
case FONT_HERSHEY_COMPLEX_SMALL:
2202
ascii = !isItalic ? HersheyComplexSmall : HersheyComplexSmallItalic;
2203
break;
2204
case FONT_HERSHEY_SCRIPT_SIMPLEX:
2205
ascii = HersheyScriptSimplex;
2206
break;
2207
case FONT_HERSHEY_SCRIPT_COMPLEX:
2208
ascii = HersheyScriptComplex;
2209
break;
2210
default:
2211
CV_Error( CV_StsOutOfRange, "Unknown font type" );
2212
}
2213
return ascii;
2214
}
2215
2216
inline void readCheck(int &c, int &i, const String &text, int fontFace)
2217
{
2218
2219
int leftBoundary = ' ', rightBoundary = 127;
2220
2221
if(c >= 0x80 && fontFace == FONT_HERSHEY_COMPLEX)
2222
{
2223
if(c == 0xD0 && (uchar)text[i + 1] >= 0x90 && (uchar)text[i + 1] <= 0xBF)
2224
{
2225
c = (uchar)text[++i] - 17;
2226
leftBoundary = 127;
2227
rightBoundary = 175;
2228
}
2229
else if(c == 0xD1 && (uchar)text[i + 1] >= 0x80 && (uchar)text[i + 1] <= 0x8F)
2230
{
2231
c = (uchar)text[++i] + 47;
2232
leftBoundary = 175;
2233
rightBoundary = 191;
2234
}
2235
else
2236
{
2237
if(c >= 0xC0 && text[i+1] != 0) //2 bytes utf
2238
i++;
2239
2240
if(c >= 0xE0 && text[i+1] != 0) //3 bytes utf
2241
i++;
2242
2243
if(c >= 0xF0 && text[i+1] != 0) //4 bytes utf
2244
i++;
2245
2246
if(c >= 0xF8 && text[i+1] != 0) //5 bytes utf
2247
i++;
2248
2249
if(c >= 0xFC && text[i+1] != 0) //6 bytes utf
2250
i++;
2251
2252
c = '?';
2253
}
2254
}
2255
2256
if(c >= rightBoundary || c < leftBoundary)
2257
c = '?';
2258
}
2259
2260
extern const char* g_HersheyGlyphs[];
2261
2262
void putText( InputOutputArray _img, const String& text, Point org,
2263
int fontFace, double fontScale, Scalar color,
2264
int thickness, int line_type, bool bottomLeftOrigin )
2265
2266
{
2267
CV_INSTRUMENT_REGION();
2268
2269
if ( text.empty() )
2270
{
2271
return;
2272
}
2273
Mat img = _img.getMat();
2274
const int* ascii = getFontData(fontFace);
2275
2276
double buf[4];
2277
scalarToRawData(color, buf, img.type(), 0);
2278
2279
int base_line = -(ascii[0] & 15);
2280
int hscale = cvRound(fontScale*XY_ONE), vscale = hscale;
2281
2282
if( line_type == CV_AA && img.depth() != CV_8U )
2283
line_type = 8;
2284
2285
if( bottomLeftOrigin )
2286
vscale = -vscale;
2287
2288
int64 view_x = (int64)org.x << XY_SHIFT;
2289
int64 view_y = ((int64)org.y << XY_SHIFT) + base_line*vscale;
2290
std::vector<Point2l> pts;
2291
pts.reserve(1 << 10);
2292
const char **faces = cv::g_HersheyGlyphs;
2293
2294
for( int i = 0; i < (int)text.size(); i++ )
2295
{
2296
int c = (uchar)text[i];
2297
Point2l p;
2298
2299
readCheck(c, i, text, fontFace);
2300
2301
const char* ptr = faces[ascii[(c-' ')+1]];
2302
p.x = (uchar)ptr[0] - 'R';
2303
p.y = (uchar)ptr[1] - 'R';
2304
int64 dx = p.y*hscale;
2305
view_x -= p.x*hscale;
2306
pts.resize(0);
2307
2308
for( ptr += 2;; )
2309
{
2310
if( *ptr == ' ' || !*ptr )
2311
{
2312
if( pts.size() > 1 )
2313
PolyLine( img, &pts[0], (int)pts.size(), false, buf, thickness, line_type, XY_SHIFT );
2314
if( !*ptr++ )
2315
break;
2316
pts.resize(0);
2317
}
2318
else
2319
{
2320
p.x = (uchar)ptr[0] - 'R';
2321
p.y = (uchar)ptr[1] - 'R';
2322
ptr += 2;
2323
pts.push_back(Point2l(p.x*hscale + view_x, p.y*vscale + view_y));
2324
}
2325
}
2326
view_x += dx;
2327
}
2328
}
2329
2330
Size getTextSize( const String& text, int fontFace, double fontScale, int thickness, int* _base_line)
2331
{
2332
Size size;
2333
double view_x = 0;
2334
const char **faces = cv::g_HersheyGlyphs;
2335
const int* ascii = getFontData(fontFace);
2336
2337
int base_line = (ascii[0] & 15);
2338
int cap_line = (ascii[0] >> 4) & 15;
2339
size.height = cvRound((cap_line + base_line)*fontScale + (thickness+1)/2);
2340
2341
for( int i = 0; i < (int)text.size(); i++ )
2342
{
2343
int c = (uchar)text[i];
2344
Point p;
2345
2346
readCheck(c, i, text, fontFace);
2347
2348
const char* ptr = faces[ascii[(c-' ')+1]];
2349
p.x = (uchar)ptr[0] - 'R';
2350
p.y = (uchar)ptr[1] - 'R';
2351
view_x += (p.y - p.x)*fontScale;
2352
}
2353
2354
size.width = cvRound(view_x + thickness);
2355
if( _base_line )
2356
*_base_line = cvRound(base_line*fontScale + thickness*0.5);
2357
return size;
2358
}
2359
2360
double getFontScaleFromHeight(const int fontFace, const int pixelHeight, const int thickness)
2361
{
2362
// By https://stackoverflow.com/a/27898487/1531708
2363
const int* ascii = getFontData(fontFace);
2364
2365
int base_line = (ascii[0] & 15);
2366
int cap_line = (ascii[0] >> 4) & 15;
2367
2368
return static_cast<double>(pixelHeight - static_cast<double>((thickness + 1)) / 2.0) / static_cast<double>(cap_line + base_line);
2369
}
2370
2371
}
2372
2373
2374
void cv::fillConvexPoly(InputOutputArray _img, InputArray _points,
2375
const Scalar& color, int lineType, int shift)
2376
{
2377
CV_INSTRUMENT_REGION();
2378
2379
Mat img = _img.getMat(), points = _points.getMat();
2380
CV_Assert(points.checkVector(2, CV_32S) >= 0);
2381
fillConvexPoly(img, points.ptr<Point>(), points.rows*points.cols*points.channels()/2, color, lineType, shift);
2382
}
2383
2384
2385
void cv::fillPoly(InputOutputArray _img, InputArrayOfArrays pts,
2386
const Scalar& color, int lineType, int shift, Point offset)
2387
{
2388
CV_INSTRUMENT_REGION();
2389
2390
Mat img = _img.getMat();
2391
int i, ncontours = (int)pts.total();
2392
if( ncontours == 0 )
2393
return;
2394
AutoBuffer<Point*> _ptsptr(ncontours);
2395
AutoBuffer<int> _npts(ncontours);
2396
Point** ptsptr = _ptsptr.data();
2397
int* npts = _npts.data();
2398
2399
for( i = 0; i < ncontours; i++ )
2400
{
2401
Mat p = pts.getMat(i);
2402
CV_Assert(p.checkVector(2, CV_32S) >= 0);
2403
ptsptr[i] = p.ptr<Point>();
2404
npts[i] = p.rows*p.cols*p.channels()/2;
2405
}
2406
fillPoly(img, (const Point**)ptsptr, npts, (int)ncontours, color, lineType, shift, offset);
2407
}
2408
2409
2410
void cv::polylines(InputOutputArray _img, InputArrayOfArrays pts,
2411
bool isClosed, const Scalar& color,
2412
int thickness, int lineType, int shift )
2413
{
2414
CV_INSTRUMENT_REGION();
2415
2416
Mat img = _img.getMat();
2417
bool manyContours = pts.kind() == _InputArray::STD_VECTOR_VECTOR ||
2418
pts.kind() == _InputArray::STD_VECTOR_MAT;
2419
int i, ncontours = manyContours ? (int)pts.total() : 1;
2420
if( ncontours == 0 )
2421
return;
2422
AutoBuffer<Point*> _ptsptr(ncontours);
2423
AutoBuffer<int> _npts(ncontours);
2424
Point** ptsptr = _ptsptr.data();
2425
int* npts = _npts.data();
2426
2427
for( i = 0; i < ncontours; i++ )
2428
{
2429
Mat p = pts.getMat(manyContours ? i : -1);
2430
if( p.total() == 0 )
2431
{
2432
ptsptr[i] = NULL;
2433
npts[i] = 0;
2434
continue;
2435
}
2436
CV_Assert(p.checkVector(2, CV_32S) >= 0);
2437
ptsptr[i] = p.ptr<Point>();
2438
npts[i] = p.rows*p.cols*p.channels()/2;
2439
}
2440
polylines(img, (const Point**)ptsptr, npts, (int)ncontours, isClosed, color, thickness, lineType, shift);
2441
}
2442
2443
namespace
2444
{
2445
using namespace cv;
2446
2447
static void addChildContour(InputArrayOfArrays contours,
2448
size_t ncontours,
2449
const Vec4i* hierarchy,
2450
int i, std::vector<CvSeq>& seq,
2451
std::vector<CvSeqBlock>& block)
2452
{
2453
for( ; i >= 0; i = hierarchy[i][0] )
2454
{
2455
Mat ci = contours.getMat(i);
2456
cvMakeSeqHeaderForArray(CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point),
2457
!ci.empty() ? (void*)ci.ptr() : 0, (int)ci.total(),
2458
&seq[i], &block[i] );
2459
2460
int h_next = hierarchy[i][0], h_prev = hierarchy[i][1],
2461
v_next = hierarchy[i][2], v_prev = hierarchy[i][3];
2462
seq[i].h_next = (0 <= h_next && h_next < (int)ncontours) ? &seq[h_next] : 0;
2463
seq[i].h_prev = (0 <= h_prev && h_prev < (int)ncontours) ? &seq[h_prev] : 0;
2464
seq[i].v_next = (0 <= v_next && v_next < (int)ncontours) ? &seq[v_next] : 0;
2465
seq[i].v_prev = (0 <= v_prev && v_prev < (int)ncontours) ? &seq[v_prev] : 0;
2466
2467
if( v_next >= 0 )
2468
addChildContour(contours, ncontours, hierarchy, v_next, seq, block);
2469
}
2470
}
2471
}
2472
2473
void cv::drawContours( InputOutputArray _image, InputArrayOfArrays _contours,
2474
int contourIdx, const Scalar& color, int thickness,
2475
int lineType, InputArray _hierarchy,
2476
int maxLevel, Point offset )
2477
{
2478
CV_INSTRUMENT_REGION();
2479
2480
Mat image = _image.getMat(), hierarchy = _hierarchy.getMat();
2481
CvMat _cimage = cvMat(image);
2482
2483
size_t ncontours = _contours.total();
2484
size_t i = 0, first = 0, last = ncontours;
2485
std::vector<CvSeq> seq;
2486
std::vector<CvSeqBlock> block;
2487
2488
if( !last )
2489
return;
2490
2491
seq.resize(last);
2492
block.resize(last);
2493
2494
for( i = first; i < last; i++ )
2495
seq[i].first = 0;
2496
2497
if( contourIdx >= 0 )
2498
{
2499
CV_Assert( 0 <= contourIdx && contourIdx < (int)last );
2500
first = contourIdx;
2501
last = contourIdx + 1;
2502
}
2503
2504
for( i = first; i < last; i++ )
2505
{
2506
Mat ci = _contours.getMat((int)i);
2507
if( ci.empty() )
2508
continue;
2509
int npoints = ci.checkVector(2, CV_32S);
2510
CV_Assert( npoints > 0 );
2511
cvMakeSeqHeaderForArray( CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point),
2512
ci.ptr(), npoints, &seq[i], &block[i] );
2513
}
2514
2515
if( hierarchy.empty() || maxLevel == 0 )
2516
for( i = first; i < last; i++ )
2517
{
2518
seq[i].h_next = i < last-1 ? &seq[i+1] : 0;
2519
seq[i].h_prev = i > first ? &seq[i-1] : 0;
2520
}
2521
else
2522
{
2523
size_t count = last - first;
2524
CV_Assert(hierarchy.total() == ncontours && hierarchy.type() == CV_32SC4 );
2525
const Vec4i* h = hierarchy.ptr<Vec4i>();
2526
2527
if( count == ncontours )
2528
{
2529
for( i = first; i < last; i++ )
2530
{
2531
int h_next = h[i][0], h_prev = h[i][1],
2532
v_next = h[i][2], v_prev = h[i][3];
2533
seq[i].h_next = (size_t)h_next < count ? &seq[h_next] : 0;
2534
seq[i].h_prev = (size_t)h_prev < count ? &seq[h_prev] : 0;
2535
seq[i].v_next = (size_t)v_next < count ? &seq[v_next] : 0;
2536
seq[i].v_prev = (size_t)v_prev < count ? &seq[v_prev] : 0;
2537
}
2538
}
2539
else
2540
{
2541
int child = h[first][2];
2542
if( child >= 0 )
2543
{
2544
addChildContour(_contours, ncontours, h, child, seq, block);
2545
seq[first].v_next = &seq[child];
2546
}
2547
}
2548
}
2549
2550
cvDrawContours( &_cimage, &seq[first], cvScalar(color), cvScalar(color), contourIdx >= 0 ?
2551
-maxLevel : maxLevel, thickness, lineType, cvPoint(offset) );
2552
}
2553
2554
2555
2556
static const int CodeDeltas[8][2] =
2557
{ {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} };
2558
2559
#define CV_ADJUST_EDGE_COUNT( count, seq ) \
2560
((count) -= ((count) == (seq)->total && !CV_IS_SEQ_CLOSED(seq)))
2561
2562
CV_IMPL void
2563
cvDrawContours( void* _img, CvSeq* contour,
2564
CvScalar _externalColor, CvScalar _holeColor,
2565
int maxLevel, int thickness,
2566
int line_type, CvPoint _offset )
2567
{
2568
CvSeq *contour0 = contour, *h_next = 0;
2569
CvTreeNodeIterator iterator;
2570
std::vector<cv::PolyEdge> edges;
2571
std::vector<cv::Point2l> pts;
2572
cv::Scalar externalColor = _externalColor, holeColor = _holeColor;
2573
cv::Mat img = cv::cvarrToMat(_img);
2574
cv::Point offset = _offset;
2575
double ext_buf[4], hole_buf[4];
2576
2577
if( line_type == CV_AA && img.depth() != CV_8U )
2578
line_type = 8;
2579
2580
if( !contour )
2581
return;
2582
2583
CV_Assert( thickness <= MAX_THICKNESS );
2584
2585
scalarToRawData( externalColor, ext_buf, img.type(), 0 );
2586
scalarToRawData( holeColor, hole_buf, img.type(), 0 );
2587
2588
maxLevel = MAX(maxLevel, INT_MIN+2);
2589
maxLevel = MIN(maxLevel, INT_MAX-1);
2590
2591
if( maxLevel < 0 )
2592
{
2593
h_next = contour->h_next;
2594
contour->h_next = 0;
2595
maxLevel = -maxLevel+1;
2596
}
2597
2598
cvInitTreeNodeIterator( &iterator, contour, maxLevel );
2599
while( (contour = (CvSeq*)cvNextTreeNode( &iterator )) != 0 )
2600
{
2601
CvSeqReader reader;
2602
int i, count = contour->total;
2603
int elem_type = CV_MAT_TYPE(contour->flags);
2604
void* clr = (contour->flags & CV_SEQ_FLAG_HOLE) == 0 ? ext_buf : hole_buf;
2605
2606
cvStartReadSeq( contour, &reader, 0 );
2607
CV_Assert(reader.ptr != NULL);
2608
if( thickness < 0 )
2609
pts.resize(0);
2610
2611
if( CV_IS_SEQ_CHAIN_CONTOUR( contour ))
2612
{
2613
cv::Point pt = ((CvChain*)contour)->origin;
2614
cv::Point prev_pt = pt;
2615
char prev_code = reader.ptr ? reader.ptr[0] : '\0';
2616
2617
prev_pt += offset;
2618
2619
for( i = 0; i < count; i++ )
2620
{
2621
char code;
2622
CV_READ_SEQ_ELEM( code, reader );
2623
2624
assert( (code & ~7) == 0 );
2625
2626
if( code != prev_code )
2627
{
2628
prev_code = code;
2629
if( thickness >= 0 )
2630
cv::ThickLine( img, prev_pt, pt, clr, thickness, line_type, 2, 0 );
2631
else
2632
pts.push_back(pt);
2633
prev_pt = pt;
2634
}
2635
2636
pt.x += CodeDeltas[(int)code][0];
2637
pt.y += CodeDeltas[(int)code][1];
2638
}
2639
2640
if( thickness >= 0 )
2641
cv::ThickLine( img, prev_pt,
2642
cv::Point(((CvChain*)contour)->origin) + offset,
2643
clr, thickness, line_type, 2, 0 );
2644
else
2645
cv::CollectPolyEdges(img, &pts[0], (int)pts.size(),
2646
edges, ext_buf, line_type, 0, offset);
2647
}
2648
else if( CV_IS_SEQ_POLYLINE( contour ))
2649
{
2650
CV_Assert( elem_type == CV_32SC2 );
2651
cv::Point pt1, pt2;
2652
int shift = 0;
2653
2654
count -= !CV_IS_SEQ_CLOSED(contour);
2655
{ CvPoint pt_ = CV_STRUCT_INITIALIZER; CV_READ_SEQ_ELEM(pt_, reader); pt1 = pt_; }
2656
pt1 += offset;
2657
if( thickness < 0 )
2658
pts.push_back(pt1);
2659
2660
for( i = 0; i < count; i++ )
2661
{
2662
{ CvPoint pt_ = CV_STRUCT_INITIALIZER; CV_READ_SEQ_ELEM(pt_, reader); pt2 = pt_; }
2663
pt2 += offset;
2664
if( thickness >= 0 )
2665
cv::ThickLine( img, pt1, pt2, clr, thickness, line_type, 2, shift );
2666
else
2667
pts.push_back(pt2);
2668
pt1 = pt2;
2669
}
2670
if( thickness < 0 )
2671
cv::CollectPolyEdges( img, &pts[0], (int)pts.size(),
2672
edges, ext_buf, line_type, 0, cv::Point() );
2673
}
2674
}
2675
2676
if( thickness < 0 )
2677
cv::FillEdgeCollection( img, edges, ext_buf );
2678
2679
if( h_next && contour0 )
2680
contour0->h_next = h_next;
2681
}
2682
2683
CV_IMPL int
2684
cvClipLine( CvSize size, CvPoint* pt1, CvPoint* pt2 )
2685
{
2686
CV_Assert( pt1 && pt2 );
2687
return cv::clipLine( size, *(cv::Point*)pt1, *(cv::Point*)pt2 );
2688
}
2689
2690
2691
CV_IMPL int
2692
cvEllipse2Poly( CvPoint center, CvSize axes, int angle,
2693
int arc_start, int arc_end, CvPoint* _pts, int delta )
2694
{
2695
std::vector<cv::Point> pts;
2696
cv::ellipse2Poly( Point(center), Size(axes), angle, arc_start, arc_end, delta, pts );
2697
memcpy( _pts, &pts[0], pts.size()*sizeof(_pts[0]) );
2698
return (int)pts.size();
2699
}
2700
2701
CV_IMPL CvScalar
2702
cvColorToScalar( double packed_color, int type )
2703
{
2704
cv::Scalar scalar;
2705
2706
if( CV_MAT_DEPTH( type ) == CV_8U )
2707
{
2708
int icolor = cvRound( packed_color );
2709
if( CV_MAT_CN( type ) > 1 )
2710
{
2711
scalar.val[0] = icolor & 255;
2712
scalar.val[1] = (icolor >> 8) & 255;
2713
scalar.val[2] = (icolor >> 16) & 255;
2714
scalar.val[3] = (icolor >> 24) & 255;
2715
}
2716
else
2717
{
2718
scalar.val[0] = cv::saturate_cast<uchar>( icolor );
2719
scalar.val[1] = scalar.val[2] = scalar.val[3] = 0;
2720
}
2721
}
2722
else if( CV_MAT_DEPTH( type ) == CV_8S )
2723
{
2724
int icolor = cvRound( packed_color );
2725
if( CV_MAT_CN( type ) > 1 )
2726
{
2727
scalar.val[0] = (char)icolor;
2728
scalar.val[1] = (char)(icolor >> 8);
2729
scalar.val[2] = (char)(icolor >> 16);
2730
scalar.val[3] = (char)(icolor >> 24);
2731
}
2732
else
2733
{
2734
scalar.val[0] = cv::saturate_cast<schar>( icolor );
2735
scalar.val[1] = scalar.val[2] = scalar.val[3] = 0;
2736
}
2737
}
2738
else
2739
{
2740
int cn = CV_MAT_CN( type );
2741
switch( cn )
2742
{
2743
case 1:
2744
scalar.val[0] = packed_color;
2745
scalar.val[1] = scalar.val[2] = scalar.val[3] = 0;
2746
break;
2747
case 2:
2748
scalar.val[0] = scalar.val[1] = packed_color;
2749
scalar.val[2] = scalar.val[3] = 0;
2750
break;
2751
case 3:
2752
scalar.val[0] = scalar.val[1] = scalar.val[2] = packed_color;
2753
scalar.val[3] = 0;
2754
break;
2755
default:
2756
scalar.val[0] = scalar.val[1] =
2757
scalar.val[2] = scalar.val[3] = packed_color;
2758
break;
2759
}
2760
}
2761
2762
return cvScalar(scalar);
2763
}
2764
2765
CV_IMPL int
2766
cvInitLineIterator( const CvArr* img, CvPoint pt1, CvPoint pt2,
2767
CvLineIterator* iterator, int connectivity,
2768
int left_to_right )
2769
{
2770
CV_Assert( iterator != 0 );
2771
cv::LineIterator li(cv::cvarrToMat(img), pt1, pt2, connectivity, left_to_right!=0);
2772
2773
iterator->err = li.err;
2774
iterator->minus_delta = li.minusDelta;
2775
iterator->plus_delta = li.plusDelta;
2776
iterator->minus_step = li.minusStep;
2777
iterator->plus_step = li.plusStep;
2778
iterator->ptr = li.ptr;
2779
2780
return li.count;
2781
}
2782
2783
CV_IMPL void
2784
cvLine( CvArr* _img, CvPoint pt1, CvPoint pt2, CvScalar color,
2785
int thickness, int line_type, int shift )
2786
{
2787
cv::Mat img = cv::cvarrToMat(_img);
2788
cv::line( img, pt1, pt2, color, thickness, line_type, shift );
2789
}
2790
2791
CV_IMPL void
2792
cvRectangle( CvArr* _img, CvPoint pt1, CvPoint pt2,
2793
CvScalar color, int thickness,
2794
int line_type, int shift )
2795
{
2796
cv::Mat img = cv::cvarrToMat(_img);
2797
cv::rectangle( img, pt1, pt2, color, thickness, line_type, shift );
2798
}
2799
2800
CV_IMPL void
2801
cvRectangleR( CvArr* _img, CvRect rec,
2802
CvScalar color, int thickness,
2803
int line_type, int shift )
2804
{
2805
cv::Mat img = cv::cvarrToMat(_img);
2806
cv::rectangle( img, rec, color, thickness, line_type, shift );
2807
}
2808
2809
CV_IMPL void
2810
cvCircle( CvArr* _img, CvPoint center, int radius,
2811
CvScalar color, int thickness, int line_type, int shift )
2812
{
2813
cv::Mat img = cv::cvarrToMat(_img);
2814
cv::circle( img, center, radius, color, thickness, line_type, shift );
2815
}
2816
2817
CV_IMPL void
2818
cvEllipse( CvArr* _img, CvPoint center, CvSize axes,
2819
double angle, double start_angle, double end_angle,
2820
CvScalar color, int thickness, int line_type, int shift )
2821
{
2822
cv::Mat img = cv::cvarrToMat(_img);
2823
cv::ellipse( img, center, axes, angle, start_angle, end_angle,
2824
color, thickness, line_type, shift );
2825
}
2826
2827
CV_IMPL void
2828
cvFillConvexPoly( CvArr* _img, const CvPoint *pts, int npts,
2829
CvScalar color, int line_type, int shift )
2830
{
2831
cv::Mat img = cv::cvarrToMat(_img);
2832
cv::fillConvexPoly( img, (const cv::Point*)pts, npts,
2833
color, line_type, shift );
2834
}
2835
2836
CV_IMPL void
2837
cvFillPoly( CvArr* _img, CvPoint **pts, const int *npts, int ncontours,
2838
CvScalar color, int line_type, int shift )
2839
{
2840
cv::Mat img = cv::cvarrToMat(_img);
2841
2842
cv::fillPoly( img, (const cv::Point**)pts, npts, ncontours, color, line_type, shift );
2843
}
2844
2845
CV_IMPL void
2846
cvPolyLine( CvArr* _img, CvPoint **pts, const int *npts,
2847
int ncontours, int closed, CvScalar color,
2848
int thickness, int line_type, int shift )
2849
{
2850
cv::Mat img = cv::cvarrToMat(_img);
2851
2852
cv::polylines( img, (const cv::Point**)pts, npts, ncontours,
2853
closed != 0, color, thickness, line_type, shift );
2854
}
2855
2856
CV_IMPL void
2857
cvPutText( CvArr* _img, const char *text, CvPoint org, const CvFont *_font, CvScalar color )
2858
{
2859
cv::Mat img = cv::cvarrToMat(_img);
2860
CV_Assert( text != 0 && _font != 0);
2861
cv::putText( img, text, org, _font->font_face, (_font->hscale+_font->vscale)*0.5,
2862
color, _font->thickness, _font->line_type,
2863
CV_IS_IMAGE(_img) && ((IplImage*)_img)->origin != 0 );
2864
}
2865
2866
2867
CV_IMPL void
2868
cvInitFont( CvFont *font, int font_face, double hscale, double vscale,
2869
double shear, int thickness, int line_type )
2870
{
2871
CV_Assert( font != 0 && hscale > 0 && vscale > 0 && thickness >= 0 );
2872
2873
font->ascii = cv::getFontData(font_face);
2874
font->font_face = font_face;
2875
font->hscale = (float)hscale;
2876
font->vscale = (float)vscale;
2877
font->thickness = thickness;
2878
font->shear = (float)shear;
2879
font->greek = font->cyrillic = 0;
2880
font->line_type = line_type;
2881
}
2882
2883
CV_IMPL void
2884
cvGetTextSize( const char *text, const CvFont *_font, CvSize *_size, int *_base_line )
2885
{
2886
CV_Assert(text != 0 && _font != 0);
2887
cv::Size size = cv::getTextSize( text, _font->font_face, (_font->hscale + _font->vscale)*0.5,
2888
_font->thickness, _base_line );
2889
if( _size )
2890
*_size = cvSize(size);
2891
}
2892
2893
/* End of file. */
2894
2895