Opencv 3.1 project on GR-PEACH board
Fork of gr-peach-opencv-project by
drawing.cpp
00001 /*M/////////////////////////////////////////////////////////////////////////////////////// 00002 // 00003 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 00004 // 00005 // By downloading, copying, installing or using the software you agree to this license. 00006 // If you do not agree to this license, do not download, install, 00007 // copy or use the software. 00008 // 00009 // 00010 // Intel License Agreement 00011 // For Open Source Computer Vision Library 00012 // 00013 // Copyright (C) 2000, Intel Corporation, all rights reserved. 00014 // Third party copyrights are property of their respective owners. 00015 // 00016 // Redistribution and use in source and binary forms, with or without modification, 00017 // are permitted provided that the following conditions are met: 00018 // 00019 // * Redistribution's of source code must retain the above copyright notice, 00020 // this list of conditions and the following disclaimer. 00021 // 00022 // * Redistribution's in binary form must reproduce the above copyright notice, 00023 // this list of conditions and the following disclaimer in the documentation 00024 // and/or other materials provided with the distribution. 00025 // 00026 // * The name of Intel Corporation may not be used to endorse or promote products 00027 // derived from this software without specific prior written permission. 00028 // 00029 // This software is provided by the copyright holders and contributors "as is" and 00030 // any express or implied warranties, including, but not limited to, the implied 00031 // warranties of merchantability and fitness for a particular purpose are disclaimed. 00032 // In no event shall the Intel Corporation or contributors be liable for any direct, 00033 // indirect, incidental, special, exemplary, or consequential damages 00034 // (including, but not limited to, procurement of substitute goods or services; 00035 // loss of use, data, or profits; or business interruption) however caused 00036 // and on any theory of liability, whether in contract, strict liability, 00037 // or tort (including negligence or otherwise) arising in any way out of 00038 // the use of this software, even if advised of the possibility of such damage. 00039 // 00040 //M*/ 00041 #include "precomp.hpp" 00042 00043 namespace cv 00044 { 00045 00046 enum { XY_SHIFT = 16, XY_ONE = 1 << XY_SHIFT, DRAWING_STORAGE_BLOCK = (1<<12) - 256 }; 00047 00048 static const int MAX_THICKNESS = 32767; 00049 00050 struct PolyEdge 00051 { 00052 PolyEdge() : y0(0), y1(0), x(0), dx(0), next(0) {} 00053 //PolyEdge(int _y0, int _y1, int _x, int _dx) : y0(_y0), y1(_y1), x(_x), dx(_dx) {} 00054 00055 int y0, y1; 00056 int x, dx; 00057 PolyEdge *next; 00058 }; 00059 00060 static void 00061 CollectPolyEdges( Mat& img, const Point* v, int npts, 00062 std::vector<PolyEdge>& edges, const void* color, int line_type, 00063 int shift, Point offset=Point() ); 00064 00065 static void 00066 FillEdgeCollection( Mat& img, std::vector<PolyEdge>& edges, const void* color ); 00067 00068 static void 00069 PolyLine( Mat& img, const Point* v, int npts, bool closed, 00070 const void* color, int thickness, int line_type, int shift ); 00071 00072 static void 00073 FillConvexPoly( Mat& img, const Point* v, int npts, 00074 const void* color, int line_type, int shift ); 00075 00076 /****************************************************************************************\ 00077 * Lines * 00078 \****************************************************************************************/ 00079 00080 bool clipLine( Size img_size, Point& pt1, Point& pt2 ) 00081 { 00082 int64 x1, y1, x2, y2; 00083 int c1, c2; 00084 int64 right = img_size.width-1, bottom = img_size.height-1; 00085 00086 if( img_size.width <= 0 || img_size.height <= 0 ) 00087 return false; 00088 00089 x1 = pt1.x; y1 = pt1.y; x2 = pt2.x; y2 = pt2.y; 00090 c1 = (x1 < 0) + (x1 > right) * 2 + (y1 < 0) * 4 + (y1 > bottom) * 8; 00091 c2 = (x2 < 0) + (x2 > right) * 2 + (y2 < 0) * 4 + (y2 > bottom) * 8; 00092 00093 if( (c1 & c2) == 0 && (c1 | c2) != 0 ) 00094 { 00095 int64 a; 00096 if( c1 & 12 ) 00097 { 00098 a = c1 < 8 ? 0 : bottom; 00099 x1 += (a - y1) * (x2 - x1) / (y2 - y1); 00100 y1 = a; 00101 c1 = (x1 < 0) + (x1 > right) * 2; 00102 } 00103 if( c2 & 12 ) 00104 { 00105 a = c2 < 8 ? 0 : bottom; 00106 x2 += (a - y2) * (x2 - x1) / (y2 - y1); 00107 y2 = a; 00108 c2 = (x2 < 0) + (x2 > right) * 2; 00109 } 00110 if( (c1 & c2) == 0 && (c1 | c2) != 0 ) 00111 { 00112 if( c1 ) 00113 { 00114 a = c1 == 1 ? 0 : right; 00115 y1 += (a - x1) * (y2 - y1) / (x2 - x1); 00116 x1 = a; 00117 c1 = 0; 00118 } 00119 if( c2 ) 00120 { 00121 a = c2 == 1 ? 0 : right; 00122 y2 += (a - x2) * (y2 - y1) / (x2 - x1); 00123 x2 = a; 00124 c2 = 0; 00125 } 00126 } 00127 00128 assert( (c1 & c2) != 0 || (x1 | y1 | x2 | y2) >= 0 ); 00129 00130 pt1.x = (int)x1; 00131 pt1.y = (int)y1; 00132 pt2.x = (int)x2; 00133 pt2.y = (int)y2; 00134 } 00135 00136 return (c1 | c2) == 0; 00137 } 00138 00139 bool clipLine( Rect img_rect, Point& pt1, Point& pt2 ) 00140 { 00141 Point tl = img_rect.tl(); 00142 pt1 -= tl; pt2 -= tl; 00143 bool inside = clipLine(img_rect.size(), pt1, pt2); 00144 pt1 += tl; pt2 += tl; 00145 00146 return inside; 00147 } 00148 00149 /* 00150 Initializes line iterator. 00151 Returns number of points on the line or negative number if error. 00152 */ 00153 LineIterator::LineIterator(const Mat& img, Point pt1, Point pt2, 00154 int connectivity, bool left_to_right) 00155 { 00156 count = -1; 00157 00158 CV_Assert( connectivity == 8 || connectivity == 4 ); 00159 00160 if( (unsigned)pt1.x >= (unsigned)(img.cols) || 00161 (unsigned)pt2.x >= (unsigned)(img.cols) || 00162 (unsigned)pt1.y >= (unsigned)(img.rows) || 00163 (unsigned)pt2.y >= (unsigned)(img.rows) ) 00164 { 00165 if( !clipLine( img.size(), pt1, pt2 ) ) 00166 { 00167 ptr = img.data; 00168 err = plusDelta = minusDelta = plusStep = minusStep = count = 0; 00169 return; 00170 } 00171 } 00172 00173 int bt_pix0 = (int)img.elemSize(), bt_pix = bt_pix0; 00174 size_t istep = img.step; 00175 00176 int dx = pt2.x - pt1.x; 00177 int dy = pt2.y - pt1.y; 00178 int s = dx < 0 ? -1 : 0; 00179 00180 if( left_to_right ) 00181 { 00182 dx = (dx ^ s) - s; 00183 dy = (dy ^ s) - s; 00184 pt1.x ^= (pt1.x ^ pt2.x) & s; 00185 pt1.y ^= (pt1.y ^ pt2.y) & s; 00186 } 00187 else 00188 { 00189 dx = (dx ^ s) - s; 00190 bt_pix = (bt_pix ^ s) - s; 00191 } 00192 00193 ptr = (uchar*)(img.data + pt1.y * istep + pt1.x * bt_pix0); 00194 00195 s = dy < 0 ? -1 : 0; 00196 dy = (dy ^ s) - s; 00197 istep = (istep ^ s) - s; 00198 00199 s = dy > dx ? -1 : 0; 00200 00201 /* conditional swaps */ 00202 dx ^= dy & s; 00203 dy ^= dx & s; 00204 dx ^= dy & s; 00205 00206 bt_pix ^= istep & s; 00207 istep ^= bt_pix & s; 00208 bt_pix ^= istep & s; 00209 00210 if( connectivity == 8 ) 00211 { 00212 assert( dx >= 0 && dy >= 0 ); 00213 00214 err = dx - (dy + dy); 00215 plusDelta = dx + dx; 00216 minusDelta = -(dy + dy); 00217 plusStep = (int)istep; 00218 minusStep = bt_pix; 00219 count = dx + 1; 00220 } 00221 else /* connectivity == 4 */ 00222 { 00223 assert( dx >= 0 && dy >= 0 ); 00224 00225 err = 0; 00226 plusDelta = (dx + dx) + (dy + dy); 00227 minusDelta = -(dy + dy); 00228 plusStep = (int)istep - bt_pix; 00229 minusStep = bt_pix; 00230 count = dx + dy + 1; 00231 } 00232 00233 this->ptr0 = img.ptr(); 00234 this->step = (int)img.step; 00235 this->elemSize = bt_pix0; 00236 } 00237 00238 static void 00239 Line( Mat& img, Point pt1, Point pt2, 00240 const void* _color, int connectivity = 8 ) 00241 { 00242 if( connectivity == 0 ) 00243 connectivity = 8; 00244 else if( connectivity == 1 ) 00245 connectivity = 4; 00246 00247 LineIterator iterator(img, pt1, pt2, connectivity, true); 00248 int i, count = iterator.count; 00249 int pix_size = (int)img.elemSize(); 00250 const uchar* color = (const uchar*)_color; 00251 00252 for( i = 0; i < count; i++, ++iterator ) 00253 { 00254 uchar* ptr = *iterator; 00255 if( pix_size == 1 ) 00256 ptr[0] = color[0]; 00257 else if( pix_size == 3 ) 00258 { 00259 ptr[0] = color[0]; 00260 ptr[1] = color[1]; 00261 ptr[2] = color[2]; 00262 } 00263 else 00264 memcpy( *iterator, color, pix_size ); 00265 } 00266 } 00267 00268 00269 /* Correction table depent on the slope */ 00270 static const uchar SlopeCorrTable[] = { 00271 181, 181, 181, 182, 182, 183, 184, 185, 187, 188, 190, 192, 194, 196, 198, 201, 00272 203, 206, 209, 211, 214, 218, 221, 224, 227, 231, 235, 238, 242, 246, 250, 254 00273 }; 00274 00275 /* Gaussian for antialiasing filter */ 00276 static const int FilterTable[] = { 00277 168, 177, 185, 194, 202, 210, 218, 224, 231, 236, 241, 246, 249, 252, 254, 254, 00278 254, 254, 252, 249, 246, 241, 236, 231, 224, 218, 210, 202, 194, 185, 177, 168, 00279 158, 149, 140, 131, 122, 114, 105, 97, 89, 82, 75, 68, 62, 56, 50, 45, 00280 40, 36, 32, 28, 25, 22, 19, 16, 14, 12, 11, 9, 8, 7, 5, 5 00281 }; 00282 00283 static void 00284 LineAA( Mat& img, Point pt1, Point pt2, const void* color ) 00285 { 00286 int dx, dy; 00287 int ecount, scount = 0; 00288 int slope; 00289 int ax, ay; 00290 int x_step, y_step; 00291 int i, j; 00292 int ep_table[9]; 00293 int cb = ((uchar*)color)[0], cg = ((uchar*)color)[1], cr = ((uchar*)color)[2], ca = ((uchar*)color)[3]; 00294 int _cb, _cg, _cr, _ca; 00295 int nch = img.channels(); 00296 uchar* ptr = img.ptr(); 00297 size_t step = img.step; 00298 Size size = img.size(); 00299 00300 if( !((nch == 1 || nch == 3 || nch == 4) && img.depth() == CV_8U) ) 00301 { 00302 Line(img, pt1, pt2, color); 00303 return; 00304 } 00305 00306 pt1.x -= XY_ONE*2; 00307 pt1.y -= XY_ONE*2; 00308 pt2.x -= XY_ONE*2; 00309 pt2.y -= XY_ONE*2; 00310 ptr += img.step*2 + 2*nch; 00311 00312 size.width = ((size.width - 5) << XY_SHIFT) + 1; 00313 size.height = ((size.height - 5) << XY_SHIFT) + 1; 00314 00315 if( !clipLine( size, pt1, pt2 )) 00316 return; 00317 00318 dx = pt2.x - pt1.x; 00319 dy = pt2.y - pt1.y; 00320 00321 j = dx < 0 ? -1 : 0; 00322 ax = (dx ^ j) - j; 00323 i = dy < 0 ? -1 : 0; 00324 ay = (dy ^ i) - i; 00325 00326 if( ax > ay ) 00327 { 00328 dx = ax; 00329 dy = (dy ^ j) - j; 00330 pt1.x ^= pt2.x & j; 00331 pt2.x ^= pt1.x & j; 00332 pt1.x ^= pt2.x & j; 00333 pt1.y ^= pt2.y & j; 00334 pt2.y ^= pt1.y & j; 00335 pt1.y ^= pt2.y & j; 00336 00337 x_step = XY_ONE; 00338 y_step = (int) (((int64) dy << XY_SHIFT) / (ax | 1)); 00339 pt2.x += XY_ONE; 00340 ecount = (pt2.x >> XY_SHIFT) - (pt1.x >> XY_SHIFT); 00341 j = -(pt1.x & (XY_ONE - 1)); 00342 pt1.y += (int) ((((int64) y_step) * j) >> XY_SHIFT) + (XY_ONE >> 1); 00343 slope = (y_step >> (XY_SHIFT - 5)) & 0x3f; 00344 slope ^= (y_step < 0 ? 0x3f : 0); 00345 00346 /* Get 4-bit fractions for end-point adjustments */ 00347 i = (pt1.x >> (XY_SHIFT - 7)) & 0x78; 00348 j = (pt2.x >> (XY_SHIFT - 7)) & 0x78; 00349 } 00350 else 00351 { 00352 dy = ay; 00353 dx = (dx ^ i) - i; 00354 pt1.x ^= pt2.x & i; 00355 pt2.x ^= pt1.x & i; 00356 pt1.x ^= pt2.x & i; 00357 pt1.y ^= pt2.y & i; 00358 pt2.y ^= pt1.y & i; 00359 pt1.y ^= pt2.y & i; 00360 00361 x_step = (int) (((int64) dx << XY_SHIFT) / (ay | 1)); 00362 y_step = XY_ONE; 00363 pt2.y += XY_ONE; 00364 ecount = (pt2.y >> XY_SHIFT) - (pt1.y >> XY_SHIFT); 00365 j = -(pt1.y & (XY_ONE - 1)); 00366 pt1.x += (int) ((((int64) x_step) * j) >> XY_SHIFT) + (XY_ONE >> 1); 00367 slope = (x_step >> (XY_SHIFT - 5)) & 0x3f; 00368 slope ^= (x_step < 0 ? 0x3f : 0); 00369 00370 /* Get 4-bit fractions for end-point adjustments */ 00371 i = (pt1.y >> (XY_SHIFT - 7)) & 0x78; 00372 j = (pt2.y >> (XY_SHIFT - 7)) & 0x78; 00373 } 00374 00375 slope = (slope & 0x20) ? 0x100 : SlopeCorrTable[slope]; 00376 00377 /* Calc end point correction table */ 00378 { 00379 int t0 = slope << 7; 00380 int t1 = ((0x78 - i) | 4) * slope; 00381 int t2 = (j | 4) * slope; 00382 00383 ep_table[0] = 0; 00384 ep_table[8] = slope; 00385 ep_table[1] = ep_table[3] = ((((j - i) & 0x78) | 4) * slope >> 8) & 0x1ff; 00386 ep_table[2] = (t1 >> 8) & 0x1ff; 00387 ep_table[4] = ((((j - i) + 0x80) | 4) * slope >> 8) & 0x1ff; 00388 ep_table[5] = ((t1 + t0) >> 8) & 0x1ff; 00389 ep_table[6] = (t2 >> 8) & 0x1ff; 00390 ep_table[7] = ((t2 + t0) >> 8) & 0x1ff; 00391 } 00392 00393 if( nch == 3 ) 00394 { 00395 #define ICV_PUT_POINT() \ 00396 { \ 00397 _cb = tptr[0]; \ 00398 _cb += ((cb - _cb)*a + 127)>> 8;\ 00399 _cg = tptr[1]; \ 00400 _cg += ((cg - _cg)*a + 127)>> 8;\ 00401 _cr = tptr[2]; \ 00402 _cr += ((cr - _cr)*a + 127)>> 8;\ 00403 tptr[0] = (uchar)_cb; \ 00404 tptr[1] = (uchar)_cg; \ 00405 tptr[2] = (uchar)_cr; \ 00406 } 00407 if( ax > ay ) 00408 { 00409 ptr += (pt1.x >> XY_SHIFT) * 3; 00410 00411 while( ecount >= 0 ) 00412 { 00413 uchar *tptr = ptr + ((pt1.y >> XY_SHIFT) - 1) * step; 00414 00415 int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 + 00416 (((ecount >= 2) + 1) & (ecount | 2))]; 00417 int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31; 00418 00419 a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff; 00420 ICV_PUT_POINT(); 00421 ICV_PUT_POINT(); 00422 00423 tptr += step; 00424 a = (ep_corr * FilterTable[dist] >> 8) & 0xff; 00425 ICV_PUT_POINT(); 00426 ICV_PUT_POINT(); 00427 00428 tptr += step; 00429 a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff; 00430 ICV_PUT_POINT(); 00431 ICV_PUT_POINT(); 00432 00433 pt1.y += y_step; 00434 ptr += 3; 00435 scount++; 00436 ecount--; 00437 } 00438 } 00439 else 00440 { 00441 ptr += (pt1.y >> XY_SHIFT) * step; 00442 00443 while( ecount >= 0 ) 00444 { 00445 uchar *tptr = ptr + ((pt1.x >> XY_SHIFT) - 1) * 3; 00446 00447 int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 + 00448 (((ecount >= 2) + 1) & (ecount | 2))]; 00449 int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31; 00450 00451 a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff; 00452 ICV_PUT_POINT(); 00453 ICV_PUT_POINT(); 00454 00455 tptr += 3; 00456 a = (ep_corr * FilterTable[dist] >> 8) & 0xff; 00457 ICV_PUT_POINT(); 00458 ICV_PUT_POINT(); 00459 00460 tptr += 3; 00461 a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff; 00462 ICV_PUT_POINT(); 00463 ICV_PUT_POINT(); 00464 00465 pt1.x += x_step; 00466 ptr += step; 00467 scount++; 00468 ecount--; 00469 } 00470 } 00471 #undef ICV_PUT_POINT 00472 } 00473 else if(nch == 1) 00474 { 00475 #define ICV_PUT_POINT() \ 00476 { \ 00477 _cb = tptr[0]; \ 00478 _cb += ((cb - _cb)*a + 127)>> 8;\ 00479 tptr[0] = (uchar)_cb; \ 00480 } 00481 00482 if( ax > ay ) 00483 { 00484 ptr += (pt1.x >> XY_SHIFT); 00485 00486 while( ecount >= 0 ) 00487 { 00488 uchar *tptr = ptr + ((pt1.y >> XY_SHIFT) - 1) * step; 00489 00490 int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 + 00491 (((ecount >= 2) + 1) & (ecount | 2))]; 00492 int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31; 00493 00494 a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff; 00495 ICV_PUT_POINT(); 00496 ICV_PUT_POINT(); 00497 00498 tptr += step; 00499 a = (ep_corr * FilterTable[dist] >> 8) & 0xff; 00500 ICV_PUT_POINT(); 00501 ICV_PUT_POINT(); 00502 00503 tptr += step; 00504 a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff; 00505 ICV_PUT_POINT(); 00506 ICV_PUT_POINT(); 00507 00508 pt1.y += y_step; 00509 ptr++; 00510 scount++; 00511 ecount--; 00512 } 00513 } 00514 else 00515 { 00516 ptr += (pt1.y >> XY_SHIFT) * step; 00517 00518 while( ecount >= 0 ) 00519 { 00520 uchar *tptr = ptr + ((pt1.x >> XY_SHIFT) - 1); 00521 00522 int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 + 00523 (((ecount >= 2) + 1) & (ecount | 2))]; 00524 int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31; 00525 00526 a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff; 00527 ICV_PUT_POINT(); 00528 ICV_PUT_POINT(); 00529 00530 tptr++; 00531 a = (ep_corr * FilterTable[dist] >> 8) & 0xff; 00532 ICV_PUT_POINT(); 00533 ICV_PUT_POINT(); 00534 00535 tptr++; 00536 a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff; 00537 ICV_PUT_POINT(); 00538 ICV_PUT_POINT(); 00539 00540 pt1.x += x_step; 00541 ptr += step; 00542 scount++; 00543 ecount--; 00544 } 00545 } 00546 #undef ICV_PUT_POINT 00547 } 00548 else 00549 { 00550 #define ICV_PUT_POINT() \ 00551 { \ 00552 _cb = tptr[0]; \ 00553 _cb += ((cb - _cb)*a + 127)>> 8;\ 00554 _cg = tptr[1]; \ 00555 _cg += ((cg - _cg)*a + 127)>> 8;\ 00556 _cr = tptr[2]; \ 00557 _cr += ((cr - _cr)*a + 127)>> 8;\ 00558 _ca = tptr[3]; \ 00559 _ca += ((ca - _ca)*a + 127)>> 8;\ 00560 tptr[0] = (uchar)_cb; \ 00561 tptr[1] = (uchar)_cg; \ 00562 tptr[2] = (uchar)_cr; \ 00563 tptr[3] = (uchar)_ca; \ 00564 } 00565 if( ax > ay ) 00566 { 00567 ptr += (pt1.x >> XY_SHIFT) * 4; 00568 00569 while( ecount >= 0 ) 00570 { 00571 uchar *tptr = ptr + ((pt1.y >> XY_SHIFT) - 1) * step; 00572 00573 int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 + 00574 (((ecount >= 2) + 1) & (ecount | 2))]; 00575 int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31; 00576 00577 a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff; 00578 ICV_PUT_POINT(); 00579 ICV_PUT_POINT(); 00580 00581 tptr += step; 00582 a = (ep_corr * FilterTable[dist] >> 8) & 0xff; 00583 ICV_PUT_POINT(); 00584 ICV_PUT_POINT(); 00585 00586 tptr += step; 00587 a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff; 00588 ICV_PUT_POINT(); 00589 ICV_PUT_POINT(); 00590 00591 pt1.y += y_step; 00592 ptr += 4; 00593 scount++; 00594 ecount--; 00595 } 00596 } 00597 else 00598 { 00599 ptr += (pt1.y >> XY_SHIFT) * step; 00600 00601 while( ecount >= 0 ) 00602 { 00603 uchar *tptr = ptr + ((pt1.x >> XY_SHIFT) - 1) * 4; 00604 00605 int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 + 00606 (((ecount >= 2) + 1) & (ecount | 2))]; 00607 int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31; 00608 00609 a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff; 00610 ICV_PUT_POINT(); 00611 ICV_PUT_POINT(); 00612 00613 tptr += 4; 00614 a = (ep_corr * FilterTable[dist] >> 8) & 0xff; 00615 ICV_PUT_POINT(); 00616 ICV_PUT_POINT(); 00617 00618 tptr += 4; 00619 a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff; 00620 ICV_PUT_POINT(); 00621 ICV_PUT_POINT(); 00622 00623 pt1.x += x_step; 00624 ptr += step; 00625 scount++; 00626 ecount--; 00627 } 00628 } 00629 #undef ICV_PUT_POINT 00630 } 00631 } 00632 00633 00634 static void 00635 Line2( Mat& img, Point pt1, Point pt2, const void* color ) 00636 { 00637 int dx, dy; 00638 int ecount; 00639 int ax, ay; 00640 int i, j, x, y; 00641 int x_step, y_step; 00642 int cb = ((uchar*)color)[0]; 00643 int cg = ((uchar*)color)[1]; 00644 int cr = ((uchar*)color)[2]; 00645 int pix_size = (int)img.elemSize(); 00646 uchar *ptr = img.ptr(), *tptr; 00647 size_t step = img.step; 00648 Size size = img.size(), sizeScaled(size.width*XY_ONE, size.height*XY_ONE); 00649 00650 //assert( img && (nch == 1 || nch == 3) && img.depth() == CV_8U ); 00651 00652 if( !clipLine( sizeScaled, pt1, pt2 )) 00653 return; 00654 00655 dx = pt2.x - pt1.x; 00656 dy = pt2.y - pt1.y; 00657 00658 j = dx < 0 ? -1 : 0; 00659 ax = (dx ^ j) - j; 00660 i = dy < 0 ? -1 : 0; 00661 ay = (dy ^ i) - i; 00662 00663 if( ax > ay ) 00664 { 00665 dx = ax; 00666 dy = (dy ^ j) - j; 00667 pt1.x ^= pt2.x & j; 00668 pt2.x ^= pt1.x & j; 00669 pt1.x ^= pt2.x & j; 00670 pt1.y ^= pt2.y & j; 00671 pt2.y ^= pt1.y & j; 00672 pt1.y ^= pt2.y & j; 00673 00674 x_step = XY_ONE; 00675 y_step = (int) (((int64) dy << XY_SHIFT) / (ax | 1)); 00676 ecount = (pt2.x - pt1.x) >> XY_SHIFT; 00677 } 00678 else 00679 { 00680 dy = ay; 00681 dx = (dx ^ i) - i; 00682 pt1.x ^= pt2.x & i; 00683 pt2.x ^= pt1.x & i; 00684 pt1.x ^= pt2.x & i; 00685 pt1.y ^= pt2.y & i; 00686 pt2.y ^= pt1.y & i; 00687 pt1.y ^= pt2.y & i; 00688 00689 x_step = (int) (((int64) dx << XY_SHIFT) / (ay | 1)); 00690 y_step = XY_ONE; 00691 ecount = (pt2.y - pt1.y) >> XY_SHIFT; 00692 } 00693 00694 pt1.x += (XY_ONE >> 1); 00695 pt1.y += (XY_ONE >> 1); 00696 00697 if( pix_size == 3 ) 00698 { 00699 #define ICV_PUT_POINT(_x,_y) \ 00700 x = (_x); y = (_y); \ 00701 if( 0 <= x && x < size.width && \ 00702 0 <= y && y < size.height ) \ 00703 { \ 00704 tptr = ptr + y*step + x*3; \ 00705 tptr[0] = (uchar)cb; \ 00706 tptr[1] = (uchar)cg; \ 00707 tptr[2] = (uchar)cr; \ 00708 } 00709 00710 ICV_PUT_POINT((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT, 00711 (pt2.y + (XY_ONE >> 1)) >> XY_SHIFT); 00712 00713 if( ax > ay ) 00714 { 00715 pt1.x >>= XY_SHIFT; 00716 00717 while( ecount >= 0 ) 00718 { 00719 ICV_PUT_POINT(pt1.x, pt1.y >> XY_SHIFT); 00720 pt1.x++; 00721 pt1.y += y_step; 00722 ecount--; 00723 } 00724 } 00725 else 00726 { 00727 pt1.y >>= XY_SHIFT; 00728 00729 while( ecount >= 0 ) 00730 { 00731 ICV_PUT_POINT(pt1.x >> XY_SHIFT, pt1.y); 00732 pt1.x += x_step; 00733 pt1.y++; 00734 ecount--; 00735 } 00736 } 00737 00738 #undef ICV_PUT_POINT 00739 } 00740 else if( pix_size == 1 ) 00741 { 00742 #define ICV_PUT_POINT(_x,_y) \ 00743 x = (_x); y = (_y); \ 00744 if( 0 <= x && x < size.width && \ 00745 0 <= y && y < size.height ) \ 00746 { \ 00747 tptr = ptr + y*step + x;\ 00748 tptr[0] = (uchar)cb; \ 00749 } 00750 00751 ICV_PUT_POINT((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT, 00752 (pt2.y + (XY_ONE >> 1)) >> XY_SHIFT); 00753 00754 if( ax > ay ) 00755 { 00756 pt1.x >>= XY_SHIFT; 00757 00758 while( ecount >= 0 ) 00759 { 00760 ICV_PUT_POINT(pt1.x, pt1.y >> XY_SHIFT); 00761 pt1.x++; 00762 pt1.y += y_step; 00763 ecount--; 00764 } 00765 } 00766 else 00767 { 00768 pt1.y >>= XY_SHIFT; 00769 00770 while( ecount >= 0 ) 00771 { 00772 ICV_PUT_POINT(pt1.x >> XY_SHIFT, pt1.y); 00773 pt1.x += x_step; 00774 pt1.y++; 00775 ecount--; 00776 } 00777 } 00778 00779 #undef ICV_PUT_POINT 00780 } 00781 else 00782 { 00783 #define ICV_PUT_POINT(_x,_y) \ 00784 x = (_x); y = (_y); \ 00785 if( 0 <= x && x < size.width && \ 00786 0 <= y && y < size.height ) \ 00787 { \ 00788 tptr = ptr + y*step + x*pix_size;\ 00789 for( j = 0; j < pix_size; j++ ) \ 00790 tptr[j] = ((uchar*)color)[j]; \ 00791 } 00792 00793 ICV_PUT_POINT((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT, 00794 (pt2.y + (XY_ONE >> 1)) >> XY_SHIFT); 00795 00796 if( ax > ay ) 00797 { 00798 pt1.x >>= XY_SHIFT; 00799 00800 while( ecount >= 0 ) 00801 { 00802 ICV_PUT_POINT(pt1.x, pt1.y >> XY_SHIFT); 00803 pt1.x++; 00804 pt1.y += y_step; 00805 ecount--; 00806 } 00807 } 00808 else 00809 { 00810 pt1.y >>= XY_SHIFT; 00811 00812 while( ecount >= 0 ) 00813 { 00814 ICV_PUT_POINT(pt1.x >> XY_SHIFT, pt1.y); 00815 pt1.x += x_step; 00816 pt1.y++; 00817 ecount--; 00818 } 00819 } 00820 00821 #undef ICV_PUT_POINT 00822 } 00823 } 00824 00825 00826 /****************************************************************************************\ 00827 * Antialiazed Elliptic Arcs via Antialiazed Lines * 00828 \****************************************************************************************/ 00829 00830 static const float SinTable[] = 00831 { 0.0000000f, 0.0174524f, 0.0348995f, 0.0523360f, 0.0697565f, 0.0871557f, 00832 0.1045285f, 0.1218693f, 0.1391731f, 0.1564345f, 0.1736482f, 0.1908090f, 00833 0.2079117f, 0.2249511f, 0.2419219f, 0.2588190f, 0.2756374f, 0.2923717f, 00834 0.3090170f, 0.3255682f, 0.3420201f, 0.3583679f, 0.3746066f, 0.3907311f, 00835 0.4067366f, 0.4226183f, 0.4383711f, 0.4539905f, 0.4694716f, 0.4848096f, 00836 0.5000000f, 0.5150381f, 0.5299193f, 0.5446390f, 0.5591929f, 0.5735764f, 00837 0.5877853f, 0.6018150f, 0.6156615f, 0.6293204f, 0.6427876f, 0.6560590f, 00838 0.6691306f, 0.6819984f, 0.6946584f, 0.7071068f, 0.7193398f, 0.7313537f, 00839 0.7431448f, 0.7547096f, 0.7660444f, 0.7771460f, 0.7880108f, 0.7986355f, 00840 0.8090170f, 0.8191520f, 0.8290376f, 0.8386706f, 0.8480481f, 0.8571673f, 00841 0.8660254f, 0.8746197f, 0.8829476f, 0.8910065f, 0.8987940f, 0.9063078f, 00842 0.9135455f, 0.9205049f, 0.9271839f, 0.9335804f, 0.9396926f, 0.9455186f, 00843 0.9510565f, 0.9563048f, 0.9612617f, 0.9659258f, 0.9702957f, 0.9743701f, 00844 0.9781476f, 0.9816272f, 0.9848078f, 0.9876883f, 0.9902681f, 0.9925462f, 00845 0.9945219f, 0.9961947f, 0.9975641f, 0.9986295f, 0.9993908f, 0.9998477f, 00846 1.0000000f, 0.9998477f, 0.9993908f, 0.9986295f, 0.9975641f, 0.9961947f, 00847 0.9945219f, 0.9925462f, 0.9902681f, 0.9876883f, 0.9848078f, 0.9816272f, 00848 0.9781476f, 0.9743701f, 0.9702957f, 0.9659258f, 0.9612617f, 0.9563048f, 00849 0.9510565f, 0.9455186f, 0.9396926f, 0.9335804f, 0.9271839f, 0.9205049f, 00850 0.9135455f, 0.9063078f, 0.8987940f, 0.8910065f, 0.8829476f, 0.8746197f, 00851 0.8660254f, 0.8571673f, 0.8480481f, 0.8386706f, 0.8290376f, 0.8191520f, 00852 0.8090170f, 0.7986355f, 0.7880108f, 0.7771460f, 0.7660444f, 0.7547096f, 00853 0.7431448f, 0.7313537f, 0.7193398f, 0.7071068f, 0.6946584f, 0.6819984f, 00854 0.6691306f, 0.6560590f, 0.6427876f, 0.6293204f, 0.6156615f, 0.6018150f, 00855 0.5877853f, 0.5735764f, 0.5591929f, 0.5446390f, 0.5299193f, 0.5150381f, 00856 0.5000000f, 0.4848096f, 0.4694716f, 0.4539905f, 0.4383711f, 0.4226183f, 00857 0.4067366f, 0.3907311f, 0.3746066f, 0.3583679f, 0.3420201f, 0.3255682f, 00858 0.3090170f, 0.2923717f, 0.2756374f, 0.2588190f, 0.2419219f, 0.2249511f, 00859 0.2079117f, 0.1908090f, 0.1736482f, 0.1564345f, 0.1391731f, 0.1218693f, 00860 0.1045285f, 0.0871557f, 0.0697565f, 0.0523360f, 0.0348995f, 0.0174524f, 00861 0.0000000f, -0.0174524f, -0.0348995f, -0.0523360f, -0.0697565f, -0.0871557f, 00862 -0.1045285f, -0.1218693f, -0.1391731f, -0.1564345f, -0.1736482f, -0.1908090f, 00863 -0.2079117f, -0.2249511f, -0.2419219f, -0.2588190f, -0.2756374f, -0.2923717f, 00864 -0.3090170f, -0.3255682f, -0.3420201f, -0.3583679f, -0.3746066f, -0.3907311f, 00865 -0.4067366f, -0.4226183f, -0.4383711f, -0.4539905f, -0.4694716f, -0.4848096f, 00866 -0.5000000f, -0.5150381f, -0.5299193f, -0.5446390f, -0.5591929f, -0.5735764f, 00867 -0.5877853f, -0.6018150f, -0.6156615f, -0.6293204f, -0.6427876f, -0.6560590f, 00868 -0.6691306f, -0.6819984f, -0.6946584f, -0.7071068f, -0.7193398f, -0.7313537f, 00869 -0.7431448f, -0.7547096f, -0.7660444f, -0.7771460f, -0.7880108f, -0.7986355f, 00870 -0.8090170f, -0.8191520f, -0.8290376f, -0.8386706f, -0.8480481f, -0.8571673f, 00871 -0.8660254f, -0.8746197f, -0.8829476f, -0.8910065f, -0.8987940f, -0.9063078f, 00872 -0.9135455f, -0.9205049f, -0.9271839f, -0.9335804f, -0.9396926f, -0.9455186f, 00873 -0.9510565f, -0.9563048f, -0.9612617f, -0.9659258f, -0.9702957f, -0.9743701f, 00874 -0.9781476f, -0.9816272f, -0.9848078f, -0.9876883f, -0.9902681f, -0.9925462f, 00875 -0.9945219f, -0.9961947f, -0.9975641f, -0.9986295f, -0.9993908f, -0.9998477f, 00876 -1.0000000f, -0.9998477f, -0.9993908f, -0.9986295f, -0.9975641f, -0.9961947f, 00877 -0.9945219f, -0.9925462f, -0.9902681f, -0.9876883f, -0.9848078f, -0.9816272f, 00878 -0.9781476f, -0.9743701f, -0.9702957f, -0.9659258f, -0.9612617f, -0.9563048f, 00879 -0.9510565f, -0.9455186f, -0.9396926f, -0.9335804f, -0.9271839f, -0.9205049f, 00880 -0.9135455f, -0.9063078f, -0.8987940f, -0.8910065f, -0.8829476f, -0.8746197f, 00881 -0.8660254f, -0.8571673f, -0.8480481f, -0.8386706f, -0.8290376f, -0.8191520f, 00882 -0.8090170f, -0.7986355f, -0.7880108f, -0.7771460f, -0.7660444f, -0.7547096f, 00883 -0.7431448f, -0.7313537f, -0.7193398f, -0.7071068f, -0.6946584f, -0.6819984f, 00884 -0.6691306f, -0.6560590f, -0.6427876f, -0.6293204f, -0.6156615f, -0.6018150f, 00885 -0.5877853f, -0.5735764f, -0.5591929f, -0.5446390f, -0.5299193f, -0.5150381f, 00886 -0.5000000f, -0.4848096f, -0.4694716f, -0.4539905f, -0.4383711f, -0.4226183f, 00887 -0.4067366f, -0.3907311f, -0.3746066f, -0.3583679f, -0.3420201f, -0.3255682f, 00888 -0.3090170f, -0.2923717f, -0.2756374f, -0.2588190f, -0.2419219f, -0.2249511f, 00889 -0.2079117f, -0.1908090f, -0.1736482f, -0.1564345f, -0.1391731f, -0.1218693f, 00890 -0.1045285f, -0.0871557f, -0.0697565f, -0.0523360f, -0.0348995f, -0.0174524f, 00891 -0.0000000f, 0.0174524f, 0.0348995f, 0.0523360f, 0.0697565f, 0.0871557f, 00892 0.1045285f, 0.1218693f, 0.1391731f, 0.1564345f, 0.1736482f, 0.1908090f, 00893 0.2079117f, 0.2249511f, 0.2419219f, 0.2588190f, 0.2756374f, 0.2923717f, 00894 0.3090170f, 0.3255682f, 0.3420201f, 0.3583679f, 0.3746066f, 0.3907311f, 00895 0.4067366f, 0.4226183f, 0.4383711f, 0.4539905f, 0.4694716f, 0.4848096f, 00896 0.5000000f, 0.5150381f, 0.5299193f, 0.5446390f, 0.5591929f, 0.5735764f, 00897 0.5877853f, 0.6018150f, 0.6156615f, 0.6293204f, 0.6427876f, 0.6560590f, 00898 0.6691306f, 0.6819984f, 0.6946584f, 0.7071068f, 0.7193398f, 0.7313537f, 00899 0.7431448f, 0.7547096f, 0.7660444f, 0.7771460f, 0.7880108f, 0.7986355f, 00900 0.8090170f, 0.8191520f, 0.8290376f, 0.8386706f, 0.8480481f, 0.8571673f, 00901 0.8660254f, 0.8746197f, 0.8829476f, 0.8910065f, 0.8987940f, 0.9063078f, 00902 0.9135455f, 0.9205049f, 0.9271839f, 0.9335804f, 0.9396926f, 0.9455186f, 00903 0.9510565f, 0.9563048f, 0.9612617f, 0.9659258f, 0.9702957f, 0.9743701f, 00904 0.9781476f, 0.9816272f, 0.9848078f, 0.9876883f, 0.9902681f, 0.9925462f, 00905 0.9945219f, 0.9961947f, 0.9975641f, 0.9986295f, 0.9993908f, 0.9998477f, 00906 1.0000000f 00907 }; 00908 00909 00910 static void 00911 sincos( int angle, float& cosval, float& sinval ) 00912 { 00913 angle += (angle < 0 ? 360 : 0); 00914 sinval = SinTable[angle]; 00915 cosval = SinTable[450 - angle]; 00916 } 00917 00918 /* 00919 constructs polygon that represents elliptic arc. 00920 */ 00921 void ellipse2Poly( Point center, Size axes, int angle, 00922 int arc_start, int arc_end, 00923 int delta, std::vector<Point>& pts ) 00924 { 00925 float alpha, beta; 00926 double size_a = axes.width, size_b = axes.height; 00927 double cx = center.x, cy = center.y; 00928 Point prevPt(INT_MIN,INT_MIN); 00929 int i; 00930 00931 while( angle < 0 ) 00932 angle += 360; 00933 while( angle > 360 ) 00934 angle -= 360; 00935 00936 if( arc_start > arc_end ) 00937 { 00938 i = arc_start; 00939 arc_start = arc_end; 00940 arc_end = i; 00941 } 00942 while( arc_start < 0 ) 00943 { 00944 arc_start += 360; 00945 arc_end += 360; 00946 } 00947 while( arc_end > 360 ) 00948 { 00949 arc_end -= 360; 00950 arc_start -= 360; 00951 } 00952 if( arc_end - arc_start > 360 ) 00953 { 00954 arc_start = 0; 00955 arc_end = 360; 00956 } 00957 sincos( angle, alpha, beta ); 00958 pts.resize(0); 00959 00960 for( i = arc_start; i < arc_end + delta; i += delta ) 00961 { 00962 double x, y; 00963 angle = i; 00964 if( angle > arc_end ) 00965 angle = arc_end; 00966 if( angle < 0 ) 00967 angle += 360; 00968 00969 x = size_a * SinTable[450-angle]; 00970 y = size_b * SinTable[angle]; 00971 Point pt; 00972 pt.x = cvRound( cx + x * alpha - y * beta ); 00973 pt.y = cvRound( cy + x * beta + y * alpha ); 00974 if( pt != prevPt ){ 00975 pts.push_back(pt); 00976 prevPt = pt; 00977 } 00978 } 00979 00980 // If there are no points, it's a zero-size polygon 00981 if( pts.size() == 1) { 00982 pts.assign(2,center); 00983 } 00984 } 00985 00986 00987 static void 00988 EllipseEx( Mat& img, Point center, Size axes, 00989 int angle, int arc_start, int arc_end, 00990 const void* color, int thickness, int line_type ) 00991 { 00992 axes.width = std::abs(axes.width), axes.height = std::abs(axes.height); 00993 int delta = (std::max(axes.width,axes.height)+(XY_ONE>>1))>>XY_SHIFT; 00994 delta = delta < 3 ? 90 : delta < 10 ? 30 : delta < 15 ? 18 : 5; 00995 00996 std::vector<Point> v; 00997 ellipse2Poly( center, axes, angle, arc_start, arc_end, delta, v ); 00998 00999 if( thickness >= 0 ) 01000 PolyLine( img, &v[0], (int)v.size(), false, color, thickness, line_type, XY_SHIFT ); 01001 else if( arc_end - arc_start >= 360 ) 01002 FillConvexPoly( img, &v[0], (int)v.size(), color, line_type, XY_SHIFT ); 01003 else 01004 { 01005 v.push_back(center); 01006 std::vector<PolyEdge> edges; 01007 CollectPolyEdges( img, &v[0], (int)v.size(), edges, color, line_type, XY_SHIFT ); 01008 FillEdgeCollection( img, edges, color ); 01009 } 01010 } 01011 01012 01013 /****************************************************************************************\ 01014 * Polygons filling * 01015 \****************************************************************************************/ 01016 01017 /* helper macros: filling horizontal row */ 01018 #define ICV_HLINE( ptr, xl, xr, color, pix_size ) \ 01019 { \ 01020 uchar* hline_ptr = (uchar*)(ptr) + (xl)*(pix_size); \ 01021 uchar* hline_max_ptr = (uchar*)(ptr) + (xr)*(pix_size); \ 01022 \ 01023 for( ; hline_ptr <= hline_max_ptr; hline_ptr += (pix_size))\ 01024 { \ 01025 int hline_j; \ 01026 for( hline_j = 0; hline_j < (pix_size); hline_j++ ) \ 01027 { \ 01028 hline_ptr[hline_j] = ((uchar*)color)[hline_j]; \ 01029 } \ 01030 } \ 01031 } 01032 01033 01034 /* filling convex polygon. v - array of vertices, ntps - number of points */ 01035 static void 01036 FillConvexPoly( Mat& img, const Point* v, int npts, const void* color, int line_type, int shift ) 01037 { 01038 struct 01039 { 01040 int idx, di; 01041 int x, dx, ye; 01042 } 01043 edge[2]; 01044 01045 int delta = shift ? 1 << (shift - 1) : 0; 01046 int i, y, imin = 0, left = 0, right = 1, x1, x2; 01047 int edges = npts; 01048 int xmin, xmax, ymin, ymax; 01049 uchar* ptr = img.ptr(); 01050 Size size = img.size(); 01051 int pix_size = (int)img.elemSize(); 01052 Point p0; 01053 int delta1, delta2; 01054 01055 if( line_type < CV_AA ) 01056 delta1 = delta2 = XY_ONE >> 1; 01057 else 01058 delta1 = XY_ONE - 1, delta2 = 0; 01059 01060 p0 = v[npts - 1]; 01061 p0.x <<= XY_SHIFT - shift; 01062 p0.y <<= XY_SHIFT - shift; 01063 01064 assert( 0 <= shift && shift <= XY_SHIFT ); 01065 xmin = xmax = v[0].x; 01066 ymin = ymax = v[0].y; 01067 01068 for( i = 0; i < npts; i++ ) 01069 { 01070 Point p = v[i]; 01071 if( p.y < ymin ) 01072 { 01073 ymin = p.y; 01074 imin = i; 01075 } 01076 01077 ymax = std::max( ymax, p.y ); 01078 xmax = std::max( xmax, p.x ); 01079 xmin = MIN( xmin, p.x ); 01080 01081 p.x <<= XY_SHIFT - shift; 01082 p.y <<= XY_SHIFT - shift; 01083 01084 if( line_type <= 8 ) 01085 { 01086 if( shift == 0 ) 01087 { 01088 Point pt0, pt1; 01089 pt0.x = p0.x >> XY_SHIFT; 01090 pt0.y = p0.y >> XY_SHIFT; 01091 pt1.x = p.x >> XY_SHIFT; 01092 pt1.y = p.y >> XY_SHIFT; 01093 Line( img, pt0, pt1, color, line_type ); 01094 } 01095 else 01096 Line2( img, p0, p, color ); 01097 } 01098 else 01099 LineAA( img, p0, p, color ); 01100 p0 = p; 01101 } 01102 01103 xmin = (xmin + delta) >> shift; 01104 xmax = (xmax + delta) >> shift; 01105 ymin = (ymin + delta) >> shift; 01106 ymax = (ymax + delta) >> shift; 01107 01108 if( npts < 3 || xmax < 0 || ymax < 0 || xmin >= size.width || ymin >= size.height ) 01109 return; 01110 01111 ymax = MIN( ymax, size.height - 1 ); 01112 edge[0].idx = edge[1].idx = imin; 01113 01114 edge[0].ye = edge[1].ye = y = ymin; 01115 edge[0].di = 1; 01116 edge[1].di = npts - 1; 01117 01118 ptr += img.step*y; 01119 01120 do 01121 { 01122 if( line_type < CV_AA || y < ymax || y == ymin ) 01123 { 01124 for( i = 0; i < 2; i++ ) 01125 { 01126 if( y >= edge[i].ye ) 01127 { 01128 int idx = edge[i].idx, di = edge[i].di; 01129 int xs = 0, xe, ye, ty = 0; 01130 01131 for(;;) 01132 { 01133 ty = (v[idx].y + delta) >> shift; 01134 if( ty > y || edges == 0 ) 01135 break; 01136 xs = v[idx].x; 01137 idx += di; 01138 idx -= ((idx < npts) - 1) & npts; /* idx -= idx >= npts ? npts : 0 */ 01139 edges--; 01140 } 01141 01142 ye = ty; 01143 xs <<= XY_SHIFT - shift; 01144 xe = v[idx].x << (XY_SHIFT - shift); 01145 01146 /* no more edges */ 01147 if( y >= ye ) 01148 return; 01149 01150 edge[i].ye = ye; 01151 edge[i].dx = ((xe - xs)*2 + (ye - y)) / (2 * (ye - y)); 01152 edge[i].x = xs; 01153 edge[i].idx = idx; 01154 } 01155 } 01156 } 01157 01158 if( edge[left].x > edge[right].x ) 01159 { 01160 left ^= 1; 01161 right ^= 1; 01162 } 01163 01164 x1 = edge[left].x; 01165 x2 = edge[right].x; 01166 01167 if( y >= 0 ) 01168 { 01169 int xx1 = (x1 + delta1) >> XY_SHIFT; 01170 int xx2 = (x2 + delta2) >> XY_SHIFT; 01171 01172 if( xx2 >= 0 && xx1 < size.width ) 01173 { 01174 if( xx1 < 0 ) 01175 xx1 = 0; 01176 if( xx2 >= size.width ) 01177 xx2 = size.width - 1; 01178 ICV_HLINE( ptr, xx1, xx2, color, pix_size ); 01179 } 01180 } 01181 01182 x1 += edge[left].dx; 01183 x2 += edge[right].dx; 01184 01185 edge[left].x = x1; 01186 edge[right].x = x2; 01187 ptr += img.step; 01188 } 01189 while( ++y <= ymax ); 01190 } 01191 01192 01193 /******** Arbitrary polygon **********/ 01194 01195 static void 01196 CollectPolyEdges( Mat& img, const Point* v, int count, std::vector<PolyEdge>& edges, 01197 const void* color, int line_type, int shift, Point offset ) 01198 { 01199 int i, delta = offset.y + (shift ? 1 << (shift - 1) : 0); 01200 Point pt0 = v[count-1], pt1; 01201 pt0.x = (pt0.x + offset.x) << (XY_SHIFT - shift); 01202 pt0.y = (pt0.y + delta) >> shift; 01203 01204 edges.reserve( edges.size() + count ); 01205 01206 for( i = 0; i < count; i++, pt0 = pt1 ) 01207 { 01208 Point t0, t1; 01209 PolyEdge edge; 01210 01211 pt1 = v[i]; 01212 pt1.x = (pt1.x + offset.x) << (XY_SHIFT - shift); 01213 pt1.y = (pt1.y + delta) >> shift; 01214 01215 if( line_type < CV_AA ) 01216 { 01217 t0.y = pt0.y; t1.y = pt1.y; 01218 t0.x = (pt0.x + (XY_ONE >> 1)) >> XY_SHIFT; 01219 t1.x = (pt1.x + (XY_ONE >> 1)) >> XY_SHIFT; 01220 Line( img, t0, t1, color, line_type ); 01221 } 01222 else 01223 { 01224 t0.x = pt0.x; t1.x = pt1.x; 01225 t0.y = pt0.y << XY_SHIFT; 01226 t1.y = pt1.y << XY_SHIFT; 01227 LineAA( img, t0, t1, color ); 01228 } 01229 01230 if( pt0.y == pt1.y ) 01231 continue; 01232 01233 if( pt0.y < pt1.y ) 01234 { 01235 edge.y0 = pt0.y; 01236 edge.y1 = pt1.y; 01237 edge.x = pt0.x; 01238 } 01239 else 01240 { 01241 edge.y0 = pt1.y; 01242 edge.y1 = pt0.y; 01243 edge.x = pt1.x; 01244 } 01245 edge.dx = (pt1.x - pt0.x) / (pt1.y - pt0.y); 01246 edges.push_back(edge); 01247 } 01248 } 01249 01250 struct CmpEdges 01251 { 01252 bool operator ()(const PolyEdge& e1, const PolyEdge& e2) 01253 { 01254 return e1.y0 - e2.y0 ? e1.y0 < e2.y0 : 01255 e1.x - e2.x ? e1.x < e2.x : e1.dx < e2.dx; 01256 } 01257 }; 01258 01259 /**************** helper macros and functions for sequence/contour processing ***********/ 01260 01261 static void 01262 FillEdgeCollection( Mat& img, std::vector<PolyEdge>& edges, const void* color ) 01263 { 01264 PolyEdge tmp; 01265 int i, y, total = (int)edges.size(); 01266 Size size = img.size(); 01267 PolyEdge* e; 01268 int y_max = INT_MIN, x_max = INT_MIN, y_min = INT_MAX, x_min = INT_MAX; 01269 int pix_size = (int)img.elemSize(); 01270 01271 if( total < 2 ) 01272 return; 01273 01274 for( i = 0; i < total; i++ ) 01275 { 01276 PolyEdge& e1 = edges[i]; 01277 assert( e1.y0 < e1.y1 ); 01278 // Determine x-coordinate of the end of the edge. 01279 // (This is not necessary x-coordinate of any vertex in the array.) 01280 int x1 = e1.x + (e1.y1 - e1.y0) * e1.dx; 01281 y_min = std::min( y_min, e1.y0 ); 01282 y_max = std::max( y_max, e1.y1 ); 01283 x_min = std::min( x_min, e1.x ); 01284 x_max = std::max( x_max, e1.x ); 01285 x_min = std::min( x_min, x1 ); 01286 x_max = std::max( x_max, x1 ); 01287 } 01288 01289 if( y_max < 0 || y_min >= size.height || x_max < 0 || x_min >= (size.width<<XY_SHIFT) ) 01290 return; 01291 01292 std::sort( edges.begin(), edges.end(), CmpEdges() ); 01293 01294 // start drawing 01295 tmp.y0 = INT_MAX; 01296 edges.push_back(tmp); // after this point we do not add 01297 // any elements to edges, thus we can use pointers 01298 i = 0; 01299 tmp.next = 0; 01300 e = &edges[i]; 01301 y_max = MIN( y_max, size.height ); 01302 01303 for( y = e->y0; y < y_max; y++ ) 01304 { 01305 PolyEdge *last, *prelast, *keep_prelast; 01306 int sort_flag = 0; 01307 int draw = 0; 01308 int clipline = y < 0; 01309 01310 prelast = &tmp; 01311 last = tmp.next; 01312 while( last || e->y0 == y ) 01313 { 01314 if( last && last->y1 == y ) 01315 { 01316 // exclude edge if y reachs its lower point 01317 prelast->next = last->next; 01318 last = last->next; 01319 continue; 01320 } 01321 keep_prelast = prelast; 01322 if( last && (e->y0 > y || last->x < e->x) ) 01323 { 01324 // go to the next edge in active list 01325 prelast = last; 01326 last = last->next; 01327 } 01328 else if( i < total ) 01329 { 01330 // insert new edge into active list if y reachs its upper point 01331 prelast->next = e; 01332 e->next = last; 01333 prelast = e; 01334 e = &edges[++i]; 01335 } 01336 else 01337 break; 01338 01339 if( draw ) 01340 { 01341 if( !clipline ) 01342 { 01343 // convert x's from fixed-point to image coordinates 01344 uchar *timg = img.ptr(y); 01345 int x1 = keep_prelast->x; 01346 int x2 = prelast->x; 01347 01348 if( x1 > x2 ) 01349 { 01350 int t = x1; 01351 01352 x1 = x2; 01353 x2 = t; 01354 } 01355 01356 x1 = (x1 + XY_ONE - 1) >> XY_SHIFT; 01357 x2 = x2 >> XY_SHIFT; 01358 01359 // clip and draw the line 01360 if( x1 < size.width && x2 >= 0 ) 01361 { 01362 if( x1 < 0 ) 01363 x1 = 0; 01364 if( x2 >= size.width ) 01365 x2 = size.width - 1; 01366 ICV_HLINE( timg, x1, x2, color, pix_size ); 01367 } 01368 } 01369 keep_prelast->x += keep_prelast->dx; 01370 prelast->x += prelast->dx; 01371 } 01372 draw ^= 1; 01373 } 01374 01375 // sort edges (using bubble sort) 01376 keep_prelast = 0; 01377 01378 do 01379 { 01380 prelast = &tmp; 01381 last = tmp.next; 01382 01383 while( last != keep_prelast && last->next != 0 ) 01384 { 01385 PolyEdge *te = last->next; 01386 01387 // swap edges 01388 if( last->x > te->x ) 01389 { 01390 prelast->next = te; 01391 last->next = te->next; 01392 te->next = last; 01393 prelast = te; 01394 sort_flag = 1; 01395 } 01396 else 01397 { 01398 prelast = last; 01399 last = te; 01400 } 01401 } 01402 keep_prelast = prelast; 01403 } 01404 while( sort_flag && keep_prelast != tmp.next && keep_prelast != &tmp ); 01405 } 01406 } 01407 01408 01409 /* draws simple or filled circle */ 01410 static void 01411 Circle( Mat& img, Point center, int radius, const void* color, int fill ) 01412 { 01413 Size size = img.size(); 01414 size_t step = img.step; 01415 int pix_size = (int)img.elemSize(); 01416 uchar* ptr = img.ptr(); 01417 int err = 0, dx = radius, dy = 0, plus = 1, minus = (radius << 1) - 1; 01418 int inside = center.x >= radius && center.x < size.width - radius && 01419 center.y >= radius && center.y < size.height - radius; 01420 01421 #define ICV_PUT_POINT( ptr, x ) \ 01422 memcpy( ptr + (x)*pix_size, color, pix_size ); 01423 01424 while( dx >= dy ) 01425 { 01426 int mask; 01427 int y11 = center.y - dy, y12 = center.y + dy, y21 = center.y - dx, y22 = center.y + dx; 01428 int x11 = center.x - dx, x12 = center.x + dx, x21 = center.x - dy, x22 = center.x + dy; 01429 01430 if( inside ) 01431 { 01432 uchar *tptr0 = ptr + y11 * step; 01433 uchar *tptr1 = ptr + y12 * step; 01434 01435 if( !fill ) 01436 { 01437 ICV_PUT_POINT( tptr0, x11 ); 01438 ICV_PUT_POINT( tptr1, x11 ); 01439 ICV_PUT_POINT( tptr0, x12 ); 01440 ICV_PUT_POINT( tptr1, x12 ); 01441 } 01442 else 01443 { 01444 ICV_HLINE( tptr0, x11, x12, color, pix_size ); 01445 ICV_HLINE( tptr1, x11, x12, color, pix_size ); 01446 } 01447 01448 tptr0 = ptr + y21 * step; 01449 tptr1 = ptr + y22 * step; 01450 01451 if( !fill ) 01452 { 01453 ICV_PUT_POINT( tptr0, x21 ); 01454 ICV_PUT_POINT( tptr1, x21 ); 01455 ICV_PUT_POINT( tptr0, x22 ); 01456 ICV_PUT_POINT( tptr1, x22 ); 01457 } 01458 else 01459 { 01460 ICV_HLINE( tptr0, x21, x22, color, pix_size ); 01461 ICV_HLINE( tptr1, x21, x22, color, pix_size ); 01462 } 01463 } 01464 else if( x11 < size.width && x12 >= 0 && y21 < size.height && y22 >= 0 ) 01465 { 01466 if( fill ) 01467 { 01468 x11 = std::max( x11, 0 ); 01469 x12 = MIN( x12, size.width - 1 ); 01470 } 01471 01472 if( (unsigned)y11 < (unsigned)size.height ) 01473 { 01474 uchar *tptr = ptr + y11 * step; 01475 01476 if( !fill ) 01477 { 01478 if( x11 >= 0 ) 01479 ICV_PUT_POINT( tptr, x11 ); 01480 if( x12 < size.width ) 01481 ICV_PUT_POINT( tptr, x12 ); 01482 } 01483 else 01484 ICV_HLINE( tptr, x11, x12, color, pix_size ); 01485 } 01486 01487 if( (unsigned)y12 < (unsigned)size.height ) 01488 { 01489 uchar *tptr = ptr + y12 * step; 01490 01491 if( !fill ) 01492 { 01493 if( x11 >= 0 ) 01494 ICV_PUT_POINT( tptr, x11 ); 01495 if( x12 < size.width ) 01496 ICV_PUT_POINT( tptr, x12 ); 01497 } 01498 else 01499 ICV_HLINE( tptr, x11, x12, color, pix_size ); 01500 } 01501 01502 if( x21 < size.width && x22 >= 0 ) 01503 { 01504 if( fill ) 01505 { 01506 x21 = std::max( x21, 0 ); 01507 x22 = MIN( x22, size.width - 1 ); 01508 } 01509 01510 if( (unsigned)y21 < (unsigned)size.height ) 01511 { 01512 uchar *tptr = ptr + y21 * step; 01513 01514 if( !fill ) 01515 { 01516 if( x21 >= 0 ) 01517 ICV_PUT_POINT( tptr, x21 ); 01518 if( x22 < size.width ) 01519 ICV_PUT_POINT( tptr, x22 ); 01520 } 01521 else 01522 ICV_HLINE( tptr, x21, x22, color, pix_size ); 01523 } 01524 01525 if( (unsigned)y22 < (unsigned)size.height ) 01526 { 01527 uchar *tptr = ptr + y22 * step; 01528 01529 if( !fill ) 01530 { 01531 if( x21 >= 0 ) 01532 ICV_PUT_POINT( tptr, x21 ); 01533 if( x22 < size.width ) 01534 ICV_PUT_POINT( tptr, x22 ); 01535 } 01536 else 01537 ICV_HLINE( tptr, x21, x22, color, pix_size ); 01538 } 01539 } 01540 } 01541 dy++; 01542 err += plus; 01543 plus += 2; 01544 01545 mask = (err <= 0) - 1; 01546 01547 err -= minus & mask; 01548 dx += mask; 01549 minus -= mask & 2; 01550 } 01551 01552 #undef ICV_PUT_POINT 01553 } 01554 01555 01556 static void 01557 ThickLine( Mat& img, Point p0, Point p1, const void* color, 01558 int thickness, int line_type, int flags, int shift ) 01559 { 01560 static const double INV_XY_ONE = 1./XY_ONE; 01561 01562 p0.x <<= XY_SHIFT - shift; 01563 p0.y <<= XY_SHIFT - shift; 01564 p1.x <<= XY_SHIFT - shift; 01565 p1.y <<= XY_SHIFT - shift; 01566 01567 if( thickness <= 1 ) 01568 { 01569 if( line_type < CV_AA ) 01570 { 01571 if( line_type == 1 || line_type == 4 || shift == 0 ) 01572 { 01573 p0.x = (p0.x + (XY_ONE>>1)) >> XY_SHIFT; 01574 p0.y = (p0.y + (XY_ONE>>1)) >> XY_SHIFT; 01575 p1.x = (p1.x + (XY_ONE>>1)) >> XY_SHIFT; 01576 p1.y = (p1.y + (XY_ONE>>1)) >> XY_SHIFT; 01577 Line( img, p0, p1, color, line_type ); 01578 } 01579 else 01580 Line2( img, p0, p1, color ); 01581 } 01582 else 01583 LineAA( img, p0, p1, color ); 01584 } 01585 else 01586 { 01587 Point pt[4], dp = Point(0,0); 01588 double dx = (p0.x - p1.x)*INV_XY_ONE, dy = (p1.y - p0.y)*INV_XY_ONE; 01589 double r = dx * dx + dy * dy; 01590 int i, oddThickness = thickness & 1; 01591 thickness <<= XY_SHIFT - 1; 01592 01593 if( fabs(r) > DBL_EPSILON ) 01594 { 01595 r = (thickness + oddThickness*XY_ONE*0.5)/std::sqrt(r); 01596 dp.x = cvRound( dy * r ); 01597 dp.y = cvRound( dx * r ); 01598 01599 pt[0].x = p0.x + dp.x; 01600 pt[0].y = p0.y + dp.y; 01601 pt[1].x = p0.x - dp.x; 01602 pt[1].y = p0.y - dp.y; 01603 pt[2].x = p1.x - dp.x; 01604 pt[2].y = p1.y - dp.y; 01605 pt[3].x = p1.x + dp.x; 01606 pt[3].y = p1.y + dp.y; 01607 01608 FillConvexPoly( img, pt, 4, color, line_type, XY_SHIFT ); 01609 } 01610 01611 for( i = 0; i < 2; i++ ) 01612 { 01613 if( flags & (i+1) ) 01614 { 01615 if( line_type < CV_AA ) 01616 { 01617 Point center; 01618 center.x = (p0.x + (XY_ONE>>1)) >> XY_SHIFT; 01619 center.y = (p0.y + (XY_ONE>>1)) >> XY_SHIFT; 01620 Circle( img, center, (thickness + (XY_ONE>>1)) >> XY_SHIFT, color, 1 ); 01621 } 01622 else 01623 { 01624 EllipseEx( img, p0, cvSize(thickness, thickness), 01625 0, 0, 360, color, -1, line_type ); 01626 } 01627 } 01628 p0 = p1; 01629 } 01630 } 01631 } 01632 01633 01634 static void 01635 PolyLine( Mat& img, const Point* v, int count, bool is_closed, 01636 const void* color, int thickness, 01637 int line_type, int shift ) 01638 { 01639 if( !v || count <= 0 ) 01640 return; 01641 01642 int i = is_closed ? count - 1 : 0; 01643 int flags = 2 + !is_closed; 01644 Point p0; 01645 CV_Assert( 0 <= shift && shift <= XY_SHIFT && thickness >= 0 ); 01646 01647 p0 = v[i]; 01648 for( i = !is_closed; i < count; i++ ) 01649 { 01650 Point p = v[i]; 01651 ThickLine( img, p0, p, color, thickness, line_type, flags, shift ); 01652 p0 = p; 01653 flags = 2; 01654 } 01655 } 01656 01657 /* ----------------------------------------------------------------------------------------- */ 01658 /* ADDING A SET OF PREDEFINED MARKERS WHICH COULD BE USED TO HIGHLIGHT POSITIONS IN AN IMAGE */ 01659 /* ----------------------------------------------------------------------------------------- */ 01660 01661 void drawMarker(Mat& img, Point position, const Scalar& color, int markerType, int markerSize, int thickness, int line_type) 01662 { 01663 switch(markerType) 01664 { 01665 // The cross marker case 01666 case MARKER_CROSS: 01667 line(img, Point(position.x-(markerSize/2), position.y), Point(position.x+(markerSize/2), position.y), color, thickness, line_type); 01668 line(img, Point(position.x, position.y-(markerSize/2)), Point(position.x, position.y+(markerSize/2)), color, thickness, line_type); 01669 break; 01670 01671 // The tilted cross marker case 01672 case MARKER_TILTED_CROSS: 01673 line(img, Point(position.x-(markerSize/2), position.y-(markerSize/2)), Point(position.x+(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type); 01674 line(img, Point(position.x+(markerSize/2), position.y-(markerSize/2)), Point(position.x-(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type); 01675 break; 01676 01677 // The star marker case 01678 case MARKER_STAR: 01679 line(img, Point(position.x-(markerSize/2), position.y), Point(position.x+(markerSize/2), position.y), color, thickness, line_type); 01680 line(img, Point(position.x, position.y-(markerSize/2)), Point(position.x, position.y+(markerSize/2)), color, thickness, line_type); 01681 line(img, Point(position.x-(markerSize/2), position.y-(markerSize/2)), Point(position.x+(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type); 01682 line(img, Point(position.x+(markerSize/2), position.y-(markerSize/2)), Point(position.x-(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type); 01683 break; 01684 01685 // The diamond marker case 01686 case MARKER_DIAMOND: 01687 line(img, Point(position.x, position.y-(markerSize/2)), Point(position.x+(markerSize/2), position.y), color, thickness, line_type); 01688 line(img, Point(position.x+(markerSize/2), position.y), Point(position.x, position.y+(markerSize/2)), color, thickness, line_type); 01689 line(img, Point(position.x, position.y+(markerSize/2)), Point(position.x-(markerSize/2), position.y), color, thickness, line_type); 01690 line(img, Point(position.x-(markerSize/2), position.y), Point(position.x, position.y-(markerSize/2)), color, thickness, line_type); 01691 break; 01692 01693 // The square marker case 01694 case MARKER_SQUARE: 01695 line(img, Point(position.x-(markerSize/2), position.y-(markerSize/2)), Point(position.x+(markerSize/2), position.y-(markerSize/2)), color, thickness, line_type); 01696 line(img, Point(position.x+(markerSize/2), position.y-(markerSize/2)), Point(position.x+(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type); 01697 line(img, Point(position.x+(markerSize/2), position.y+(markerSize/2)), Point(position.x-(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type); 01698 line(img, Point(position.x-(markerSize/2), position.y+(markerSize/2)), Point(position.x-(markerSize/2), position.y-(markerSize/2)), color, thickness, line_type); 01699 break; 01700 01701 // The triangle up marker case 01702 case MARKER_TRIANGLE_UP: 01703 line(img, Point(position.x-(markerSize/2), position.y+(markerSize/2)), Point(position.x+(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type); 01704 line(img, Point(position.x+(markerSize/2), position.y+(markerSize/2)), Point(position.x, position.y-(markerSize/2)), color, thickness, line_type); 01705 line(img, Point(position.x, position.y-(markerSize/2)), Point(position.x-(markerSize/2), position.y-(markerSize/2)), color, thickness, line_type); 01706 break; 01707 01708 // The triangle down marker case 01709 case MARKER_TRIANGLE_DOWN: 01710 line(img, Point(position.x-(markerSize/2), position.y-(markerSize/2)), Point(position.x+(markerSize/2), position.y-(markerSize/2)), color, thickness, line_type); 01711 line(img, Point(position.x+(markerSize/2), position.y-(markerSize/2)), Point(position.x, position.y+(markerSize/2)), color, thickness, line_type); 01712 line(img, Point(position.x, position.y+(markerSize/2)), Point(position.x-(markerSize/2), position.y-(markerSize/2)), color, thickness, line_type); 01713 break; 01714 01715 // If any number that doesn't exist is entered as marker type, draw a cross marker, to avoid crashes 01716 default: 01717 drawMarker(img, position, color, MARKER_CROSS, markerSize, thickness, line_type); 01718 break; 01719 } 01720 } 01721 01722 /****************************************************************************************\ 01723 * External functions * 01724 \****************************************************************************************/ 01725 01726 void line( InputOutputArray _img, Point pt1, Point pt2, const Scalar & color, 01727 int thickness, int line_type, int shift ) 01728 { 01729 Mat img = _img.getMat(); 01730 01731 if( line_type == CV_AA && img.depth() != CV_8U ) 01732 line_type = 8; 01733 01734 CV_Assert( 0 <= thickness && thickness <= MAX_THICKNESS ); 01735 CV_Assert( 0 <= shift && shift <= XY_SHIFT ); 01736 01737 double buf[4]; 01738 scalarToRawData( color, buf, img.type(), 0 ); 01739 ThickLine( img, pt1, pt2, buf, thickness, line_type, 3, shift ); 01740 } 01741 01742 void arrowedLine(InputOutputArray img, Point pt1, Point pt2, const Scalar & color, 01743 int thickness, int line_type, int shift, double tipLength) 01744 { 01745 const double tipSize = norm(pt1-pt2)*tipLength; // Factor to normalize the size of the tip depending on the length of the arrow 01746 01747 line(img, pt1, pt2, color, thickness, line_type, shift); 01748 01749 const double angle = atan2( (double) pt1.y - pt2.y, (double) pt1.x - pt2.x ); 01750 01751 Point p(cvRound(pt2.x + tipSize * cos(angle + CV_PI / 4)), 01752 cvRound(pt2.y + tipSize * sin(angle + CV_PI / 4))); 01753 line(img, p, pt2, color, thickness, line_type, shift); 01754 01755 p.x = cvRound(pt2.x + tipSize * cos(angle - CV_PI / 4)); 01756 p.y = cvRound(pt2.y + tipSize * sin(angle - CV_PI / 4)); 01757 line(img, p, pt2, color, thickness, line_type, shift); 01758 } 01759 01760 void rectangle( InputOutputArray _img, Point pt1, Point pt2, 01761 const Scalar & color, int thickness, 01762 int lineType, int shift ) 01763 { 01764 Mat img = _img.getMat(); 01765 01766 if( lineType == CV_AA && img.depth() != CV_8U ) 01767 lineType = 8; 01768 01769 CV_Assert( thickness <= MAX_THICKNESS ); 01770 CV_Assert( 0 <= shift && shift <= XY_SHIFT ); 01771 01772 double buf[4]; 01773 scalarToRawData(color, buf, img.type(), 0); 01774 01775 Point pt[4]; 01776 01777 pt[0] = pt1; 01778 pt[1].x = pt2.x; 01779 pt[1].y = pt1.y; 01780 pt[2] = pt2; 01781 pt[3].x = pt1.x; 01782 pt[3].y = pt2.y; 01783 01784 if( thickness >= 0 ) 01785 PolyLine( img, pt, 4, true, buf, thickness, lineType, shift ); 01786 else 01787 FillConvexPoly( img, pt, 4, buf, lineType, shift ); 01788 } 01789 01790 01791 void rectangle( Mat& img, Rect rec, 01792 const Scalar& color, int thickness, 01793 int lineType, int shift ) 01794 { 01795 CV_Assert( 0 <= shift && shift <= XY_SHIFT ); 01796 if( rec.area() > 0 ) 01797 rectangle( img, rec.tl(), rec.br() - Point(1<<shift,1<<shift), 01798 color, thickness, lineType, shift ); 01799 } 01800 01801 01802 void circle( InputOutputArray _img, Point center, int radius, 01803 const Scalar & color, int thickness, int line_type, int shift ) 01804 { 01805 Mat img = _img.getMat(); 01806 01807 if( line_type == CV_AA && img.depth() != CV_8U ) 01808 line_type = 8; 01809 01810 CV_Assert( radius >= 0 && thickness <= MAX_THICKNESS && 01811 0 <= shift && shift <= XY_SHIFT ); 01812 01813 double buf[4]; 01814 scalarToRawData(color, buf, img.type(), 0); 01815 01816 if( thickness > 1 || line_type >= CV_AA || shift > 0 ) 01817 { 01818 center.x <<= XY_SHIFT - shift; 01819 center.y <<= XY_SHIFT - shift; 01820 radius <<= XY_SHIFT - shift; 01821 EllipseEx( img, center, Size(radius, radius), 01822 0, 0, 360, buf, thickness, line_type ); 01823 } 01824 else 01825 Circle( img, center, radius, buf, thickness < 0 ); 01826 } 01827 01828 01829 void ellipse( InputOutputArray _img, Point center, Size axes, 01830 double angle, double start_angle, double end_angle, 01831 const Scalar & color, int thickness, int line_type, int shift ) 01832 { 01833 Mat img = _img.getMat(); 01834 01835 if( line_type == CV_AA && img.depth() != CV_8U ) 01836 line_type = 8; 01837 01838 CV_Assert( axes.width >= 0 && axes.height >= 0 && 01839 thickness <= MAX_THICKNESS && 0 <= shift && shift <= XY_SHIFT ); 01840 01841 double buf[4]; 01842 scalarToRawData(color, buf, img.type(), 0); 01843 01844 int _angle = cvRound(angle); 01845 int _start_angle = cvRound(start_angle); 01846 int _end_angle = cvRound(end_angle); 01847 center.x <<= XY_SHIFT - shift; 01848 center.y <<= XY_SHIFT - shift; 01849 axes.width <<= XY_SHIFT - shift; 01850 axes.height <<= XY_SHIFT - shift; 01851 01852 EllipseEx( img, center, axes, _angle, _start_angle, 01853 _end_angle, buf, thickness, line_type ); 01854 } 01855 01856 void ellipse(InputOutputArray _img, const RotatedRect& box, const Scalar & color, 01857 int thickness, int lineType) 01858 { 01859 Mat img = _img.getMat(); 01860 01861 if( lineType == CV_AA && img.depth() != CV_8U ) 01862 lineType = 8; 01863 01864 CV_Assert( box.size.width >= 0 && box.size.height >= 0 && 01865 thickness <= MAX_THICKNESS ); 01866 01867 double buf[4]; 01868 scalarToRawData(color, buf, img.type(), 0); 01869 01870 int _angle = cvRound(box.angle); 01871 Point center(cvRound(box.center.x*(1 << XY_SHIFT)), 01872 cvRound(box.center.y*(1 << XY_SHIFT))); 01873 Size axes(cvRound(box.size.width*(1 << (XY_SHIFT - 1))), 01874 cvRound(box.size.height*(1 << (XY_SHIFT - 1)))); 01875 EllipseEx( img, center, axes, _angle, 0, 360, buf, thickness, lineType ); 01876 } 01877 01878 void fillConvexPoly ( Mat& img, const Point* pts, int npts, 01879 const Scalar & color, int line_type, int shift ) 01880 { 01881 if( !pts || npts <= 0 ) 01882 return; 01883 01884 if( line_type == CV_AA && img.depth() != CV_8U ) 01885 line_type = 8; 01886 01887 double buf[4]; 01888 CV_Assert( 0 <= shift && shift <= XY_SHIFT ); 01889 scalarToRawData(color, buf, img.type(), 0); 01890 FillConvexPoly( img, pts, npts, buf, line_type, shift ); 01891 } 01892 01893 01894 void fillPoly ( Mat& img, const Point** pts, const int* npts, int ncontours, 01895 const Scalar & color, int line_type, 01896 int shift, Point offset ) 01897 { 01898 if( line_type == CV_AA && img.depth() != CV_8U ) 01899 line_type = 8; 01900 01901 CV_Assert( pts && npts && ncontours >= 0 && 0 <= shift && shift <= XY_SHIFT ); 01902 01903 double buf[4]; 01904 scalarToRawData(color, buf, img.type(), 0); 01905 01906 std::vector<PolyEdge> edges; 01907 01908 int i, total = 0; 01909 for( i = 0; i < ncontours; i++ ) 01910 total += npts[i]; 01911 01912 edges.reserve( total + 1 ); 01913 for( i = 0; i < ncontours; i++ ) 01914 CollectPolyEdges( img, pts[i], npts[i], edges, buf, line_type, shift, offset ); 01915 01916 FillEdgeCollection(img, edges, buf); 01917 } 01918 01919 01920 void polylines ( Mat& img, const Point* const* pts, const int* npts, int ncontours, bool isClosed, 01921 const Scalar & color, int thickness, int line_type, int shift ) 01922 { 01923 if( line_type == CV_AA && img.depth() != CV_8U ) 01924 line_type = 8; 01925 01926 CV_Assert( pts && npts && ncontours >= 0 && 01927 0 <= thickness && thickness <= MAX_THICKNESS && 01928 0 <= shift && shift <= XY_SHIFT ); 01929 01930 double buf[4]; 01931 scalarToRawData( color, buf, img.type(), 0 ); 01932 01933 for( int i = 0; i < ncontours; i++ ) 01934 PolyLine( img, pts[i], npts[i], isClosed, buf, thickness, line_type, shift ); 01935 } 01936 01937 01938 enum { FONT_SIZE_SHIFT=8, FONT_ITALIC_ALPHA=(1 << 8), 01939 FONT_ITALIC_DIGIT=(2 << 8), FONT_ITALIC_PUNCT=(4 << 8), 01940 FONT_ITALIC_BRACES=(8 << 8), FONT_HAVE_GREEK=(16 << 8), 01941 FONT_HAVE_CYRILLIC=(32 << 8) }; 01942 01943 static const int HersheyPlain[] = { 01944 (5 + 4*16) + FONT_HAVE_GREEK, 01945 199, 214, 217, 233, 219, 197, 234, 216, 221, 222, 228, 225, 211, 224, 210, 220, 01946 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 212, 213, 191, 226, 192, 01947 215, 190, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 01948 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 193, 84, 01949 194, 85, 86, 87, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 01950 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 01951 195, 223, 196, 88 }; 01952 01953 static const int HersheyPlainItalic[] = { 01954 (5 + 4*16) + FONT_ITALIC_ALPHA + FONT_HAVE_GREEK, 01955 199, 214, 217, 233, 219, 197, 234, 216, 221, 222, 228, 225, 211, 224, 210, 220, 01956 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 212, 213, 191, 226, 192, 01957 215, 190, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 01958 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 193, 84, 01959 194, 85, 86, 87, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 01960 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 01961 195, 223, 196, 88 }; 01962 01963 static const int HersheyComplexSmall[] = { 01964 (6 + 7*16) + FONT_HAVE_GREEK, 01965 1199, 1214, 1217, 1275, 1274, 1271, 1272, 1216, 1221, 1222, 1219, 1232, 1211, 1231, 1210, 1220, 01966 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1212, 2213, 1241, 1238, 1242, 01967 1215, 1273, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 01968 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1223, 1084, 01969 1224, 1247, 586, 1249, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 01970 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 01971 1225, 1229, 1226, 1246 }; 01972 01973 static const int HersheyComplexSmallItalic[] = { 01974 (6 + 7*16) + FONT_ITALIC_ALPHA + FONT_HAVE_GREEK, 01975 1199, 1214, 1217, 1275, 1274, 1271, 1272, 1216, 1221, 1222, 1219, 1232, 1211, 1231, 1210, 1220, 01976 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1212, 1213, 1241, 1238, 1242, 01977 1215, 1273, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 01978 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1223, 1084, 01979 1224, 1247, 586, 1249, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161, 01980 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 01981 1225, 1229, 1226, 1246 }; 01982 01983 static const int HersheySimplex[] = { 01984 (9 + 12*16) + FONT_HAVE_GREEK, 01985 2199, 714, 717, 733, 719, 697, 734, 716, 721, 722, 728, 725, 711, 724, 710, 720, 01986 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 712, 713, 691, 726, 692, 01987 715, 690, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 01988 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 693, 584, 01989 694, 2247, 586, 2249, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 01990 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 01991 695, 723, 696, 2246 }; 01992 01993 static const int HersheyDuplex[] = { 01994 (9 + 12*16) + FONT_HAVE_GREEK, 01995 2199, 2714, 2728, 2732, 2719, 2733, 2718, 2727, 2721, 2722, 2723, 2725, 2711, 2724, 2710, 2720, 01996 2700, 2701, 2702, 2703, 2704, 2705, 2706, 2707, 2708, 2709, 2712, 2713, 2730, 2726, 2731, 01997 2715, 2734, 2501, 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2509, 2510, 2511, 2512, 2513, 01998 2514, 2515, 2516, 2517, 2518, 2519, 2520, 2521, 2522, 2523, 2524, 2525, 2526, 2223, 2084, 01999 2224, 2247, 587, 2249, 2601, 2602, 2603, 2604, 2605, 2606, 2607, 2608, 2609, 2610, 2611, 02000 2612, 2613, 2614, 2615, 2616, 2617, 2618, 2619, 2620, 2621, 2622, 2623, 2624, 2625, 2626, 02001 2225, 2229, 2226, 2246 }; 02002 02003 static const int HersheyComplex[] = { 02004 (9 + 12*16) + FONT_HAVE_GREEK + FONT_HAVE_CYRILLIC, 02005 2199, 2214, 2217, 2275, 2274, 2271, 2272, 2216, 2221, 2222, 2219, 2232, 2211, 2231, 2210, 2220, 02006 2200, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2212, 2213, 2241, 2238, 2242, 02007 2215, 2273, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 02008 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2223, 2084, 02009 2224, 2247, 587, 2249, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111, 02010 2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 2122, 2123, 2124, 2125, 2126, 02011 2225, 2229, 2226, 2246, 2801, 2802, 2803, 2804, 2805, 2806, 2807, 2808, 2809, 2810, 2811, 02012 2812, 2813, 2814, 2815, 2816, 2817, 2818, 2819, 2820, 2821, 2822, 2823, 2824, 2825, 2826, 02013 2827, 2828, 2829, 2830, 2831, 2832, 2901, 2902, 2903, 2904, 2905, 2906, 2907, 2908, 2909, 02014 2910, 2911, 2912, 2913, 2914, 2915, 2916, 2917, 2918, 2919, 2920, 2921, 2922, 2923, 2924, 02015 2925, 2926, 2927, 2928, 2929, 2930, 2931, 2932}; 02016 02017 static const int HersheyComplexItalic[] = { 02018 (9 + 12*16) + FONT_ITALIC_ALPHA + FONT_ITALIC_DIGIT + FONT_ITALIC_PUNCT + 02019 FONT_HAVE_GREEK + FONT_HAVE_CYRILLIC, 02020 2199, 2764, 2778, 2782, 2769, 2783, 2768, 2777, 2771, 2772, 2219, 2232, 2211, 2231, 2210, 2220, 02021 2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2212, 2213, 2241, 2238, 2242, 02022 2765, 2273, 2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, 02023 2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2223, 2084, 02024 2224, 2247, 587, 2249, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161, 02025 2162, 2163, 2164, 2165, 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2176, 02026 2225, 2229, 2226, 2246 }; 02027 02028 static const int HersheyTriplex[] = { 02029 (9 + 12*16) + FONT_HAVE_GREEK, 02030 2199, 3214, 3228, 3232, 3219, 3233, 3218, 3227, 3221, 3222, 3223, 3225, 3211, 3224, 3210, 3220, 02031 3200, 3201, 3202, 3203, 3204, 3205, 3206, 3207, 3208, 3209, 3212, 3213, 3230, 3226, 3231, 02032 3215, 3234, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011, 3012, 3013, 02033 2014, 3015, 3016, 3017, 3018, 3019, 3020, 3021, 3022, 3023, 3024, 3025, 3026, 2223, 2084, 02034 2224, 2247, 587, 2249, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, 3111, 02035 3112, 3113, 3114, 3115, 3116, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124, 3125, 3126, 02036 2225, 2229, 2226, 2246 }; 02037 02038 static const int HersheyTriplexItalic[] = { 02039 (9 + 12*16) + FONT_ITALIC_ALPHA + FONT_ITALIC_DIGIT + 02040 FONT_ITALIC_PUNCT + FONT_HAVE_GREEK, 02041 2199, 3264, 3278, 3282, 3269, 3233, 3268, 3277, 3271, 3272, 3223, 3225, 3261, 3224, 3260, 3270, 02042 3250, 3251, 3252, 3253, 3254, 3255, 3256, 3257, 3258, 3259, 3262, 3263, 3230, 3226, 3231, 02043 3265, 3234, 3051, 3052, 3053, 3054, 3055, 3056, 3057, 3058, 3059, 3060, 3061, 3062, 3063, 02044 2064, 3065, 3066, 3067, 3068, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3076, 2223, 2084, 02045 2224, 2247, 587, 2249, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3159, 3160, 3161, 02046 3162, 3163, 3164, 3165, 3166, 3167, 3168, 3169, 3170, 3171, 3172, 3173, 3174, 3175, 3176, 02047 2225, 2229, 2226, 2246 }; 02048 02049 static const int HersheyScriptSimplex[] = { 02050 (9 + 12*16) + FONT_ITALIC_ALPHA + FONT_HAVE_GREEK, 02051 2199, 714, 717, 733, 719, 697, 734, 716, 721, 722, 728, 725, 711, 724, 710, 720, 02052 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 712, 713, 691, 726, 692, 02053 715, 690, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 02054 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 693, 584, 02055 694, 2247, 586, 2249, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 02056 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 02057 695, 723, 696, 2246 }; 02058 02059 static const int HersheyScriptComplex[] = { 02060 (9 + 12*16) + FONT_ITALIC_ALPHA + FONT_ITALIC_DIGIT + FONT_ITALIC_PUNCT + FONT_HAVE_GREEK, 02061 2199, 2764, 2778, 2782, 2769, 2783, 2768, 2777, 2771, 2772, 2219, 2232, 2211, 2231, 2210, 2220, 02062 2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2212, 2213, 2241, 2238, 2242, 02063 2215, 2273, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563, 02064 2564, 2565, 2566, 2567, 2568, 2569, 2570, 2571, 2572, 2573, 2574, 2575, 2576, 2223, 2084, 02065 2224, 2247, 586, 2249, 2651, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661, 02066 2662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2676, 02067 2225, 2229, 2226, 2246 }; 02068 02069 02070 static const int* getFontData(int fontFace) 02071 { 02072 bool isItalic = (fontFace & FONT_ITALIC) != 0; 02073 const int* ascii = 0; 02074 02075 switch( fontFace & 15 ) 02076 { 02077 case FONT_HERSHEY_SIMPLEX: 02078 ascii = HersheySimplex; 02079 break; 02080 case FONT_HERSHEY_PLAIN: 02081 ascii = !isItalic ? HersheyPlain : HersheyPlainItalic; 02082 break; 02083 case FONT_HERSHEY_DUPLEX: 02084 ascii = HersheyDuplex; 02085 break; 02086 case FONT_HERSHEY_COMPLEX: 02087 ascii = !isItalic ? HersheyComplex : HersheyComplexItalic; 02088 break; 02089 case FONT_HERSHEY_TRIPLEX: 02090 ascii = !isItalic ? HersheyTriplex : HersheyTriplexItalic; 02091 break; 02092 case FONT_HERSHEY_COMPLEX_SMALL: 02093 ascii = !isItalic ? HersheyComplexSmall : HersheyComplexSmallItalic; 02094 break; 02095 case FONT_HERSHEY_SCRIPT_SIMPLEX: 02096 ascii = HersheyScriptSimplex; 02097 break; 02098 case FONT_HERSHEY_SCRIPT_COMPLEX: 02099 ascii = HersheyScriptComplex; 02100 break; 02101 default: 02102 CV_Error( CV_StsOutOfRange, "Unknown font type" ); 02103 } 02104 return ascii; 02105 } 02106 02107 inline void readCheck(int &c, int &i, const String &text, int fontFace) 02108 { 02109 02110 int leftBoundary = ' ', rightBoundary = 127; 02111 02112 if(c >= 0x80 && fontFace == FONT_HERSHEY_COMPLEX) 02113 { 02114 if(c == 0xD0 && (uchar)text[i + 1] >= 0x90 && (uchar)text[i + 1] <= 0xBF) 02115 { 02116 c = (uchar)text[++i] - 17; 02117 leftBoundary = 127; 02118 rightBoundary = 175; 02119 } 02120 else if(c == 0xD1 && (uchar)text[i + 1] >= 0x80 && (uchar)text[i + 1] <= 0x8F) 02121 { 02122 c = (uchar)text[++i] + 47; 02123 leftBoundary = 175; 02124 rightBoundary = 191; 02125 } 02126 else 02127 { 02128 if(c >= 0xC0 && text[i+1] != 0) //2 bytes utf 02129 i++; 02130 02131 if(c >= 0xE0 && text[i+1] != 0) //3 bytes utf 02132 i++; 02133 02134 if(c >= 0xF0 && text[i+1] != 0) //4 bytes utf 02135 i++; 02136 02137 if(c >= 0xF8 && text[i+1] != 0) //5 bytes utf 02138 i++; 02139 02140 if(c >= 0xFC && text[i+1] != 0) //6 bytes utf 02141 i++; 02142 02143 c = '?'; 02144 } 02145 } 02146 02147 if(c >= rightBoundary || c < leftBoundary) 02148 c = '?'; 02149 } 02150 02151 extern const char* g_HersheyGlyphs[]; 02152 02153 void putText( InputOutputArray _img, const String& text, Point org, 02154 int fontFace, double fontScale, Scalar color, 02155 int thickness, int line_type, bool bottomLeftOrigin ) 02156 02157 { 02158 if ( text.empty() ) 02159 { 02160 return; 02161 } 02162 Mat img = _img.getMat(); 02163 const int* ascii = getFontData(fontFace); 02164 02165 double buf[4]; 02166 scalarToRawData(color, buf, img.type(), 0); 02167 02168 int base_line = -(ascii[0] & 15); 02169 int hscale = cvRound(fontScale*XY_ONE), vscale = hscale; 02170 02171 if( line_type == CV_AA && img.depth() != CV_8U ) 02172 line_type = 8; 02173 02174 if( bottomLeftOrigin ) 02175 vscale = -vscale; 02176 02177 int view_x = org.x << XY_SHIFT; 02178 int view_y = (org.y << XY_SHIFT) + base_line*vscale; 02179 std::vector<Point> pts; 02180 pts.reserve(1 << 10); 02181 const char **faces = cv::g_HersheyGlyphs; 02182 02183 for( int i = 0; i < (int)text.size(); i++ ) 02184 { 02185 int c = (uchar)text[i]; 02186 Point p; 02187 02188 readCheck(c, i, text, fontFace); 02189 02190 const char* ptr = faces[ascii[(c-' ')+1]]; 02191 p.x = (uchar)ptr[0] - 'R'; 02192 p.y = (uchar)ptr[1] - 'R'; 02193 int dx = p.y*hscale; 02194 view_x -= p.x*hscale; 02195 pts.resize(0); 02196 02197 for( ptr += 2;; ) 02198 { 02199 if( *ptr == ' ' || !*ptr ) 02200 { 02201 if( pts.size() > 1 ) 02202 PolyLine( img, &pts[0], (int)pts.size(), false, buf, thickness, line_type, XY_SHIFT ); 02203 if( !*ptr++ ) 02204 break; 02205 pts.resize(0); 02206 } 02207 else 02208 { 02209 p.x = (uchar)ptr[0] - 'R'; 02210 p.y = (uchar)ptr[1] - 'R'; 02211 ptr += 2; 02212 pts.push_back(Point(p.x*hscale + view_x, p.y*vscale + view_y)); 02213 } 02214 } 02215 view_x += dx; 02216 } 02217 } 02218 02219 Size getTextSize( const String& text, int fontFace, double fontScale, int thickness, int* _base_line) 02220 { 02221 Size size; 02222 double view_x = 0; 02223 const char **faces = cv::g_HersheyGlyphs; 02224 const int* ascii = getFontData(fontFace); 02225 02226 int base_line = (ascii[0] & 15); 02227 int cap_line = (ascii[0] >> 4) & 15; 02228 size.height = cvRound((cap_line + base_line)*fontScale + (thickness+1)/2); 02229 02230 for( int i = 0; i < (int)text.size(); i++ ) 02231 { 02232 int c = (uchar)text[i]; 02233 Point p; 02234 02235 readCheck(c, i, text, fontFace); 02236 02237 const char* ptr = faces[ascii[(c-' ')+1]]; 02238 p.x = (uchar)ptr[0] - 'R'; 02239 p.y = (uchar)ptr[1] - 'R'; 02240 view_x += (p.y - p.x)*fontScale; 02241 } 02242 02243 size.width = cvRound(view_x + thickness); 02244 if( _base_line ) 02245 *_base_line = cvRound(base_line*fontScale + thickness*0.5); 02246 return size; 02247 } 02248 02249 } 02250 02251 02252 void cv::fillConvexPoly (InputOutputArray _img, InputArray _points, 02253 const Scalar & color, int lineType, int shift) 02254 { 02255 Mat img = _img.getMat(), points = _points.getMat(); 02256 CV_Assert(points.checkVector(2, CV_32S) >= 0); 02257 fillConvexPoly (img, points.ptr<Point>(), points.rows*points.cols*points.channels()/2, color, lineType, shift); 02258 } 02259 02260 02261 void cv::fillPoly (InputOutputArray _img, InputArrayOfArrays pts, 02262 const Scalar & color, int lineType, int shift, Point offset) 02263 { 02264 Mat img = _img.getMat(); 02265 int i, ncontours = (int)pts.total(); 02266 if( ncontours == 0 ) 02267 return; 02268 AutoBuffer<Point*> _ptsptr(ncontours); 02269 AutoBuffer<int> _npts(ncontours); 02270 Point** ptsptr = _ptsptr; 02271 int* npts = _npts; 02272 02273 for( i = 0; i < ncontours; i++ ) 02274 { 02275 Mat p = pts.getMat(i); 02276 CV_Assert(p.checkVector(2, CV_32S) >= 0); 02277 ptsptr[i] = p.ptr<Point>(); 02278 npts[i] = p.rows*p.cols*p.channels()/2; 02279 } 02280 fillPoly (img, (const Point**)ptsptr, npts, (int)ncontours, color, lineType, shift, offset); 02281 } 02282 02283 02284 void cv::polylines (InputOutputArray _img, InputArrayOfArrays pts, 02285 bool isClosed, const Scalar & color, 02286 int thickness, int lineType, int shift ) 02287 { 02288 Mat img = _img.getMat(); 02289 bool manyContours = pts.kind() == _InputArray::STD_VECTOR_VECTOR || 02290 pts.kind() == _InputArray::STD_VECTOR_MAT; 02291 int i, ncontours = manyContours ? (int)pts.total() : 1; 02292 if( ncontours == 0 ) 02293 return; 02294 AutoBuffer<Point*> _ptsptr(ncontours); 02295 AutoBuffer<int> _npts(ncontours); 02296 Point** ptsptr = _ptsptr; 02297 int* npts = _npts; 02298 02299 for( i = 0; i < ncontours; i++ ) 02300 { 02301 Mat p = pts.getMat(manyContours ? i : -1); 02302 if( p.total() == 0 ) 02303 { 02304 ptsptr[i] = NULL; 02305 npts[i] = 0; 02306 continue; 02307 } 02308 CV_Assert(p.checkVector(2, CV_32S) >= 0); 02309 ptsptr[i] = p.ptr<Point>(); 02310 npts[i] = p.rows*p.cols*p.channels()/2; 02311 } 02312 polylines (img, (const Point**)ptsptr, npts, (int)ncontours, isClosed, color, thickness, lineType, shift); 02313 } 02314 02315 namespace 02316 { 02317 using namespace cv; 02318 02319 static void addChildContour(InputArrayOfArrays contours, 02320 size_t ncontours, 02321 const Vec4i * hierarchy, 02322 int i, std::vector<CvSeq>& seq, 02323 std::vector<CvSeqBlock>& block) 02324 { 02325 for( ; i >= 0; i = hierarchy[i][0] ) 02326 { 02327 Mat ci = contours.getMat(i); 02328 cvMakeSeqHeaderForArray(CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point ), 02329 !ci.empty() ? (void*)ci.ptr() : 0, (int)ci.total(), 02330 &seq[i], &block[i] ); 02331 02332 int h_next = hierarchy[i][0], h_prev = hierarchy[i][1], 02333 v_next = hierarchy[i][2], v_prev = hierarchy[i][3]; 02334 seq[i].h_next = (0 <= h_next && h_next < (int)ncontours) ? &seq[h_next] : 0; 02335 seq[i].h_prev = (0 <= h_prev && h_prev < (int)ncontours) ? &seq[h_prev] : 0; 02336 seq[i].v_next = (0 <= v_next && v_next < (int)ncontours) ? &seq[v_next] : 0; 02337 seq[i].v_prev = (0 <= v_prev && v_prev < (int)ncontours) ? &seq[v_prev] : 0; 02338 02339 if( v_next >= 0 ) 02340 addChildContour(contours, ncontours, hierarchy, v_next, seq, block); 02341 } 02342 } 02343 } 02344 02345 void cv::drawContours( InputOutputArray _image, InputArrayOfArrays _contours, 02346 int contourIdx, const Scalar & color, int thickness, 02347 int lineType, InputArray _hierarchy, 02348 int maxLevel, Point offset ) 02349 { 02350 Mat image = _image.getMat(), hierarchy = _hierarchy.getMat(); 02351 CvMat _cimage = image; 02352 02353 size_t ncontours = _contours.total(); 02354 size_t i = 0, first = 0, last = ncontours; 02355 std::vector<CvSeq> seq; 02356 std::vector<CvSeqBlock> block; 02357 02358 if( !last ) 02359 return; 02360 02361 seq.resize(last); 02362 block.resize(last); 02363 02364 for( i = first; i < last; i++ ) 02365 seq[i].first = 0; 02366 02367 if( contourIdx >= 0 ) 02368 { 02369 CV_Assert( 0 <= contourIdx && contourIdx < (int)last ); 02370 first = contourIdx; 02371 last = contourIdx + 1; 02372 } 02373 02374 for( i = first; i < last; i++ ) 02375 { 02376 Mat ci = _contours.getMat((int)i); 02377 if( ci.empty() ) 02378 continue; 02379 int npoints = ci.checkVector(2, CV_32S); 02380 CV_Assert( npoints > 0 ); 02381 cvMakeSeqHeaderForArray( CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point), 02382 ci.ptr(), npoints, &seq[i], &block[i] ); 02383 } 02384 02385 if( hierarchy.empty() || maxLevel == 0 ) 02386 for( i = first; i < last; i++ ) 02387 { 02388 seq[i].h_next = i < last-1 ? &seq[i+1] : 0; 02389 seq[i].h_prev = i > first ? &seq[i-1] : 0; 02390 } 02391 else 02392 { 02393 size_t count = last - first; 02394 CV_Assert(hierarchy.total() == ncontours && hierarchy.type() == CV_32SC4 ); 02395 const Vec4i * h = hierarchy.ptr<Vec4i >(); 02396 02397 if( count == ncontours ) 02398 { 02399 for( i = first; i < last; i++ ) 02400 { 02401 int h_next = h[i][0], h_prev = h[i][1], 02402 v_next = h[i][2], v_prev = h[i][3]; 02403 seq[i].h_next = (size_t)h_next < count ? &seq[h_next] : 0; 02404 seq[i].h_prev = (size_t)h_prev < count ? &seq[h_prev] : 0; 02405 seq[i].v_next = (size_t)v_next < count ? &seq[v_next] : 0; 02406 seq[i].v_prev = (size_t)v_prev < count ? &seq[v_prev] : 0; 02407 } 02408 } 02409 else 02410 { 02411 int child = h[first][2]; 02412 if( child >= 0 ) 02413 { 02414 addChildContour(_contours, ncontours, h, child, seq, block); 02415 seq[first].v_next = &seq[child]; 02416 } 02417 } 02418 } 02419 02420 cvDrawContours( &_cimage, &seq[first], color, color, contourIdx >= 0 ? 02421 -maxLevel : maxLevel, thickness, lineType, offset ); 02422 } 02423 02424 02425 02426 static const int CodeDeltas[8][2] = 02427 { {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} }; 02428 02429 #define CV_ADJUST_EDGE_COUNT( count, seq ) \ 02430 ((count) -= ((count) == (seq)->total && !CV_IS_SEQ_CLOSED(seq))) 02431 02432 CV_IMPL void 02433 cvDrawContours( void* _img, CvSeq* contour, 02434 CvScalar _externalColor, CvScalar _holeColor, 02435 int maxLevel, int thickness, 02436 int line_type, CvPoint _offset ) 02437 { 02438 CvSeq *contour0 = contour, *h_next = 0; 02439 CvTreeNodeIterator iterator; 02440 std::vector<cv::PolyEdge> edges; 02441 std::vector<cv::Point> pts; 02442 cv::Scalar externalColor = _externalColor, holeColor = _holeColor; 02443 cv::Mat img = cv::cvarrToMat(_img); 02444 cv::Point offset = _offset; 02445 double ext_buf[4], hole_buf[4]; 02446 02447 if( line_type == CV_AA && img.depth() != CV_8U ) 02448 line_type = 8; 02449 02450 if( !contour ) 02451 return; 02452 02453 CV_Assert( thickness <= MAX_THICKNESS ); 02454 02455 scalarToRawData( externalColor, ext_buf, img.type(), 0 ); 02456 scalarToRawData( holeColor, hole_buf, img.type(), 0 ); 02457 02458 maxLevel = MAX(maxLevel, INT_MIN+2); 02459 maxLevel = MIN(maxLevel, INT_MAX-1); 02460 02461 if( maxLevel < 0 ) 02462 { 02463 h_next = contour->h_next; 02464 contour->h_next = 0; 02465 maxLevel = -maxLevel+1; 02466 } 02467 02468 cvInitTreeNodeIterator( &iterator, contour, maxLevel ); 02469 while( (contour = (CvSeq*)cvNextTreeNode( &iterator )) != 0 ) 02470 { 02471 CvSeqReader reader; 02472 int i, count = contour->total; 02473 int elem_type = CV_MAT_TYPE(contour->flags); 02474 void* clr = (contour->flags & CV_SEQ_FLAG_HOLE) == 0 ? ext_buf : hole_buf; 02475 02476 cvStartReadSeq( contour, &reader, 0 ); 02477 if( thickness < 0 ) 02478 pts.resize(0); 02479 02480 if( CV_IS_SEQ_CHAIN_CONTOUR( contour )) 02481 { 02482 cv::Point pt = ((CvChain*)contour)->origin; 02483 cv::Point prev_pt = pt; 02484 char prev_code = reader.ptr ? reader.ptr[0] : '\0'; 02485 02486 prev_pt += offset; 02487 02488 for( i = 0; i < count; i++ ) 02489 { 02490 char code; 02491 CV_READ_SEQ_ELEM( code, reader ); 02492 02493 assert( (code & ~7) == 0 ); 02494 02495 if( code != prev_code ) 02496 { 02497 prev_code = code; 02498 if( thickness >= 0 ) 02499 cv::ThickLine( img, prev_pt, pt, clr, thickness, line_type, 2, 0 ); 02500 else 02501 pts.push_back(pt); 02502 prev_pt = pt; 02503 } 02504 02505 pt.x += CodeDeltas[(int)code][0]; 02506 pt.y += CodeDeltas[(int)code][1]; 02507 } 02508 02509 if( thickness >= 0 ) 02510 cv::ThickLine( img, prev_pt, 02511 cv::Point (((CvChain*)contour)->origin) + offset, 02512 clr, thickness, line_type, 2, 0 ); 02513 else 02514 cv::CollectPolyEdges(img, &pts[0], (int)pts.size(), 02515 edges, ext_buf, line_type, 0, offset); 02516 } 02517 else if( CV_IS_SEQ_POLYLINE( contour )) 02518 { 02519 CV_Assert( elem_type == CV_32SC2 ); 02520 cv::Point pt1, pt2; 02521 int shift = 0; 02522 02523 count -= !CV_IS_SEQ_CLOSED(contour); 02524 CV_READ_SEQ_ELEM( pt1, reader ); 02525 pt1 += offset; 02526 if( thickness < 0 ) 02527 pts.push_back(pt1); 02528 02529 for( i = 0; i < count; i++ ) 02530 { 02531 CV_READ_SEQ_ELEM( pt2, reader ); 02532 pt2 += offset; 02533 if( thickness >= 0 ) 02534 cv::ThickLine( img, pt1, pt2, clr, thickness, line_type, 2, shift ); 02535 else 02536 pts.push_back(pt2); 02537 pt1 = pt2; 02538 } 02539 if( thickness < 0 ) 02540 cv::CollectPolyEdges( img, &pts[0], (int)pts.size(), 02541 edges, ext_buf, line_type, 0, cv::Point () ); 02542 } 02543 } 02544 02545 if( thickness < 0 ) 02546 cv::FillEdgeCollection( img, edges, ext_buf ); 02547 02548 if( h_next && contour0 ) 02549 contour0->h_next = h_next; 02550 } 02551 02552 CV_IMPL int 02553 cvClipLine( CvSize size, CvPoint* pt1, CvPoint* pt2 ) 02554 { 02555 CV_Assert( pt1 && pt2 ); 02556 return cv::clipLine( size, *(cv::Point *)pt1, *(cv::Point *)pt2 ); 02557 } 02558 02559 02560 CV_IMPL int 02561 cvEllipse2Poly( CvPoint center, CvSize axes, int angle, 02562 int arc_start, int arc_end, CvPoint* _pts, int delta ) 02563 { 02564 std::vector<cv::Point> pts; 02565 cv::ellipse2Poly( center, axes, angle, arc_start, arc_end, delta, pts ); 02566 memcpy( _pts, &pts[0], pts.size()*sizeof(_pts[0]) ); 02567 return (int)pts.size(); 02568 } 02569 02570 CV_IMPL CvScalar 02571 cvColorToScalar( double packed_color, int type ) 02572 { 02573 CvScalar scalar; 02574 02575 if( CV_MAT_DEPTH( type ) == CV_8U ) 02576 { 02577 int icolor = cvRound( packed_color ); 02578 if( CV_MAT_CN( type ) > 1 ) 02579 { 02580 scalar.val[0] = icolor & 255; 02581 scalar.val[1] = (icolor >> 8) & 255; 02582 scalar.val[2] = (icolor >> 16) & 255; 02583 scalar.val[3] = (icolor >> 24) & 255; 02584 } 02585 else 02586 { 02587 scalar.val[0] = cv::saturate_cast<uchar>( icolor ); 02588 scalar.val[1] = scalar.val[2] = scalar.val[3] = 0; 02589 } 02590 } 02591 else if( CV_MAT_DEPTH( type ) == CV_8S ) 02592 { 02593 int icolor = cvRound( packed_color ); 02594 if( CV_MAT_CN( type ) > 1 ) 02595 { 02596 scalar.val[0] = (char)icolor; 02597 scalar.val[1] = (char)(icolor >> 8); 02598 scalar.val[2] = (char)(icolor >> 16); 02599 scalar.val[3] = (char)(icolor >> 24); 02600 } 02601 else 02602 { 02603 scalar.val[0] = cv::saturate_cast<schar>( icolor ); 02604 scalar.val[1] = scalar.val[2] = scalar.val[3] = 0; 02605 } 02606 } 02607 else 02608 { 02609 int cn = CV_MAT_CN( type ); 02610 switch( cn ) 02611 { 02612 case 1: 02613 scalar.val[0] = packed_color; 02614 scalar.val[1] = scalar.val[2] = scalar.val[3] = 0; 02615 break; 02616 case 2: 02617 scalar.val[0] = scalar.val[1] = packed_color; 02618 scalar.val[2] = scalar.val[3] = 0; 02619 break; 02620 case 3: 02621 scalar.val[0] = scalar.val[1] = scalar.val[2] = packed_color; 02622 scalar.val[3] = 0; 02623 break; 02624 default: 02625 scalar.val[0] = scalar.val[1] = 02626 scalar.val[2] = scalar.val[3] = packed_color; 02627 break; 02628 } 02629 } 02630 02631 return scalar; 02632 } 02633 02634 CV_IMPL int 02635 cvInitLineIterator( const CvArr* img, CvPoint pt1, CvPoint pt2, 02636 CvLineIterator* iterator, int connectivity, 02637 int left_to_right ) 02638 { 02639 CV_Assert( iterator != 0 ); 02640 cv::LineIterator li(cv::cvarrToMat(img), pt1, pt2, connectivity, left_to_right!=0); 02641 02642 iterator->err = li.err; 02643 iterator->minus_delta = li.minusDelta; 02644 iterator->plus_delta = li.plusDelta; 02645 iterator->minus_step = li.minusStep; 02646 iterator->plus_step = li.plusStep; 02647 iterator->ptr = li.ptr; 02648 02649 return li.count; 02650 } 02651 02652 CV_IMPL void 02653 cvLine( CvArr* _img, CvPoint pt1, CvPoint pt2, CvScalar color, 02654 int thickness, int line_type, int shift ) 02655 { 02656 cv::Mat img = cv::cvarrToMat(_img); 02657 cv::line( img, pt1, pt2, color, thickness, line_type, shift ); 02658 } 02659 02660 CV_IMPL void 02661 cvRectangle( CvArr* _img, CvPoint pt1, CvPoint pt2, 02662 CvScalar color, int thickness, 02663 int line_type, int shift ) 02664 { 02665 cv::Mat img = cv::cvarrToMat(_img); 02666 cv::rectangle( img, pt1, pt2, color, thickness, line_type, shift ); 02667 } 02668 02669 CV_IMPL void 02670 cvRectangleR( CvArr* _img, CvRect rec, 02671 CvScalar color, int thickness, 02672 int line_type, int shift ) 02673 { 02674 cv::Mat img = cv::cvarrToMat(_img); 02675 cv::rectangle( img, rec, color, thickness, line_type, shift ); 02676 } 02677 02678 CV_IMPL void 02679 cvCircle( CvArr* _img, CvPoint center, int radius, 02680 CvScalar color, int thickness, int line_type, int shift ) 02681 { 02682 cv::Mat img = cv::cvarrToMat(_img); 02683 cv::circle( img, center, radius, color, thickness, line_type, shift ); 02684 } 02685 02686 CV_IMPL void 02687 cvEllipse( CvArr* _img, CvPoint center, CvSize axes, 02688 double angle, double start_angle, double end_angle, 02689 CvScalar color, int thickness, int line_type, int shift ) 02690 { 02691 cv::Mat img = cv::cvarrToMat(_img); 02692 cv::ellipse( img, center, axes, angle, start_angle, end_angle, 02693 color, thickness, line_type, shift ); 02694 } 02695 02696 CV_IMPL void 02697 cvFillConvexPoly( CvArr* _img, const CvPoint *pts, int npts, 02698 CvScalar color, int line_type, int shift ) 02699 { 02700 cv::Mat img = cv::cvarrToMat(_img); 02701 cv::fillConvexPoly ( img, (const cv::Point *)pts, npts, 02702 color, line_type, shift ); 02703 } 02704 02705 CV_IMPL void 02706 cvFillPoly( CvArr* _img, CvPoint **pts, const int *npts, int ncontours, 02707 CvScalar color, int line_type, int shift ) 02708 { 02709 cv::Mat img = cv::cvarrToMat(_img); 02710 02711 cv::fillPoly ( img, (const cv::Point **)pts, npts, ncontours, color, line_type, shift ); 02712 } 02713 02714 CV_IMPL void 02715 cvPolyLine( CvArr* _img, CvPoint **pts, const int *npts, 02716 int ncontours, int closed, CvScalar color, 02717 int thickness, int line_type, int shift ) 02718 { 02719 cv::Mat img = cv::cvarrToMat(_img); 02720 02721 cv::polylines ( img, (const cv::Point **)pts, npts, ncontours, 02722 closed != 0, color, thickness, line_type, shift ); 02723 } 02724 02725 CV_IMPL void 02726 cvPutText( CvArr* _img, const char *text, CvPoint org, const CvFont *_font, CvScalar color ) 02727 { 02728 cv::Mat img = cv::cvarrToMat(_img); 02729 CV_Assert( text != 0 && _font != 0); 02730 cv::putText( img, text, org, _font->font_face, (_font->hscale+_font->vscale)*0.5, 02731 color, _font->thickness, _font->line_type, 02732 CV_IS_IMAGE(_img) && ((IplImage*)_img)->origin != 0 ); 02733 } 02734 02735 02736 CV_IMPL void 02737 cvInitFont( CvFont *font, int font_face, double hscale, double vscale, 02738 double shear, int thickness, int line_type ) 02739 { 02740 CV_Assert( font != 0 && hscale > 0 && vscale > 0 && thickness >= 0 ); 02741 02742 font->ascii = cv::getFontData(font_face); 02743 font->font_face = font_face; 02744 font->hscale = (float)hscale; 02745 font->vscale = (float)vscale; 02746 font->thickness = thickness; 02747 font->shear = (float)shear; 02748 font->greek = font->cyrillic = 0; 02749 font->line_type = line_type; 02750 } 02751 02752 CV_IMPL void 02753 cvGetTextSize( const char *text, const CvFont *_font, CvSize *_size, int *_base_line ) 02754 { 02755 CV_Assert(text != 0 && _font != 0); 02756 cv::Size size = cv::getTextSize( text, _font->font_face, (_font->hscale + _font->vscale)*0.5, 02757 _font->thickness, _base_line ); 02758 if( _size ) 02759 *_size = size; 02760 } 02761 02762 /* End of file. */ 02763
Generated on Tue Jul 12 2022 15:17:22 by 1.7.2