00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <deque>
00039 #include "Image/DrawOps.H"
00040
00041 #include "Image/ColorOps.H"
00042 #include "Image/ColorMap.H"
00043 #include "Image/CutPaste.H"
00044 #include "Image/FilterOps.H"
00045 #include "Image/Image.H"
00046 #include "Image/MathOps.H"
00047 #include "Image/Pixels.H"
00048 #include "Image/Point2D.H"
00049 #include "Image/Range.H"
00050 #include "Image/ShapeOps.H"
00051 #include "Image/Transforms.H"
00052 #include "Image/MatrixOps.H"
00053 #include "Util/Assert.H"
00054 #include "Util/MathFunctions.H"
00055 #include "Util/sformat.H"
00056 #include "rutz/trace.h"
00057 #include <cmath>
00058
00059 void drawTraj(Image< PixRGB<byte> >& img,
00060 const Point2D<int>* foa, const Point2D<int>* foas_end)
00061 {
00062 GVX_TRACE(__PRETTY_FUNCTION__);
00063 const Point2D<int>* foa_prev = foa;
00064 for (; foa != foas_end; ++foa)
00065 {
00066 drawCircle(img, *foa, 10, PixRGB<byte>(255,255,0), 1);
00067 if (foa != foa_prev)
00068 drawArrow(img, *foa_prev, *foa, PixRGB<byte>(255,0,0), 1);
00069 foa_prev = foa;
00070 }
00071 }
00072
00073
00074 Image< PixRGB<byte> > colGreyCombo(const Image< PixRGB<byte> >& colimg,
00075 const Image<float>& bwimg,
00076 const bool xcombo, const bool interp)
00077 {
00078 GVX_TRACE(__PRETTY_FUNCTION__);
00079
00080 ASSERT(colimg.initialized());
00081
00082
00083 const Image<byte> tmp =
00084 bwimg.initialized()
00085 ? Image<byte>(rescaleOpt(bwimg, colimg.getDims(), interp))
00086 : Image<byte>(colimg.getDims(), ZEROS);
00087
00088 const Image< PixRGB<byte> > tmp2 = makeRGB(tmp, tmp, tmp);
00089
00090 if (xcombo) return concatX(colimg, tmp2);
00091 else return concatY(colimg, tmp2);
00092 }
00093
00094
00095 Image< PixRGB<byte> > colColCombo(const Image< PixRGB<byte> >& colimg1,
00096 const Image< PixRGB<byte> >& colimg2,
00097 const bool xcombo, const bool interp)
00098 {
00099 GVX_TRACE(__PRETTY_FUNCTION__);
00100
00101 ASSERT(colimg1.initialized());
00102 ASSERT(colimg2.initialized());
00103
00104 Image< PixRGB<byte> > tmp;
00105 if (xcombo)
00106 {
00107 if (colimg1.getHeight() != colimg2.getHeight())
00108 tmp = rescaleOpt(colimg2, colimg1.getWidth() / 2,
00109 colimg1.getHeight(), interp);
00110 else tmp = colimg2;
00111 return concatX(colimg1, tmp);
00112 }
00113 else
00114 {
00115 if (colimg1.getWidth() != colimg2.getWidth())
00116 tmp = rescaleOpt(colimg2, colimg1.getWidth(),
00117 colimg1.getHeight() / 2, interp);
00118 else tmp = colimg2;
00119 return concatY(colimg1, tmp);
00120 }
00121 }
00122
00123
00124 Image< PixRGB<byte> > highlightRegions(const Image< PixRGB<byte> >& img,
00125 const Image<byte>& mask,
00126 const int maxval)
00127 {
00128 GVX_TRACE(__PRETTY_FUNCTION__);
00129 Image<float> tmp = chamfer34(mask);
00130 tmp = binaryReverse(tmp, float(maxval));
00131 tmp.setVal(0, 0, 0.0);
00132 inplaceNormalize(tmp, 0.0f, 1.0f);
00133 return img * tmp;
00134 }
00135
00136
00137 Image< PixRGB<byte> > warp3Dmap(const Image< PixRGB<byte> >& img,
00138 const Image<float>& hmap,
00139 const float pitch, const float yaw,
00140 Dims& imdims)
00141 {
00142 GVX_TRACE(__PRETTY_FUNCTION__);
00143
00144 Image<float> ftmp = lowPass9(rescale(hmap,img.getWidth(),img.getHeight()));
00145 inplaceClamp(ftmp, 0.0f, 255.0f);
00146
00147
00148 return warp3D(img, ftmp, pitch, yaw, 255.0, imdims);
00149 }
00150
00151
00152 void inplaceSetValMask(Image<float>& dest,
00153 const Image<byte>& mask, const float val)
00154 {
00155 GVX_TRACE(__PRETTY_FUNCTION__);
00156 ASSERT(dest.isSameSize(mask));
00157
00158 Image<byte>::const_iterator mptr = mask.begin();
00159
00160 Image<float>::iterator
00161 dptr = dest.beginw(),
00162 endptr = dest.endw();
00163
00164 while (dptr != endptr)
00165 {
00166 if (*mptr) *dptr = val;
00167 ++mptr;
00168 ++dptr;
00169 }
00170 }
00171
00172
00173 template <class T>
00174 void drawDisk(Image<T>& dst, const Point2D<int>& center,
00175 const int radius, const T value)
00176 {
00177 GVX_TRACE(__PRETTY_FUNCTION__);
00178 ASSERT(dst.initialized());
00179 if (radius == 1)
00180 {
00181 if (dst.coordsOk(center)) dst.setVal(center.i + dst.getWidth() * center.j, value);
00182 return;
00183 }
00184
00185 for (int y = -radius; y <= radius; ++y)
00186 {
00187 int bound = int(sqrtf(float(squareOf(radius) - squareOf(y))));
00188 for (int x = -bound; x <= bound; ++x)
00189 if (dst.coordsOk(x + center.i, y + center.j))
00190 dst.setVal(x + center.i, y + center.j, value);
00191 }
00192 }
00193
00194
00195 template <class T>
00196 void drawLine(Image<T>& dst,
00197 const Point2D<int>& pos, float ori, float len, const T col,
00198 const int rad = 1)
00199 {
00200
00201 GVX_TRACE(__PRETTY_FUNCTION__);
00202 ASSERT(dst.initialized());
00203
00204 int x1 = int(cos(ori)*len/2);
00205 int y1 = int(sin(ori)*len/2);
00206
00207 Point2D<int> p1(pos.i-x1, pos.j+y1);
00208 Point2D<int> p2(pos.i+x1, pos.j-y1);
00209
00210 drawLine(dst, p1, p2, col, rad);
00211
00212 }
00213
00214
00215
00216 template <class T>
00217 void drawLine(Image<T>& dst, const Point2D<int>& p1, const Point2D<int>& p2,
00218 const T col, const int rad)
00219 {
00220 GVX_TRACE(__PRETTY_FUNCTION__);
00221 ASSERT(dst.initialized());
00222
00223 int dx = p2.i - p1.i, ax = abs(dx) << 1, sx = signOf(dx);
00224 int dy = p2.j - p1.j, ay = abs(dy) << 1, sy = signOf(dy);
00225 int x = p1.i, y = p1.j;
00226
00227 const int w = dst.getWidth();
00228 const int h = dst.getHeight();
00229
00230 T* const dptr = dst.getArrayPtr();
00231
00232 if (ax > ay)
00233 {
00234 int d = ay - (ax >> 1);
00235 for (;;)
00236 {
00237 if (rad == 1)
00238 {
00239
00240 if (x >= 0 && x < w && y >= 0 && y < h)
00241 dptr[x + w * y] = col;
00242 }
00243 else
00244 drawDisk(dst, Point2D<int>(x,y), rad, col);
00245 if (x == p2.i) return;
00246 if (d >= 0) { y += sy; d -= ax; }
00247 x += sx; d += ay;
00248 }
00249 }
00250 else
00251 {
00252 int d = ax - (ay >> 1);
00253 for (;;)
00254 {
00255 if (rad == 1)
00256 {
00257
00258 if (x >= 0 && x < w && y >= 0 && y < h)
00259 dptr[x + w * y] = col;
00260 }
00261 else
00262 drawDisk(dst, Point2D<int>(x,y), rad, col);
00263 if (y == p2.j) return;
00264 if (d >= 0) { x += sx; d -= ay; }
00265 y += sy; d += ax;
00266 }
00267 }
00268 }
00269
00270
00271 template <class T>
00272 void drawCorner(Image<T>& dst,
00273 const Point2D<int>& pos, float ori, float ang, float len, const T col,
00274 const int rad = 1)
00275 {
00276
00277 GVX_TRACE(__PRETTY_FUNCTION__);
00278 ASSERT(dst.initialized());
00279
00280 int x1 = int(cos(ori - ang/2)*len/2);
00281 int y1 = int(sin(ori - ang/2)*len/2);
00282
00283 int x2 = int(cos(ori + ang/2)*len/2);
00284 int y2 = int(sin(ori + ang/2)*len/2);
00285
00286 Point2D<int> p1(pos.i, pos.j);
00287 Point2D<int> p2(pos.i+x1, pos.j-y1);
00288 Point2D<int> p3(pos.i+x2, pos.j-y2);
00289
00290 drawLine(dst, p1, p2, col, rad);
00291 drawLine(dst, p1, p3, col, rad);
00292
00293 }
00294
00295
00296 template <class T>
00297 void drawRect(Image<T>& dst,
00298 const Rectangle& r, const T color, const int rad)
00299 {
00300 GVX_TRACE(__PRETTY_FUNCTION__);
00301 ASSERT(dst.initialized());
00302 ASSERT(r.isValid());
00303 ASSERT(dst.rectangleOk(r));
00304
00305 Point2D<int> p1(r.left(), r.top());
00306 Point2D<int> p2(r.rightI(), r.top());
00307 Point2D<int> p3(r.left(), r.bottomI());
00308 Point2D<int> p4(r.rightI(), r.bottomI());
00309
00310 drawLine(dst, p1, p2, color, rad);
00311 drawLine(dst, p1, p3, color, rad);
00312 drawLine(dst, p3, p4, color, rad);
00313 drawLine(dst, p2, p4, color, rad);
00314 }
00315
00316
00317 template <class T>
00318 void drawRectSquareCorners(Image<T>& dst, const Rectangle& r1,
00319 const T color, const int linewidth)
00320 {
00321 GVX_TRACE(__PRETTY_FUNCTION__);
00322 ASSERT(dst.initialized());
00323 ASSERT(r1.isValid());
00324
00325 const Rectangle r = r1.getOverlap(dst.getBounds());
00326
00327 ASSERT(dst.rectangleOk(r));
00328
00329 const int minrad = (linewidth - 1) / 2;
00330
00331 for (int i = 0; i < linewidth; ++i)
00332 {
00333 const int offset = i - minrad;
00334
00335 const Point2D<int> p1(r.left() + offset, r.top() + offset);
00336 const Point2D<int> p2(r.rightI() - offset, r.top() + offset);
00337 const Point2D<int> p3(r.left() + offset, r.bottomI() - offset);
00338 const Point2D<int> p4(r.rightI() - offset, r.bottomI() - offset);
00339
00340 drawLine(dst, p1, p2, color, 1);
00341 drawLine(dst, p1, p3, color, 1);
00342 drawLine(dst, p3, p4, color, 1);
00343 drawLine(dst, p2, p4, color, 1);
00344 }
00345 }
00346
00347
00348 template <class T>
00349 void drawRectOR(Image<T>& dst,
00350 const Rectangle& r, const T color, const int rad,
00351 const float ori)
00352 {
00353 GVX_TRACE(__PRETTY_FUNCTION__);
00354 ASSERT(dst.initialized());
00355
00356
00357
00358 const float centerX = r.rightI() - r.left();
00359 const float centerY = r.bottomI() - r.top();
00360
00361
00362
00363
00364 const float distX = centerX/2;
00365 const float distY = centerY/2;
00366 const float radius = sqrt(pow(distX,2) + pow(distY,2));
00367
00368
00369 const float thetaO = atan(distX/distY);
00370 const float thetaN1 = thetaO + ori;
00371 const float thetaN2 = ori - thetaO;
00372 const float Xnew1 = radius * sin(thetaN1);
00373 const float Ynew1 = radius * cos(thetaN1);
00374 const float Xnew2 = radius * sin(thetaN2);
00375 const float Ynew2 = radius * cos(thetaN2);
00376
00377
00378 const float Xbr = r.left() + distX + Xnew1;
00379 const float Ybr = r.top() + distY + Ynew1;
00380 const float Xtl = r.left() + distX - Xnew1;
00381 const float Ytl = r.top() + distY - Ynew1;
00382 const float Xbl = r.left() + distX + Xnew2;
00383 const float Ybl = r.top() + distY + Ynew2;
00384 const float Xtr = r.left() + distX - Xnew2;
00385 const float Ytr = r.top() + distY - Ynew2;
00386
00387
00388 Point2D<int> p1((int)round(Xbr), (int)round(Ybr));
00389 Point2D<int> p2((int)round(Xtl), (int)round(Ytl));
00390 Point2D<int> p3((int)round(Xbl), (int)round(Ybl));
00391 Point2D<int> p4((int)round(Xtr), (int)round(Ytr));
00392
00393
00394 drawLine(dst, p1, p3, color, rad);
00395 drawLine(dst, p1, p4, color, rad);
00396 drawLine(dst, p2, p3, color, rad);
00397 drawLine(dst, p2, p4, color, rad);
00398 }
00399
00400
00401 template <class T>
00402 void drawRectEZ(Image<T>& dst,
00403 const Rectangle& r, const T color, const int rad)
00404 {
00405 GVX_TRACE(__PRETTY_FUNCTION__);
00406 if (!r.isValid()) return;
00407
00408 ASSERT(dst.initialized());
00409
00410 if (dst.rectangleOk(r))
00411 {
00412 Point2D<int> p1(r.left(), r.top());
00413 Point2D<int> p2(r.rightI(), r.top());
00414 Point2D<int> p3(r.left(), r.bottomI());
00415 Point2D<int> p4(r.rightI(), r.bottomI());
00416
00417 drawLine(dst, p1, p2, color, rad);
00418 drawLine(dst, p1, p3, color, rad);
00419 drawLine(dst, p3, p4, color, rad);
00420 drawLine(dst, p2, p4, color, rad);
00421 }
00422 else
00423 {
00424 const Rectangle r2 = r.getOverlap(dst.getBounds());
00425
00426 int rl = r2.left(); int rt = r2.top();
00427 int rr = r2.rightI(); int rb = r2.bottomI();
00428
00429 Point2D<int> p1(rl, rt); Point2D<int> p2(rr, rt);
00430 Point2D<int> p3(rl, rb); Point2D<int> p4(rr, rb);
00431
00432 drawLine(dst, p1, p2, color, rad); drawLine(dst, p1, p3, color, rad);
00433 drawLine(dst, p3, p4, color, rad); drawLine(dst, p2, p4, color, rad);
00434 }
00435
00436 }
00437
00438
00439 template <class T>
00440 void drawFilledRect(Image<T>& dst, const Rectangle& r, const T val)
00441 {
00442 GVX_TRACE(__PRETTY_FUNCTION__);
00443 ASSERT(dst.rectangleOk(r));
00444
00445 const int w = dst.getWidth();
00446
00447 const int rw = r.width();
00448 const int rh = r.height();
00449
00450 const int rowskip = w - rw;
00451
00452 typename Image<T>::iterator dptr = dst.beginw() + r.left() + r.top() * w;
00453
00454 for (int y = 0; y < rh; ++y)
00455 {
00456 for (int x = 0; x < rw; ++x)
00457 *dptr++ = val;
00458 dptr += rowskip;
00459 }
00460 }
00461
00462
00463 template <class T>
00464 Image<T> drawHistogram(std::vector<float> hist, int width, int height, T lineVal, T fillVal)
00465 {
00466 Image<T> ret = Image<T>(width,height,ZEROS);
00467 if(hist.size() == 0)
00468 return ret;
00469 float recWidth = width/float(hist.size()+1);
00470 float peak = *std::max_element(hist.begin(),hist.end());
00471 float recScale = height/float(peak);
00472 for(uint h=0; h< hist.size(); h++)
00473 {
00474 Dims d = Dims(floor(recWidth),std::max(int(floor(recScale*(hist[h]))),1));
00475 Point2D<int> p = Point2D<int>(floor(recWidth*h+recWidth/2.0),0);
00476 Rectangle rec = Rectangle(p,d);
00477 if(!ret.rectangleOk(rec))
00478 {
00479 LINFO("H[%d] failed with p %s and Dims %s",h,convertToString(p).c_str(),convertToString(d).c_str());
00480 LFATAL("Histogram rectangle invalid");
00481 }
00482 drawFilledRect(ret,rec,fillVal);
00483 drawRectSquareCorners(ret,rec,lineVal,1);
00484 }
00485 return ret;
00486 }
00487
00488
00489 template <class T>
00490 void drawCross(Image<T>& dst,
00491 const Point2D<int>& p, const T col, const int siz,
00492 const int rad)
00493 {
00494 GVX_TRACE(__PRETTY_FUNCTION__);
00495 ASSERT(dst.initialized());
00496 Point2D<int> p1, p2;
00497
00498 p1.i = clampValue(p.i - siz, 0, dst.getWidth() - 1);
00499 p1.j = clampValue(p.j, 0, dst.getHeight() - 1);
00500 p2.i = clampValue(p.i + siz, 0, dst.getWidth() - 1);
00501 p2.j = clampValue(p.j, 0, dst.getHeight() - 1);
00502
00503 drawLine(dst, p1, p2, col, rad);
00504
00505 p1.i = clampValue(p.i, 0, dst.getWidth() - 1);
00506 p1.j = clampValue(p.j - siz, 0, dst.getHeight() - 1);
00507 p2.i = clampValue(p.i, 0, dst.getWidth() - 1);
00508 p2.j = clampValue(p.j + siz, 0, dst.getHeight() - 1);
00509
00510 drawLine(dst, p1, p2, col, rad);
00511 }
00512
00513
00514 template <class T>
00515 void drawCrossOR(Image<T>& dst,
00516 const Point2D<int>& p, const T col, const int siz,
00517 const int rad, const float ori)
00518 {
00519 GVX_TRACE(__PRETTY_FUNCTION__);
00520 ASSERT(dst.initialized());
00521 Point2D<int> p1, p2;
00522
00523
00524 const float newX = siz * sin(ori);
00525 const float newY = siz * cos(ori);
00526
00527 p1.i = clampValue(int(p.i - newY), 0, dst.getWidth() - 1);
00528 p1.j = clampValue(int(p.j + newX), 0, dst.getHeight() - 1);
00529
00530 p2.i = clampValue(int(p.i + newY), 0, dst.getWidth() - 1);
00531 p2.j = clampValue(int(p.j - newX), 0, dst.getHeight() - 1);
00532
00533 drawLine(dst, p1, p2, col, rad);
00534
00535 p1.i = clampValue(int(p.i - newX), 0, dst.getWidth() - 1);
00536 p1.j = clampValue(int(p.j - newY), 0, dst.getHeight() - 1);
00537
00538 p2.i = clampValue(int(p.i + newX), 0, dst.getWidth() - 1);
00539 p2.j = clampValue(int(p.j + newY), 0, dst.getHeight() - 1);
00540
00541 drawLine(dst, p1, p2, col, rad);
00542 }
00543
00544
00545 template <class T>
00546 void drawPatch(Image<T>& dst,
00547 const Point2D<int>& p, const int siz, const T col)
00548 {
00549 GVX_TRACE(__PRETTY_FUNCTION__);
00550 ASSERT(dst.initialized());
00551 for (int i = -siz; i <= siz; ++i)
00552 for (int j = -siz; j <= siz; ++j)
00553 {
00554 const int xx = clampValue(p.i + i, 0, dst.getWidth() - 1);
00555 const int yy = clampValue(p.j + j, 0, dst.getHeight() - 1);
00556 dst.setVal(xx, yy, col);
00557 }
00558 }
00559
00560
00561 template <class T>
00562 void drawPatchBB(Image<T>& dst, const Point2D<int>& p, const int siz, const T col, const T bgcol)
00563 {
00564 GVX_TRACE(__PRETTY_FUNCTION__);
00565 ASSERT(dst.initialized());
00566
00567 for (int i = -siz-2; i <= siz+2; ++i)
00568 for (int j = -siz-2; j <= siz+2; ++j)
00569 {
00570 const int xx = clampValue(p.i + i, 0, dst.getWidth() - 1);
00571 const int yy = clampValue(p.j + j, 0, dst.getHeight() - 1);
00572 if (i < -siz || i > siz || j < -siz || j > siz) dst.setVal(xx, yy, bgcol);
00573 else dst.setVal(xx, yy, col);
00574 }
00575 }
00576
00577
00578 template <class T>
00579 void drawCircle(Image<T>& dst,
00580 const Point2D<int>& p, const int radius,
00581 const T col, const int rad)
00582 {
00583 GVX_TRACE(__PRETTY_FUNCTION__);
00584 ASSERT(dst.initialized());
00585 if (radius == 1)
00586 {
00587 if (dst.coordsOk(p)) dst.setVal(p.i, p.j, col);
00588 return;
00589 }
00590
00591 Point2D<int> pp(p);
00592 pp.i -= radius; drawDisk(dst, pp, rad, col);
00593 pp.i += radius + radius; drawDisk(dst, pp, rad, col);
00594 int bound1 = radius, bound2 = radius;
00595
00596 for (int y = 1; y <= radius; y ++)
00597 {
00598 bound2 = bound1;
00599 bound1 = int(sqrtf(float( squareOf(radius) - squareOf(y) )));
00600 for (int i = bound1; i <= bound2; i ++)
00601 {
00602 pp.j = p.j - y;
00603 pp.i = p.i - i; drawDisk(dst, pp, rad, col);
00604 pp.i = p.i + i; drawDisk(dst, pp, rad, col);
00605 pp.j = p.j + y; drawDisk(dst, pp, rad, col);
00606 pp.i = p.i - i; drawDisk(dst, pp, rad, col);
00607 }
00608 }
00609 }
00610
00611
00612 template <class T>
00613 void drawEllipse(Image<T>& dst,
00614 const Point2D<int>& p, const int radiusx, const int radiusy,
00615 const T col, const int rad)
00616 {
00617 GVX_TRACE(__PRETTY_FUNCTION__);
00618 ASSERT(dst.initialized());
00619
00620 int steps = 36;
00621 double a = double(M_PI*2.0)/double(steps);
00622 double sa = (double)sin(a);
00623 double ca = (double)cos(a);
00624
00625 double ny=1;
00626 double nz=0;
00627 Point2D<int> lastPoint(p.i + radiusx, p.j);
00628 for(int i=1; i<=steps; i++)
00629 {
00630 double tmp = ca*ny - sa*nz;
00631 nz = sa*ny + ca*nz;
00632 ny = tmp;
00633 Point2D<int> newPoint(p.i+(ny*radiusx),p.j+(nz*radiusy));
00634 drawLine(dst, lastPoint, newPoint, col, rad);
00635 lastPoint = newPoint;
00636 }
00637
00638
00639 }
00640
00641
00642 template <class T_or_RGB>
00643 void drawSuperquadric(Image<T_or_RGB>& dst,
00644 const Point2D<int>& p,
00645 const float a, const float b, const float e, const T_or_RGB col,
00646 const float rot, const float k1, const float k2,
00647 const float thetai,
00648 const float thetaf,
00649 const int rad,
00650 const int nSeg)
00651
00652 {
00653 const float dTheta = (thetaf-thetai) / (float)nSeg;
00654
00655 for (float theta=thetai; theta < thetaf; theta += dTheta)
00656 {
00657 Point2D<float> p1 = ellipsoid(a,b, e, theta);
00658 Point2D<float> p2 = ellipsoid(a,b, e, theta + dTheta);
00659
00660 Point2D<float> tmpPos1;
00661 Point2D<float> tmpPos2;
00662
00663 tmpPos1.i = p1.i + p1.j*k1;
00664 tmpPos1.j = p1.i*k2 + p1.j;
00665
00666 tmpPos2.i = p2.i + p2.j*k1;
00667 tmpPos2.j = p2.i*k2 + p2.j;
00668
00669
00670 p1.i = (cos(rot)*tmpPos1.i - sin(rot)*tmpPos1.j) + p.i;
00671 p1.j = (sin(rot)*tmpPos1.i + cos(rot)*tmpPos1.j) + p.j;
00672
00673 p2.i = (cos(rot)*tmpPos2.i - sin(rot)*tmpPos2.j) + p.i;
00674 p2.j = (sin(rot)*tmpPos2.i + cos(rot)*tmpPos2.j) + p.j;
00675
00676 drawLine(dst, (Point2D<int>)p1, (Point2D<int>)p2, col, rad);
00677 }
00678
00679 }
00680
00681
00682
00683 template <class T>
00684 void drawArrow(Image<T>& dst,
00685 const Point2D<int>& p1, const Point2D<int>& p2,
00686 const T col, const int rad)
00687 {
00688 GVX_TRACE(__PRETTY_FUNCTION__);
00689
00690 drawLine(dst, p1, p2, col, rad);
00691
00692 Point2D<int> pm; pm.i = (p1.i + p2.i) / 2; pm.j = (p1.j + p2.j) / 2;
00693 float norm = float(std::max(dst.getWidth(), dst.getHeight())) / 30.0F;
00694 float angle = atan2((float)(p2.j - p1.j), (float)(p2.i - p1.i));
00695 float arrow_angle = 20.0F * M_PI / 180.0F;
00696 Point2D<int> pp;
00697 pp.i = pm.i - int(norm * cos(angle + arrow_angle));
00698 pp.j = pm.j - int(norm * sin(angle + arrow_angle));
00699 drawLine(dst, pm, pp, col, rad);
00700 pp.i = pm.i - int(norm * cos(angle - arrow_angle));
00701 pp.j = pm.j - int(norm * sin(angle - arrow_angle));
00702 drawLine(dst, pm, pp, col, rad);
00703 }
00704
00705
00706 template <class T>
00707 void drawGrid(Image<T>& dst,
00708 const int spacingX, const int spacingY,
00709 const int thickX, const int thickY,
00710 const T col)
00711 {
00712 GVX_TRACE(__PRETTY_FUNCTION__);
00713 ASSERT(dst.initialized());
00714 for (int i = thickX / 2; i < dst.getWidth() - thickX / 2; i += spacingX)
00715 for (int j = 0; j < dst.getHeight(); j ++)
00716 for (int t = -thickX / 2; t <= thickX / 2; t ++)
00717 dst.setVal(i + t, j, col);
00718
00719 for (int j = thickY / 2; j < dst.getHeight() - thickY / 2; j += spacingY)
00720 for (int i = 0; i < dst.getWidth(); i ++)
00721 for (int t = -thickY / 2; t <= thickY / 2; t ++)
00722 dst.setVal(i, t + j, col);
00723 }
00724
00725
00726 template <class T, class TT>
00727 void drawContour2D(const Image<T>& src, Image<TT>& dst, const TT& col, const byte rad)
00728 {
00729
00730 ASSERT(src.initialized());
00731 ASSERT(dst.initialized());
00732 ASSERT(src.isSameSize(dst));
00733
00734 typename Image<T>::const_iterator sptr = src.begin();
00735 T z = T(); const int h = src.getHeight(), w = src.getWidth();
00736
00737
00738
00739
00740 Point2D<int> p(0, 0);
00741
00742
00743 for (p.i = 0; p.i < w; ++p.i) if (*sptr++) drawDisk(dst, p, rad, col);
00744
00745
00746 if (h == 1) return;
00747
00748
00749 for (p.j = 1; p.j < h-1; ++p.j)
00750 {
00751
00752 p.i = 0; if (*sptr++) drawDisk(dst, p, rad, col);
00753
00754
00755 if (w == 1) continue;
00756
00757
00758 for (p.i = 1; p.i < w-1; ++p.i) {
00759 if (*sptr && (sptr[-1] == z || sptr[1] == z || sptr[-w] == z || sptr[w] == z)) drawDisk(dst, p, rad, col);
00760 ++sptr;
00761 }
00762
00763
00764 p.i = w-1; if (*sptr++) drawDisk(dst, p, rad, col);
00765 }
00766
00767
00768 p.j = h-1; for (p.i = 0; p.i < w; ++p.i) if (*sptr++) drawDisk(dst, p, rad, col);
00769 }
00770
00771
00772 template <class T>
00773 void drawGrid(Image<T>& dst, const uint nx, const uint ny, const int thick, const T col)
00774 {
00775 GVX_TRACE(__PRETTY_FUNCTION__);
00776 ASSERT(dst.initialized());
00777
00778 const float wx = float(dst.getWidth()) / float(nx), hy = float(dst.getHeight()) / float(ny);
00779 for (uint j = 0; j < ny; ++j)
00780 {
00781 const int py1 = int(hy*(j)+0.49999F);
00782 const int py2 = int(hy*(j+1)+0.49999F);
00783 for (uint i = 0; i < nx; ++i)
00784 {
00785 const int px1 = int(wx*(i)+0.49999F);
00786 const int px2 = int(wx*(i+1)+0.49999F);
00787 drawLine(dst, Point2D<int>(px1, py2-1), Point2D<int>(px2-1, py2-1), col, thick);
00788 drawLine(dst, Point2D<int>(px2-1, py1), Point2D<int>(px2-1, py2-1), col, thick);
00789 }
00790 }
00791 drawLine(dst, Point2D<int>(0, 0), Point2D<int>(dst.getWidth()-1, 0), col, thick);
00792 drawLine(dst, Point2D<int>(0, 0), Point2D<int>(0, dst.getHeight()-1), col, thick);
00793 }
00794
00795
00796 template <class T>
00797 void writeText(Image<T>& dst,
00798 const Point2D<int>& pt, const char* text,
00799 const T col, const T bgcol, const SimpleFont& f,
00800 const bool transparent_bg,
00801 const TextAnchor anchor)
00802 {
00803 GVX_TRACE(__PRETTY_FUNCTION__);
00804
00805 const int textwidth = strlen(text) * f.w();
00806 const int textheight = f.h();
00807
00808 const Point2D<int> top_left
00809 = anchor == ANCHOR_BOTTOM_RIGHT ? pt - Point2D<int>(textwidth, textheight)
00810 : anchor == ANCHOR_BOTTOM_LEFT ? pt - Point2D<int>(0, textheight)
00811 : anchor == ANCHOR_TOP_RIGHT ? pt - Point2D<int>(textwidth, 0)
00812 : pt;
00813
00814 Point2D<int> p = top_left;
00815 const int ww = dst.getWidth(), hh = dst.getHeight();
00816 const int len = int(strlen(text));
00817
00818 for (int i = 0; i < len; i ++)
00819 {
00820 const unsigned char *ptr = f.charptr(text[i]);
00821
00822 for (int y = 0; y < int(f.h()); y ++)
00823 for (int x = 0; x < int(f.w()); x ++)
00824 if (p.i + x >= 0 && p.i + x < ww && p.j + y >= 0 && p.j + y < hh)
00825 {
00826 if (!ptr[y * f.w() + x])
00827 dst.setVal(p.i + x, p.j + y, col);
00828 else if (!transparent_bg)
00829 dst.setVal(p.i + x, p.j + y, bgcol);
00830 }
00831 p.i += f.w();
00832 }
00833 }
00834
00835
00836 template <class T>
00837 Image<T> makeMultilineTextBox(const int w,
00838 const std::string* lines,
00839 const size_t nlines,
00840 const T col,
00841 const T bg,
00842 const size_t max_chars_per_line_hint,
00843 const int fontwidth)
00844 {
00845 size_t maxchars = 0;
00846
00847 if (max_chars_per_line_hint > 0)
00848 maxchars = max_chars_per_line_hint;
00849 else
00850 for (size_t i = 0; i < nlines; ++i)
00851 if (lines[i].length() > maxchars)
00852 maxchars = lines[i].length();
00853
00854 if (maxchars > 0)
00855 {
00856 const SimpleFont font =
00857 SimpleFont::fixedMaxWidth(fontwidth ? fontwidth : size_t(w)/maxchars);
00858
00859 Image<T> textarea(w, 4 + nlines*(font.h()+2), ZEROS);
00860
00861 for (size_t i = 0; i < nlines; ++i)
00862 writeText(textarea, Point2D<int>(1,1+i*(font.h()+2)),
00863 lines[i].c_str(),
00864 col, bg,
00865 font);
00866
00867 return textarea;
00868 }
00869
00870 return Image<T>();
00871 }
00872
00873
00874 template <class T>
00875 void drawPoint(Image<T>& dst,
00876 int X,int Y,T pix)
00877 {
00878 GVX_TRACE(__PRETTY_FUNCTION__);
00879 dst.setVal(X,Y,pix);
00880 if(X > 0) dst.setVal((X-1),Y,pix);
00881 if(Y > 0) dst.setVal(X,(Y-1),pix);
00882 if(X < (dst.getWidth()-1)) dst.setVal((X+1),Y,pix);
00883 if(Y < (dst.getHeight()-1)) dst.setVal(X,(Y+1),pix);
00884 }
00885
00886
00887 template <class T>
00888 int drawDiskCheckTarget(Image<T>& dst,
00889 Image<T>& mask,
00890 const Point2D<int>& center,
00891 const int radius,
00892 const T value,
00893 const T targetvalue,
00894 const T floodvalue)
00895 {
00896 GVX_TRACE(__PRETTY_FUNCTION__);
00897 ASSERT(dst.initialized());
00898 ASSERT(floodvalue < targetvalue);
00899 int nbhit = 0; Point2D<int> hitpt;
00900 for (int y = -radius; y <= radius; y ++)
00901 {
00902 int bound = (int)(sqrt( (double)( squareOf(radius) - squareOf(y) ) ));
00903 for (int x = -bound; x <= bound; x ++)
00904 if (dst.coordsOk(x + center.i, y + center.j))
00905 {
00906 dst.setVal(x + center.i, y + center.j, value);
00907 if (mask.getVal(x + center.i, y + center.j) == targetvalue)
00908 {
00909 nbhit ++;
00910 hitpt.i = x + center.i, hitpt.j = y + center.j;
00911
00912 Image<T> tmp = mask;
00913 flood(tmp, mask, hitpt, targetvalue, floodvalue);
00914 }
00915 }
00916 }
00917 return nbhit;
00918 }
00919
00920
00921 template <class T>
00922 Image<PixRGB<T> > warp3D(const Image<PixRGB<T> >& ima,
00923 const Image<float>& zmap,
00924 const float pitch, const float yaw,
00925 const float zMax, Dims& dims)
00926 {
00927 GVX_TRACE(__PRETTY_FUNCTION__);
00928 ASSERT(ima.isSameSize(zmap));
00929
00930 float cp = float(cos(double(pitch) * M_PI / 180.0));
00931 float sp = float(sin(double(pitch) * M_PI / 180.0));
00932 float cy = float(cos(double(yaw) * M_PI / 180.0));
00933 float sy = float(sin(double(yaw) * M_PI / 180.0));
00934 int iw = ima.getWidth(), ih = ima.getHeight();
00935
00936
00937 int xmin = 0, zmin = 0, xmax = 0, zmax = 0, xx, zz;
00938
00939
00940 zz = int(-cp * zMax);
00941 zmin = std::min(zmin, zz);
00942 zmax = std::max(zmax, zz);
00943
00944 xx = int(sy * ih);
00945 xmin = std::min(xmin, xx);
00946 xmax = std::max(xmax, xx);
00947 zz = int(- cy * sp * ih);
00948 zmin = std::min(zmin, zz);
00949 zmax = std::max(zmax, zz);
00950
00951 zz = int(- cy * sp * ih - cp * zMax);
00952 zmin = std::min(zmin, zz);
00953 zmax = std::max(zmax, zz);
00954
00955 xx = int(cy * iw);
00956 xmin = std::min(xmin, xx);
00957 xmax = std::max(xmax, xx);
00958 zz = int(sy * sp * iw);
00959 zmin = std::min(zmin, zz);
00960 zmax = std::max(zmax, zz);
00961
00962 zz = int(sy * sp * iw - cp * zMax);
00963 zmin = std::min(zmin, zz);
00964 zmax = std::max(zmax, zz);
00965
00966 xx = int(cy * iw + sy * ih);
00967 xmin = std::min(xmin, xx);
00968 xmax = std::max(xmax, xx);
00969 zz = int(sy * sp * iw - cy * sp * ih);
00970 zmin = std::min(zmin, zz);
00971 zmax = std::max(zmax, zz);
00972
00973 zz = int(sy * sp * iw - cy * sp * ih - cp * zMax);
00974 zmin = std::min(zmin, zz);
00975 zmax = std::max(zmax, zz);
00976
00977 int nw, nh;
00978 if (dims.isEmpty())
00979 {
00980 nw = ((xmax - xmin) * 12) / 10;
00981 nh = ((zmax - zmin) * 16) / 10;
00982
00983 dims = Dims(nw, nh);
00984 }
00985 else
00986 {
00987 nw = dims.w(); nh = dims.h();
00988 }
00989 Image<PixRGB<T> > result(nw, nh, ZEROS);
00990
00991 int xoff = -xmin + nw / 10;
00992 int zoff = -zmin + nh / 10;
00993
00994
00995 int *prev_zz = new int[nw]; memset(prev_zz, 0, nw * sizeof(int));
00996 int *prev_xx = new int[nw]; memset(prev_xx, 0, nw * sizeof(int));
00997 int ppzz = 0, ppxx = 0;
00998 for (int j = 0; j < ih; j ++)
00999 for (int i = 0; i < iw; i ++)
01000 {
01001 float x = float(i);
01002 float y = float(j);
01003 float z = - zmap.getVal(i, j);
01004
01005
01006 xx = xoff + int(cy * x + sy * y);
01007 zz = zoff + int(sy * sp * x - cy * sp * y + cp * z);
01008 xx = clampValue(xx, 0, nw-1);
01009 zz = clampValue(zz, 0, nh-1);
01010
01011
01012 PixRGB<T> pix, col;
01013 bool drawn = false;
01014 ima.getVal(i, j, col);
01015 if (j > 0 && zz > prev_zz[i] + 1)
01016 {
01017 result.getVal(prev_xx[i], prev_zz[i], pix);
01018 drawLine(result, Point2D<int>(xx, zz),
01019 Point2D<int>(prev_xx[i], prev_zz[i]),
01020 col);
01021 result.setVal(prev_xx[i], prev_zz[i], pix);
01022 drawn = true;
01023 }
01024 if (i > 0 && j > 0 && zz > ppzz + 1)
01025 {
01026 result.getVal(ppxx, ppzz, pix);
01027 drawLine(result, Point2D<int>(xx, zz),
01028 Point2D<int>(ppxx, ppzz),
01029 col);
01030 result.setVal(ppxx, ppzz, pix);
01031 drawn = true;
01032 }
01033 if (i > 0 && (zz > prev_zz[i-1] + 1||
01034 zz < prev_zz[i-1] - 1))
01035 {
01036 result.getVal(prev_xx[i-1], prev_zz[i-1], pix);
01037 drawLine(result, Point2D<int>(xx, zz),
01038 Point2D<int>(prev_xx[i-1], prev_zz[i-1]),
01039 col);
01040 result.setVal(prev_xx[i-1], prev_zz[i-1], pix);
01041 drawn = true;
01042 }
01043 if (drawn == false)
01044 result.setVal(xx, zz, col);
01045
01046 ppzz = prev_zz[i]; ppxx = prev_xx[i];
01047 prev_zz[i] = zz; prev_xx[i] = xx;
01048 }
01049 delete [] prev_zz; delete [] prev_xx;
01050
01051 return result;
01052 }
01053
01054
01055 Image< PixRGB<byte> >
01056 formatMapForDisplay(const Image<float>& img, const float factor,
01057 const Dims& newdims, const bool useInterp,
01058 const ColorMap& cmap, const bool showColorScale,
01059 const char *label)
01060 {
01061 GVX_TRACE(__PRETTY_FUNCTION__);
01062
01063 Image<float> ftmp = img;
01064
01065
01066 if (ftmp.initialized() == false) ftmp.resize(newdims, true);
01067
01068
01069 float omi, oma;
01070 if (factor != 0.0F) { getMinMax(ftmp, omi, oma); ftmp *= factor; }
01071 else inplaceNormalize(ftmp, 0.0F, 255.0F, omi, oma);
01072
01073
01074 Image<byte> btmp = ftmp;
01075
01076
01077 Image< PixRGB<byte> > ctmp = colorize(btmp, cmap);
01078
01079
01080 ctmp = rescaleOpt(ctmp, newdims, useInterp);
01081 const uint w = ctmp.getWidth(), h = ctmp.getHeight();
01082 const SimpleFont f = SimpleFont::FIXED(6);
01083 int ty = h - f.h() - 1;
01084
01085
01086 drawRect(ctmp, Rectangle::tlbrI(0, 0, h-1, w-1), PixRGB<byte>(64, 64, 255), 1);
01087
01088
01089 if (showColorScale)
01090 {
01091 const float fac = float(cmap.getWidth()) / float(w);
01092 for (uint i = 0; i < w; i ++)
01093 drawLine(ctmp, Point2D<int>(i, h-4), Point2D<int>(i, h-1), cmap.getVal(int(i * fac)), 1);
01094 ty -= 4;
01095 }
01096
01097
01098 if (label) writeText(ctmp, Point2D<int>(2,2), label, PixRGB<byte>(128,255,128),
01099 PixRGB<byte>(0), SimpleFont::FIXED(10), true);
01100
01101
01102 std::string smin = sformat("%0.02g", omi);
01103 std::string smax = sformat("%0.02g", oma);
01104
01105
01106
01107 if (factor)
01108 {
01109 smin = std::string("<") + smin;
01110 smax = std::string(">") + smax;
01111 }
01112
01113
01114 smin = std::string(" ") + smin + std::string(" ");
01115 smax = std::string(" ") + smax + std::string(" ");
01116
01117
01118 if (w >= f.w() * (smin.length() + smax.length()))
01119 {
01120 const PixRGB<byte> tcol(255, 255, 128);
01121 const PixRGB<byte> bcol(1);
01122
01123 writeText(ctmp, Point2D<int>(1, ty), smin.c_str(), tcol, bcol, f);
01124 writeText(ctmp, Point2D<int>(w - smax.length()*f.w() - 1, ty), smax.c_str(), tcol, bcol, f);
01125 }
01126
01127 return ctmp;
01128 }
01129
01130
01131 template <typename T, class U>
01132 Image<PixRGB<byte> > linePlot(const U& points, const int w,const int h,
01133 const T& minVal, const T& maxVal,
01134 const char *title,
01135 const char *ylabel,
01136 const char *xlabel,
01137 const PixRGB<byte>& linecol,
01138 const PixRGB<byte>& bckcol,
01139 const int numticks,
01140 const bool axisonright)
01141 {
01142
01143
01144 const int vecLength = points.size();
01145 T maxv(maxVal), minv(minVal);
01146
01147
01148 if (minVal == 0 && maxVal == 0)
01149 {
01150 typename U::const_iterator iter = points.begin();
01151 while (iter != points.end())
01152 {
01153 if (*iter > maxv)
01154 maxv = *iter;
01155 if (*iter < minv)
01156 minv = *iter;
01157 ++iter;
01158 }
01159 }
01160
01161 SimpleFont sf = SimpleFont::fixedMaxHeight(uint(0.125F*h));
01162 SimpleFont sn = SimpleFont::fixedMaxHeight(uint(0.075F*h));
01163 std::string ymaxstr = sformat("%1.2f",(float)maxv);
01164 std::string yminstr = sformat("%1.2f",(float)minv);
01165
01166
01167 int labelsize = ymaxstr.size() > yminstr.size() ? ymaxstr.size() : yminstr.size();
01168
01169
01170
01171 if (labelsize < 7)
01172 labelsize = 7;
01173
01174 int hborder = (int)(labelsize * sn.w() + sf.w() * 1.5F);
01175 int vborder = (int)(sn.h() + sf.h() * 1.5F);
01176
01177
01178 const int thickness = (h / 90) > 0 ? (h / 90) : 1;
01179
01180
01181
01182 Image<PixRGB<byte> > result(h, w, ZEROS);
01183 result += bckcol;
01184
01185
01186 Point2D<float> origin(axisonright ? w - hborder : hborder, h - vborder);
01187 Point2D<float> originraw(hborder, h - vborder);
01188 Point2D<float> xlim(!axisonright ? w - hborder : hborder, h - vborder);
01189 Point2D<float> ylim(axisonright ? w - hborder : hborder, vborder);
01190 float xpos, ypos;
01191
01192 if (strlen(ylabel) > 0)
01193 {
01194 xpos = origin.j + (ylim.j - origin.j) / 2.0F -
01195 sf.w() * strlen(ylabel) / 2.0F;
01196 if (axisonright)
01197 ypos = ylim.i + sn.h() + sn.h() / 2.0F;
01198 else
01199 ypos = vborder - sn.h() - sn.h() / 2.0F;
01200 writeText(result,Point2D<int>((int)xpos, (int)ypos), ylabel,
01201 linecol, bckcol, sf);
01202 result = flipVertic(transpose(result));
01203 }
01204
01205 if (strlen(title) > 0)
01206 {
01207 xpos = origin.i + (xlim.i - origin.i)/2.0F -
01208 sf.w() * strlen(title) / 2.0F;
01209 ypos = vborder - 1.25 * sf.h();
01210 writeText(result, Point2D<int>((int)xpos, (int)ypos),
01211 title, linecol, bckcol, sf);
01212 }
01213
01214 if(strlen(xlabel) > 0)
01215 {
01216 xpos = origin.i + (xlim.i - origin.i) / 2.0F -
01217 sf.w() * strlen(xlabel) / 2.0F;
01218 ypos = origin.j + sn.h() + sn.h() / 2.0F;
01219 writeText(result,Point2D<int>( (int)xpos,(int)ypos),
01220 xlabel, linecol, bckcol, sf);
01221 }
01222
01223 if (numticks >= 0)
01224 {
01225 if (axisonright)
01226 xpos = ylim.i + sn.w() * 2.0F;
01227 else
01228 xpos = hborder - (sn.w() * ymaxstr.size() + sn.w() * 2.0F);
01229 ypos = ylim.j;
01230 writeText(result, Point2D<int>((int)xpos,(int)ypos),
01231 ymaxstr.c_str(), linecol, bckcol, sn);
01232
01233 if (axisonright)
01234 xpos = ylim.i + sn.w() * 2.0F;
01235 else
01236 xpos = hborder - (sn.w() * yminstr.size() + sn.w() * 2.0F);
01237 ypos = ylim.j;
01238 ypos = origin.j - sn.h();
01239 writeText(result, Point2D<int>((int)xpos, (int)ypos),
01240 yminstr.c_str(), linecol, bckcol, sn);
01241
01242
01243 float tspace = (xlim.i - origin.i)/(float)numticks;
01244 for (int ii = 0; ii <= numticks; ++ii)
01245 {
01246
01247 xpos = tspace * ii + origin.i;
01248 Point2D<int> tick((int)xpos, (int)xlim.j),
01249 ticke((int)xpos, int(tick.j - sn.h()));
01250 drawLine(result, tick, ticke, linecol, thickness);
01251
01252
01253 float xval = (float)vecLength / (float)numticks * (float)ii;
01254 std::string ticklabel(sformat("%1.2f", xval));
01255 int offset = strlen(ticklabel.c_str())*(int)sn.w()/2;
01256 tick.i -= offset; tick.j += sn.h() / 2;
01257
01258 writeText(result,tick,ticklabel.c_str(), linecol, bckcol, sn);
01259 }
01260 }
01261
01262 Point2D<int> origin_int((int)origin.i,(int)origin.j);
01263 Point2D<int> originraw_int((int)originraw.i,(int)originraw.j);
01264 Point2D<int> xlim_int((int)xlim.i,(int)xlim.j);
01265 Point2D<int> ylim_int((int)ylim.i,(int)ylim.j);
01266
01267 drawLine(result, origin_int, xlim_int, linecol, thickness);
01268 drawLine(result, origin_int, ylim_int, linecol , thickness);
01269
01270
01271 T newMaxY = h - vborder, newMinY = vborder;
01272 T newMaxX = w - hborder, newMinX = hborder;
01273 int xPoints[vecLength], yPoints[vecLength];
01274
01275 for (int i = 0; i < vecLength; i++)
01276 {
01277 xPoints[i] = (int)((newMaxX - newMinX) * (float)i / vecLength + newMinX);
01278
01279 T p = points[i];
01280 if (points[i] < minv) p = minv;
01281 else if (points[i] > maxv) p = maxv;
01282
01283 yPoints[i] = (int)((newMaxY - newMinY) * (p - minv)/(maxv - minv) + newMinY + .5);
01284
01285 if (i == 0)
01286 drawLine(result, originraw_int,
01287 Point2D<int>(xPoints[i],(int)(newMaxY - yPoints[i] + vborder)), linecol, thickness);
01288 else
01289 drawLine(result,
01290 Point2D<int>(xPoints[i-1],(int)(newMaxY - yPoints[i-1] + vborder)),
01291 Point2D<int>(xPoints[i], (int)(newMaxY - yPoints[i] + vborder)),
01292 linecol, thickness);
01293 }
01294 return result;
01295 }
01296
01297
01298 template <typename T>
01299 Image<PixRGB<byte> > multilinePlot(const std::vector<std::vector<T> >& lines, const int w,
01300 const int h,T minVal, T maxVal,
01301 const char *title,
01302 const char *ylabel,
01303 const char *xlabel,
01304 const std::vector<PixRGB<byte> >& linescolor,
01305 const PixRGB<byte>& gridcolor,
01306 const PixRGB<byte>& bckcolor)
01307 {
01308
01309
01310
01311 int defvecLength = 0;
01312
01313 if(lines.size() !=0){
01314
01315 defvecLength = lines[0].size();
01316 for(size_t i=0; i<lines.size(); i++)
01317 defvecLength = std::min(defvecLength, (int)lines[i].size());
01318
01319 if (defvecLength != 0 && minVal == 0 && maxVal == 0)
01320 {
01321 maxVal = lines[0][0];
01322 for(int l = 0; l < (int)lines.size();l++)
01323 {
01324
01325 std::vector<T> points = lines[l];
01326 const int vecLength = points.size();
01327 for(int i = 0; i < vecLength ; i++)
01328 if(points[i] > maxVal)
01329 maxVal = points[i];
01330
01331 minVal = points[0];
01332 for(int i = 0; i < vecLength ; i++)
01333 if(points[i] < minVal)
01334 minVal = points[i];
01335 }
01336 }
01337 }
01338
01339
01340
01341
01342 SimpleFont sf = SimpleFont::fixedMaxHeight(int(.1*h));
01343 SimpleFont sn = SimpleFont::fixedMaxHeight(int(.01*h));
01344 std::string ymaxstr = sformat("%1.2f",(float)maxVal);
01345 std::string yminstr = sformat("%1.2f",(float)minVal);
01346
01347
01348 int hborder;
01349 ymaxstr.size() > yminstr.size() ?
01350 hborder = ymaxstr.size() : hborder = yminstr.size();
01351
01352
01353 if (hborder < 7)
01354 hborder = 7;
01355 hborder = (int)(hborder * sn.w() + sf.w()*1.5);
01356 int vborder = (int)(sf.h() * 1.5);
01357
01358
01359
01360 Image<PixRGB<byte> > result(h, w, ZEROS);
01361 result += bckcolor;
01362
01363
01364 Point2D<float> origin(hborder, h - vborder);
01365 Point2D<float> xlim(w-hborder, h - vborder);
01366 Point2D<float> ylim(hborder, vborder);
01367
01368
01369 float pos = origin.j + (ylim.j - origin.j)/2.0F -
01370 float(sf.w()*strlen(ylabel))/2.0F;
01371 writeText(result,Point2D<int>((int)pos, (int)(vborder - 1.25*sf.h())),
01372 ylabel, gridcolor, bckcolor, sf);
01373 result = flipVertic(transpose(result));
01374
01375 writeText(result,Point2D<int>(hborder-sn.w()*ymaxstr.size()-1,
01376 (int)ylim.j-sn.h()),
01377 ymaxstr.c_str(), gridcolor, bckcolor, sn);
01378
01379 writeText(result,Point2D<int>(hborder - sn.w() * yminstr.size() -1,
01380 (int)origin.j),
01381 yminstr.c_str(), gridcolor, bckcolor, sn);
01382
01383 pos = origin.i + (xlim.i - origin.i)/2.0F - float(sf.w()*strlen(title))/2;
01384 writeText(result, Point2D<int>( (int)pos, (int)(vborder - 1.25*sf.h())),
01385 title, gridcolor, bckcolor, sf);
01386
01387 pos = origin.i + (xlim.i - origin.i)/2.0F - float(sf.w()*strlen(xlabel))/2.0F;
01388 writeText(result,Point2D<int>( (int)pos,(int)( origin.j + 1.1 * sf.h())),
01389 xlabel, gridcolor, bckcolor, sf);
01390
01391
01392 Point2D<int> origin_int((int)origin.i,(int)origin.j),
01393 xlim_int((int)xlim.i,(int)xlim.j),
01394 ylim_int((int)ylim.i,(int)ylim.j);
01395
01396
01397 T newMaxY = h - vborder, newMinY = vborder;
01398 T newMaxX = w - hborder, newMinX = hborder;
01399 int xPoints[defvecLength], yPoints[defvecLength];
01400
01401 for(int j = 0; j < (int)lines.size(); j++)
01402 {
01403
01404
01405 PixRGB<byte> linecolor(255,255,255) ;
01406 if(j < (int)linescolor.size())
01407 linecolor = linescolor[j];
01408
01409 for (int i = 0; i < defvecLength; i++)
01410 {
01411 xPoints[i] = (int)((newMaxX - newMinX) * (float)i / defvecLength + newMinX);
01412 yPoints[i] = (int)((newMaxY - newMinY) *
01413 (lines[j][i] - minVal)/(maxVal - minVal) + newMinY + .5);
01414
01415 if (i == 0)
01416 drawLine(result, origin_int,
01417 Point2D<int>(xPoints[i],(int)( newMaxY - yPoints[i] + vborder)),
01418 linecolor, 1);
01419 else
01420 drawLine(result,
01421 Point2D<int>(xPoints[i-1],(int)(newMaxY - yPoints[i-1] + vborder)),
01422 Point2D<int>(xPoints[i], (int)(newMaxY - yPoints[i] + vborder)),
01423 linecolor, 1);
01424 }
01425 }
01426
01427 drawLine(result, origin_int, xlim_int, gridcolor, 1);
01428 drawLine(result, origin_int, ylim_int, gridcolor , 1);
01429
01430 return result;
01431 }
01432
01433
01434
01435 template <class T>
01436 void drawOutlinedPolygon(Image<T>& img, const std::vector<Point2D<int> >& polygon,
01437 const T col,
01438 const Point2D<int> trans,
01439 const float rot,
01440 const float scale,
01441 const float k1,
01442 const float k2,
01443 const int rad)
01444 {
01445 GVX_TRACE(__PRETTY_FUNCTION__);
01446 for(uint i = 0; i<polygon.size(); i++)
01447 {
01448 Point2D<float> p1 = (Point2D<float>)polygon[i];
01449 Point2D<float> p2 = (Point2D<float>)polygon[(i+1)%polygon.size()];
01450
01451
01452 Point2D<float> tmpPos1;
01453 Point2D<float> tmpPos2;
01454
01455 tmpPos1.i = p1.i + p1.j*k1;
01456 tmpPos1.j = p1.i*k2 + p1.j;
01457
01458 tmpPos2.i = p2.i + p2.j*k1;
01459 tmpPos2.j = p2.i*k2 + p2.j;
01460
01461
01462 p1.i = scale*(cos(rot)*tmpPos1.i - sin(rot)*tmpPos1.j) + trans.i;
01463 p1.j = scale*(sin(rot)*tmpPos1.i + cos(rot)*tmpPos1.j) + trans.j;
01464
01465 p2.i = scale*(cos(rot)*tmpPos2.i - sin(rot)*tmpPos2.j) + trans.i;
01466 p2.j = scale*(sin(rot)*tmpPos2.i + cos(rot)*tmpPos2.j) + trans.j;
01467
01468 drawLine(img, (Point2D<int>)p1,(Point2D<int>)p2, col, rad);
01469 }
01470 }
01471
01472
01473 template <class T>
01474 void drawFilledPolygon(Image<T>& img, const std::vector<Point2D<int> >& polygon,
01475 const T col)
01476 {
01477
01478 const int w = static_cast<int>(img.getWidth());
01479 const int h = static_cast<int>(img.getHeight());
01480 typename Image<T>::iterator iptr = img.beginw();
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490 if (polygon.size() <= 0 ) return;
01491
01492 int edgeCount = polygon.size();
01493 int num = polygon.size();
01494 int minY = polygon[0].j;
01495 int startV1 = 0;
01496 for(uint c= 1; c < polygon.size(); c++)
01497 {
01498 if (polygon[c].j < minY)
01499 {
01500 minY = polygon[c].j;
01501 startV1 = c;
01502 }
01503 }
01504 int startV2 = startV1;
01505 int endV1 = startV1 - 1;
01506 if(endV1 < 0) endV1 = (num-1);
01507
01508 int endV2 = startV2 + 1;
01509 if (endV2 >= num) endV2 = 0;
01510
01511 minY = polygon[startV1].j;
01512 int x1 = polygon[startV1].i; int y1 = polygon[startV1].j;
01513 int x2 = polygon[endV1].i; int y2 = polygon[endV1].j;
01514
01515 int dx1 = ((x2 - x1) << 8) / (y2 - y1 + 1);
01516 int count1 = y2-y1;
01517 int xVal1 = x1 << 8;
01518
01519 int x11 = polygon[startV2].i; int y11 = polygon[startV2].j;
01520 int x22 = polygon[endV2].i; int y22 = polygon[endV2].j;
01521
01522 int dx2 = ((x22 - x11) << 8) / (y22 - y11 + 1);
01523 int count2 = y22-y11;
01524 int xVal2 = x11 << 8;
01525
01526 while (edgeCount > 1)
01527 {
01528 while ( (count1 > 0) && (count2 > 0) )
01529 {
01530
01531 for(int x = xVal1>>8; x <= xVal2>>8; x++)
01532 if (x >= 0 && x < w && minY >= 0 && minY < h)
01533 iptr[x + w * minY] = col;
01534
01535 xVal1 += dx1; xVal2 += dx2;
01536 count1--; count2--;
01537 minY++;
01538 }
01539 if (count1 == 0)
01540 {
01541 edgeCount--;
01542 startV1 = endV1;
01543 endV1--;
01544 if (endV1 < 0) endV1 = num-1;
01545
01546 minY = polygon[startV1].j;
01547 x1 = polygon[startV1].i; y1 = polygon[startV1].j;
01548 x2 = polygon[endV1].i; y2 = polygon[endV1].j;
01549 dx1 = ((x2 - x1) << 8) / (abs(y2 - y1) + 1);
01550 count1 = y2-y1;
01551 xVal1 = x1 << 8;
01552 }
01553 if (count2 == 0)
01554 {
01555 edgeCount--;
01556 startV2 = endV2;
01557 endV2++;
01558 if(endV2 >= num) endV2 = 0;
01559 minY = polygon[startV2].j;
01560 x11 = polygon[startV2].i; y11 = polygon[startV2].j;
01561 x22 = polygon[endV2].i; y22 = polygon[endV2].j;
01562 dx2 = ((x22 - x11) << 8) / (abs(y22 - y11) + 1);
01563 count2 = y22-y11;
01564 xVal2 = x11 << 8;
01565 }
01566 }
01567 }
01568
01569
01570 Image<PixRGB<byte> > drawMeters(const MeterInfo* infos, const size_t ninfo,
01571 const size_t nx, const Dims& meterdims)
01572 {
01573 if (ninfo == 0) return Image<PixRGB<byte> >();
01574
01575 ASSERT(meterdims.w() > 0 && meterdims.h() > 0);
01576
01577 size_t maxlabelsize = infos[0].label.size();
01578 for (size_t i = 1; i < ninfo; ++i)
01579 if (infos[i].label.size() > maxlabelsize) maxlabelsize = infos[i].label.size();
01580
01581 const SimpleFont f = SimpleFont::fixedMaxHeight(meterdims.h());
01582
01583 const int meterx = f.w() * (maxlabelsize + 10);
01584 const int maxmeterlen = meterdims.w() - meterx;
01585
01586 const size_t ny = (ninfo + nx-1) / nx;
01587
01588 Image<PixRGB<byte> > result(meterdims.w() * nx, meterdims.h() * ny, ZEROS);
01589
01590 for (size_t i = 0; i < ninfo; ++i) {
01591 const size_t ay = i % ny, ax = i / ny;
01592
01593 const std::string txt = sformat("%*s %6.2e", int(maxlabelsize), infos[i].label.c_str(), infos[i].val);
01594
01595 writeText(result, Point2D<int>(meterdims.w() * ax, meterdims.h() * ay),
01596 txt.c_str(), PixRGB<byte>(255), PixRGB<byte>(0), f);
01597
01598 const int meterlen = clampValue(int(maxmeterlen * infos[i].val / infos[i].valmax), 1, maxmeterlen);
01599
01600 const int threshlen =
01601 (infos[i].thresh < 0.0 || infos[i].thresh > infos[i].valmax) ?
01602 -1 : int(maxmeterlen * infos[i].thresh / infos[i].valmax);
01603
01604 Image<PixRGB<byte> >::iterator itr = result.beginw()
01605 + meterdims.w()*ax + meterx + ay*meterdims.h()*result.getWidth();
01606
01607 const int rowskip = result.getWidth() - maxmeterlen;
01608
01609 const PixRGB<byte> c1(infos[i].color);
01610 const PixRGB<byte> c2(c1/2);
01611 const PixRGB<byte> c3(c2/3);
01612 const PixRGB<byte> c4(c3/2);
01613
01614 for (int y = 0; y < meterdims.h()-1; ++y) {
01615 for (int x = 0; x < meterlen; ++x)
01616 *itr++ = (x == threshlen) ? PixRGB<byte>(255,255,255) : (x & 1) ? c2 : c1;
01617 for (int x = meterlen; x < maxmeterlen; ++x)
01618 *itr++ = (x == threshlen) ? PixRGB<byte>(255,255,255) : (x & 1) ? c4 : c3;
01619 itr += rowskip;
01620 }
01621 }
01622 return result;
01623 }
01624
01625
01626
01627
01628
01629 #include "inst/Image/DrawOps.I"
01630
01631
01632 template
01633 Image<PixRGB<byte> > linePlot(const std::vector<double>& points, const int w,
01634 const int h, const double& minVal, const double& maxVal,
01635 const char *title,
01636 const char *ylabel,
01637 const char *xlabel,
01638 const PixRGB<byte>& linecol,
01639 const PixRGB<byte>& bckcol,
01640 const int numticks, const bool axisonright);
01641
01642 template
01643 Image<PixRGB<byte> > linePlot(const std::deque<double>& points, const int w,
01644 const int h, const double& minVal, const double& maxVal,
01645 const char *title,
01646 const char *ylabel,
01647 const char *xlabel,
01648 const PixRGB<byte>& linecol,
01649 const PixRGB<byte>& bckcol,
01650 const int numticks, const bool axisonright);
01651
01652 template
01653 Image<PixRGB<byte> > linePlot(const std::deque<float>& points, const int w,
01654 const int h, const float& minVal, const float& maxVal,
01655 const char *title,
01656 const char *ylabel,
01657 const char *xlabel,
01658 const PixRGB<byte>& linecol,
01659 const PixRGB<byte>& bckcol,
01660 const int numticks, const bool axisonright);
01661
01662 template
01663 Image<PixRGB<byte> > linePlot(const std::vector<float>& points, const int w,
01664 const int h, const float& minVal, const float& maxVal,
01665 const char *title,
01666 const char *ylabel,
01667 const char *xlabel,
01668 const PixRGB<byte>& linecol,
01669 const PixRGB<byte>& bckcol,
01670 const int numticks, const bool axisonright);
01671
01672 template
01673 Image<PixRGB<byte> > linePlot(const std::vector<int>& points, const int w,
01674 const int h, const int& minVal, const int& maxVal,
01675 const char *title,
01676 const char *ylabel,
01677 const char *xlabel,
01678 const PixRGB<byte>& linecol,
01679 const PixRGB<byte>& bckcol,
01680 const int numticks, const bool axisonright);
01681
01682
01683 template
01684 void drawContour2D(const Image<byte>& src, Image< PixRGB<byte> >& dst, const PixRGB<byte> &col, const byte rad);
01685
01686 template
01687 void drawContour2D(const Image<byte>& src, Image<byte>& dst, const byte &col, const byte rad);
01688
01689 template
01690 Image<PixRGB<byte> > drawHistogram(std::vector<float> hist, int width, int height, PixRGB<byte> lineVal, PixRGB<byte> fillVal);
01691
01692
01693
01694
01695