00001
00002
00003
00004
00005
00006
00007
00008
00009 #ifndef ROI_HPP_
00010 #define ROI_HPP_
00011
00012 #include <cmath>
00013 #include <boost/shared_ptr.hpp>
00014
00015 #include "jmath/jblas.hpp"
00016
00017 #include "image/Image.hpp"
00018 #include "image/imageException.hpp"
00019
00020 #define USE_TEMPLATE_INLINE 0
00021
00022 namespace jafar {
00023 namespace image {
00024 using namespace jblas;
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 class ConvexRoi;
00043 class SliceRoi;
00044
00045
00046
00051 struct Pixel
00052 {
00053 int x, y;
00054 private:
00055 int x_end;
00056 friend class ConvexRoi;
00057 friend class SliceRoi;
00058 };
00059
00060 struct Slice
00061 {
00062 int y, x1, x2;
00063 private:
00064 void* next;
00065 friend class ConvexRoi;
00066 friend class SliceRoi;
00067 };
00068
00069
00070 class ConvexRoi
00071 {
00072 public:
00073 struct SliceImpl { int x, w; };
00074 typedef std::vector<SliceImpl> ConvexRoiImpl;
00075 private:
00076 cv::Rect rect;
00077 ConvexRoiImpl convex;
00078 bool hasConvex;
00079 int count_;
00080 mutable int y_end;
00081 private:
00082 void initConvex()
00083 {
00084 convex.resize(rect.height);
00085 for(ConvexRoiImpl::iterator it = convex.begin(); it != convex.end(); ++it)
00086 {
00087 it->x = 0;
00088 it->w = rect.width;
00089 }
00090 hasConvex = true;
00091 }
00092 public:
00093
00094 ConvexRoi(): rect(cv::Rect(0,0,0,0)), hasConvex(false), count_(0) {}
00095 ConvexRoi(cv::Rect &rect): rect(rect), convex(), hasConvex(false), count_(rect.width*rect.height) {}
00096 ConvexRoi(int x, int y, int width, int height): rect(x,y,width,height), convex(), hasConvex(false), count_(width*height) {}
00097 ConvexRoi(jblas::vec2 x, jblas::sym_mat22 P, double scale);
00098
00099 void init(cv::Rect _rect) { rect = _rect; convex.resize(0); hasConvex = false; count_ = rect.width*rect.height; }
00100
00101
00102 int y( ) const { return rect.y; }
00103 int h( ) const { return rect.height; }
00104 int x( ) const { return rect.x; }
00105 int w( ) const { return rect.width; }
00106
00107
00108 private:
00109 int x(int i) const { return rect.x + (hasConvex ? convex[i-rect.y].x : 0); }
00110 int w(int i) const { return hasConvex ? convex[i-rect.y].w : rect.width; }
00111 public:
00112
00113
00114 void start_slice(Slice &s) const { s.y = rect.y-1; y_end = y()+h(); }
00115 bool next_slice(Slice &s) const
00116 {
00117 ++s.y;
00118 if (s.y >= y_end) return false;
00119 s.x1 = x(s.y);
00120 s.x2 = x(s.y)+w(s.y)-1;
00121 return true;
00122 }
00123
00124
00125 void start(Pixel &pix) const { pix.y = y(); pix.x = x(pix.y)-1; pix.x_end = x(pix.y)+w(pix.y); y_end = y()+h(); }
00126 bool next(Pixel &pix) const
00127 {
00128 ++pix.x;
00129 if (pix.x >= pix.x_end)
00130 {
00131 ++pix.y;
00132 if (pix.y >= y_end) return false;
00133 pix.x = x(pix.y);
00134 pix.x_end = x(pix.y)+w(pix.y);
00135 }
00136 return true;
00137 }
00138
00139
00140 int size( ) const { return w()*h(); }
00141 int count( ) const { return count_; }
00142 bool isIn(jblas::vec2 p) const
00143 {
00144 int py = std::floor(p(1));
00145 int px = std::floor(p(0));
00146 return (py >= y() && py < y()+h() && px >= x(py) && px < x(py)+w(py));
00147 }
00148
00150 ConvexRoi operator+ (const ConvexRoi &roi) const
00151 {
00152 ConvexRoi res(*this);
00153
00154 JFR_ERROR(ImageException, ImageException::NOT_IMPLEMENTED, "this operator hasn't been implemented yet");
00155 return res;
00156 }
00157
00159 ConvexRoi& operator+=(const ConvexRoi &roi)
00160 {
00161
00162 JFR_ERROR(ImageException, ImageException::NOT_IMPLEMENTED, "this operator hasn't been implemented yet");
00163 return *this;
00164 }
00165
00167 ConvexRoi operator- (const ConvexRoi &roi) const
00168 {
00169 ConvexRoi res(*this);
00170
00171 JFR_ERROR(ImageException, ImageException::NOT_IMPLEMENTED, "this operator hasn't been implemented yet");
00172 return res;
00173 }
00174
00176 ConvexRoi& operator-=(const ConvexRoi &roi)
00177 {
00178
00179 JFR_ERROR(ImageException, ImageException::NOT_IMPLEMENTED, "this operator hasn't been implemented yet");
00180 return *this;
00181 }
00182
00184 ConvexRoi operator* (const ConvexRoi &roi) const
00185 {
00186
00187 cv::Rect newRect;
00188 newRect.x = std::max(rect.x, roi.rect.x);
00189 int x2 = std::min(rect.x+rect.width-1, roi.rect.x+roi.rect.width-1);
00190 newRect.width = std::max(0, x2-newRect.x+1);
00191 newRect.y = std::max(rect.y, roi.rect.y);
00192 int y2 = std::min(rect.y+rect.height-1, roi.rect.y+roi.rect.height-1);
00193 newRect.height = std::max(0, y2-newRect.y+1);
00194
00195 if (!hasConvex && !roi.hasConvex)
00196 {
00197 return ConvexRoi(newRect);
00198 } else
00199 if (hasConvex && roi.hasConvex)
00200 {
00201
00202 JFR_ERROR(ImageException, ImageException::NOT_IMPLEMENTED, "this operator hasn't been implemented yet");
00203 } else
00204 {
00205 ConvexRoi newRoi(newRect);
00206 newRoi.initConvex();
00207 newRoi.count_ = 0;
00208
00209 const cv::Rect &oldRect = (hasConvex ? roi.rect : rect);
00210 const ConvexRoiImpl &oldConvex = (hasConvex ? convex : roi.convex);
00211 const cv::Rect &oldConvexRect = (hasConvex ? rect : roi.rect);
00212
00213 int shift = std::max(0, oldRect.y - oldConvexRect.y);
00214 int lastY = -1000000;
00215 int minX1 = 1000000, maxX2 = -1000000;
00216
00217 for(int y = 0; y < newRect.height; ++y)
00218 {
00219 SliceImpl &newSlice = newRoi.convex[y];
00220 SliceImpl const &oldSlice = oldConvex[y+shift];
00221 newSlice.x = std::max(newRect.x, oldConvexRect.x+oldSlice.x)-newRect.x;
00222 int newX2 = std::min(newRect.x+newRect.width-1, oldConvexRect.x+oldSlice.x+oldSlice.w-1);
00223 newSlice.w = newX2-(newRect.x+newSlice.x)+1;
00224
00225 if (newSlice.x >= newRect.width || newSlice.w <= 0)
00226 {
00227 if (lastY == -1000000)
00228 {
00229 newRect.y++; newRect.height--;
00230 shift++;
00231 y--;
00232 continue;
00233 } else
00234 {
00235 newSlice.x = 0;
00236 newSlice.w = 0;
00237 }
00238
00239 } else
00240 {
00241 lastY = y;
00242 newRoi.count_ += newSlice.w;
00243 if (newSlice.x < minX1) minX1 = newSlice.x;
00244 if (newX2 > maxX2) maxX2 = newX2;
00245
00246 }
00247 }
00248 if (lastY == -1000000)
00249 {
00250 newRoi.rect.height = 0;
00251 newRoi.convex.resize(0);
00252 } else
00253 {
00254 newRoi.rect.height = lastY+1;
00255 newRoi.rect.width = maxX2-minX1-newRect.x+1;
00256 newRoi.rect.x += minX1;
00257 newRoi.convex.resize(newRoi.rect.height);
00258 if (minX1 != 0) for(int y = 0; y < newRect.height; ++y) newRoi.convex[y].x -= minX1;
00259 }
00260
00261
00262
00263 newRoi.checkIntegrity();
00264 return newRoi;
00265 }
00266 }
00267
00269 ConvexRoi& operator*=(const ConvexRoi &roi)
00270 {
00271 *this = *this * roi;
00272 return *this;
00273 }
00274
00276 ConvexRoi operator+ (const cv::Point &p) const
00277 {
00278 ConvexRoi res(*this);
00279 res.rect.x += p.x;
00280 res.rect.y += p.y;
00281 return res;
00282 }
00284 ConvexRoi operator- (const cv::Point &p) const
00285 {
00286 ConvexRoi res(*this);
00287 res.rect.x -= p.x;
00288 res.rect.y -= p.y;
00289 return res;
00290 }
00291
00293 ConvexRoi& operator+=(const cv::Point &p)
00294 {
00295 rect.x += p.x;
00296 rect.y += p.y;
00297 return *this;
00298 }
00300 ConvexRoi& operator-=(const cv::Point &p)
00301 {
00302 rect.x -= p.x;
00303 rect.y -= p.y;
00304 return *this;
00305 }
00306
00308 void scaleTo(cv::Rect &newRect)
00309 {
00310
00311 cv::Point desiredOr(newRect.x, newRect.y);
00312 if (hasConvex)
00313 {
00314
00315 ConvexRoi newRoi(newRect);
00316 newRoi.initConvex();
00317 ConvexRoiImpl &newConvex = newRoi.convex;
00318
00319 double fw = newRect.width / (double)rect.width;
00320 newRect.x=std::floor(rect.x*fw);
00321
00322
00323 for(ConvexRoiImpl::iterator it = convex.begin(); it != convex.end(); ++it)
00324 {
00325
00326
00327
00328
00329
00330
00331 it->x = std::floor((rect.x + it->x)*fw) - newRect.x;
00332 it->w = std::ceil(it->w*fw);
00333 if (it->x+it->w > newRect.width) it->w = newRect.width-it->x;
00334
00335 }
00336
00337 int i = 0;
00338 newRoi.count_ = 0;
00339 double fh = newRect.height / (double)rect.height;
00340 newRect.y=std::floor(rect.y*fh);
00341 for(ConvexRoiImpl::iterator it = newConvex.begin(); it != newConvex.end(); ++it, ++i)
00342 {
00343
00344
00345 int jj1 = std::floor(i/fh), jj2 = std::ceil((i+1)/fh);
00346 if (jj2 >= rect.height) jj2 = rect.height-1;
00347 int x1 = convex[jj1].x, x2 = convex[jj1].x+convex[jj1].w-1;
00348 for (int j = jj1+1; j <= jj2; ++j)
00349 {
00350 if (convex[j].x < x1) x1 = convex[j].x;
00351 int x2j = convex[j].x+convex[j].w-1;
00352 if (x2j > x2) x2 = x2j;
00353 }
00354 it->x = x1;
00355 it->w = x2-x1+1;
00356 newRoi.count_ += it->w;
00357
00358 }
00359 #ifndef JFR_NDEBUG
00360 newRoi.rect = newRect;
00361 newRoi.checkIntegrity();
00362 #endif
00363 *this = newRoi;
00364 } else
00365 {
00366 count_ = newRect.width*newRect.height;
00367 }
00368 rect = newRect;
00369 if (desiredOr.x >= 0) rect.x = desiredOr.x;
00370 if (desiredOr.y >= 0) rect.y = desiredOr.y;
00371 checkIntegrity();
00372 }
00373
00374
00376 ConvexRoi operator* (double f) const
00377 {
00378 ConvexRoi res(*this);
00379 res *= f;
00380 return res;
00381 }
00382
00384 ConvexRoi& operator*=(double f)
00385 {
00386 cv::Rect newRect(-1,-1, std::ceil(rect.width *f), std::ceil(rect.height*f));
00387 scaleTo(newRect);
00388 return *this;
00389 }
00390
00392 ConvexRoi& scale(double f)
00393 {
00394 cv::Point center(rect.x+rect.width/2, rect.y+rect.height/2);
00395 cv::Rect newRect(-1,-1, std::ceil(rect.width *f), std::ceil(rect.height*f));
00396 scaleTo(newRect);
00397 cv::Point newcenter(rect.x+rect.width/2, rect.y+rect.height/2);
00398 cv::Point shift = center-newcenter;
00399 *this += shift;
00400 return *this;
00401 }
00402
00403
00404 void draw()
00405 {
00406 std::cout << "rect: " << rect << std::endl;
00407 for(int i = 0; i < rect.height; ++i)
00408 {
00409 int x1 = convex[i].x;
00410 int x2 = convex[i].x+convex[i].w-1;
00411 for(int j = 0; j < x1; ++j) std::cout << ".";
00412 for(int j = x1; j <= x2; ++j) std::cout << "#";
00413 for(int j = x2+1; j < rect.width; ++j) std::cout << ".";
00414 std::cout << std::endl;
00415 }
00416 }
00417
00418 void checkIntegrity()
00419 {
00420 #ifndef JFR_NDEBUG
00421 JFR_ASSERT(rect.x > -1000000, "ConvexRoi::checkIntegrity failed");
00422 JFR_ASSERT(rect.x < 1000000, "ConvexRoi::checkIntegrity failed");
00423 JFR_ASSERT(rect.y > -1000000, "ConvexRoi::checkIntegrity failed");
00424 JFR_ASSERT(rect.y < 1000000, "ConvexRoi::checkIntegrity failed");
00425 JFR_ASSERT(rect.width >= 0, "ConvexRoi::checkIntegrity failed");
00426 JFR_ASSERT(rect.width < 1000000, "ConvexRoi::checkIntegrity failed");
00427 JFR_ASSERT(rect.height >= 0, "ConvexRoi::checkIntegrity failed");
00428 JFR_ASSERT(rect.height < 1000000, "ConvexRoi::checkIntegrity failed");
00429
00430 if (hasConvex)
00431 {
00432 JFR_ASSERT((int)convex.size() == rect.height, "ConvexRoi::checkIntegrity failed");
00433 int minX1 = 2000000000, maxX2 = -2000000000;
00434 int recount = 0;
00435 for(ConvexRoiImpl::iterator it = convex.begin(); it != convex.end(); ++it)
00436 {
00437 JFR_ASSERT(std::abs(it->x) < 2000000000 && std::abs(it->w) < 2000000000, "ConvexRoi::checkIntegrity failed")
00438 if (it->x < minX1) minX1 = it->x;
00439 int x2 = it->x+it->w-1;
00440 if (x2 > maxX2) maxX2 = x2;
00441 recount += it->w;
00442 }
00443 if (rect.height > 0 && rect.width > 0)
00444 {
00445 JFR_ASSERT(minX1 == 0,"ConvexRoi::checkIntegrity failed");
00446 JFR_ASSERT(maxX2 == rect.width-1, "ConvexRoi::checkIntegrity failed");
00447 }
00448 JFR_ASSERT(recount == count_, "ConvexRoi::checkIntegrity failed");
00449 }
00450 #endif
00451 }
00452
00453 friend std::ostream& operator<<(std::ostream &os, ConvexRoi::SliceImpl const &c);
00454 friend std::ostream& operator<<(std::ostream& os, ConvexRoi const& roi);
00455 friend class SliceRoi;
00456
00457 };
00458
00459 std::ostream& operator<<(std::ostream &os, ConvexRoi::SliceImpl const &c);
00460 std::ostream& operator<<(std::ostream& os, ConvexRoi const& roi);
00461
00462
00463 #if 1
00464
00470 class SliceRoi
00471 {
00472 public:
00473 struct SliceImpl
00474 {
00475 int x, w; SliceImpl *next;
00476 SliceImpl(int x, int w): x(x), w(w), next(NULL) {}
00477 SliceImpl(): x(-1), w(-1), next(NULL) {}
00478 };
00479 typedef std::vector<SliceImpl*> SliceRoiImpl;
00480 private:
00481 cv::Rect rect;
00482 mutable SliceRoiImpl slices;
00483 mutable bool hasSlices;
00484 int count_;
00485 mutable int y_end;
00486 private:
00487 void initSlices(bool full) const
00488 {
00489 slices.resize(rect.height);
00490 for(SliceRoiImpl::iterator it = slices.begin(); it != slices.end(); ++it)
00491 *it = full ? new SliceImpl(0,rect.width) : NULL;
00492 if (full) hasSlices = true;
00493 }
00494 void delete_slice_line(SliceImpl ** slice_start)
00495 {
00496 SliceImpl *next;
00497 for(SliceImpl * slice = *slice_start; slice; slice = next)
00498 {
00499 next = slice->next;
00500 delete slice;
00501 }
00502 *slice_start = NULL;
00503 }
00504 void delete_slices()
00505 {
00506 for(SliceRoiImpl::iterator it = slices.begin(); it != slices.end(); ++it) delete_slice_line(&(*it));
00507 slices.resize(0);
00508 hasSlices = false;
00509 }
00510 static unsigned merge_line(SliceImpl **newSlice, SliceImpl const * slice1, SliceImpl const * slice2)
00511 {
00512 JFR_ASSERT(*newSlice == NULL, "*newSlice must be NULL");
00513
00514 unsigned linecount = 0;
00515 int right = -1;
00516 while (slice1 || slice2)
00517 {
00518
00519 if ((!slice1 || slice1->x > right) && (!slice2 || slice2->x > right))
00520 {
00521 if (*newSlice)
00522 {
00523 (*newSlice)->w = right - (*newSlice)->x;
00524 linecount += (*newSlice)->w;
00525 newSlice = &((*newSlice)->next);
00526 }
00527
00528 if (slice1 && (!slice2 || slice1->x < slice2->x))
00529 {
00530 *newSlice = new SliceImpl(slice1->x, slice1->w);
00531 right = slice1->x + slice1->w;
00532 slice1 = slice1->next;
00533 }
00534 if (slice2 && (!slice1 || slice2->x <= slice1->x))
00535 {
00536 *newSlice = new SliceImpl(slice2->x, slice2->w);
00537 right = slice2->x + slice2->w;
00538 slice2 = slice2->next;
00539 }
00540 }
00541
00542
00543 if (slice1 && slice1->x <= right)
00544 {
00545 if (slice1->x+slice1->w > right) right = slice1->x+slice1->w;
00546 slice1 = slice1->next;
00547 }
00548
00549
00550 if (slice2 && slice2->x <= right)
00551 {
00552 if (slice2->x+slice2->w > right) right = slice2->x+slice2->w;
00553 slice2 = slice2->next;
00554 }
00555
00556 }
00557 (*newSlice)->w = right - (*newSlice)->x;
00558 linecount += (*newSlice)->w;
00559 return linecount;
00560 }
00561 public:
00562
00563 SliceRoi(): rect(cv::Rect(0,0,0,0)), hasSlices(false), count_(0) {}
00564 SliceRoi(cv::Rect &rect): rect(rect), slices(), hasSlices(false), count_(rect.width*rect.height) {}
00565 SliceRoi(int x, int y, int width, int height): rect(x,y,width,height), slices(), hasSlices(false), count_(width*height) {}
00566 SliceRoi(jblas::vec2 x, jblas::sym_mat22 P, double scale) { *this = ConvexRoi(x, P, scale); }
00567 SliceRoi(const SliceRoi & roi) { *this = roi; }
00568 SliceRoi & operator=(const SliceRoi & roi);
00569 SliceRoi(const ConvexRoi & roi) { *this = roi; }
00570 SliceRoi & operator=(const ConvexRoi & croi);
00571 ~SliceRoi() { delete_slices(); }
00572
00573 void init(cv::Rect _rect) { rect = _rect; slices.resize(0); hasSlices = false; count_ = rect.width*rect.height; }
00574
00575
00576 int y( ) const { return rect.y; }
00577 int h( ) const { return rect.height; }
00578 int x( ) const { return rect.x; }
00579 int w( ) const { return rect.width; }
00580
00581
00582 private:
00583 int x(int i) const { return rect.x + (hasSlices ? slices[i-rect.y]->x : 0); }
00584 int w(int i) const
00585 {
00586 if (!hasSlices) return rect.width;
00587 SliceImpl *slice = slices[i-rect.y];
00588 while (slice->next != NULL) slice = slice->next;
00589 return slice->x + slice->w - slices[i-rect.y]->x;
00590 }
00591 public:
00592
00593
00594 void start_slice(Slice &s) const { s.y = rect.y-1; s.next = NULL; y_end = y()+h(); }
00595 bool next_slice(Slice &s) const
00596 {
00597 SliceImpl *slice = (SliceImpl*)s.next;
00598 if (slice == NULL)
00599 {
00600 ++s.y;
00601 if (s.y >= y_end) return false;
00602 slice = slices[s.y-rect.y];
00603 }
00604 s.x1 = rect.x+slice->x;
00605 s.x2 = s.x1 + slice->w - 1;
00606 s.next = slice->next;
00607 return true;
00608 }
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626 int size( ) const { return w()*h(); }
00627 int count( ) const { return count_; }
00628 bool isIn(jblas::vec2 p) const
00629 {
00630 int py = std::floor(p(1))-rect.y;
00631 int px = std::floor(p(0))-rect.x;
00632 if (py < y() || py >= y()+h()) return false;
00633 for(SliceImpl *slice = slices[py]; slice != NULL; slice = slice->next)
00634 if (px >= slice->x && px < slice->x+slice->w) return true;
00635 return false;
00636 }
00637
00638
00640 SliceRoi operator+ (const SliceRoi &roi) const
00641 {
00642 cv::Rect newRect;
00643 newRect.x = std::min(rect.x, roi.rect.x);
00644 newRect.y = std::min(rect.y, roi.rect.y);
00645 newRect.width = std::max(rect.x+rect.width-1, roi.rect.x+roi.rect.width-1) - newRect.x + 1;
00646 newRect.height = std::max(rect.y+rect.height-1, roi.rect.y+roi.rect.height-1) - newRect.y + 1;
00647
00648 SliceRoi newRoi(newRect);
00649 newRoi.initSlices(false);
00650 newRoi.count_ = 0;
00651
00652 if (!hasSlices) initSlices(true);
00653 if (!roi.hasSlices) roi.initSlices(true);
00654
00655 for(int i = 0; i < newRect.height; ++i)
00656 {
00657 SliceImpl **newSlice = &(newRoi.slices[i]);
00658 SliceImpl const * slice1 = ((i < rect.y-newRect.y || i > rect.y+rect.height-1-newRect.y) ? NULL : slices[i-rect.y-newRect.y]);
00659 SliceImpl const * slice2 = ((i < roi.rect.y-newRect.y || i > roi.rect.y+roi.rect.height-1-newRect.y) ? NULL : roi.slices[i]);
00660
00661 newRoi.count_ += merge_line(newSlice, slice1, slice2);
00662 }
00663
00664 return newRoi;
00665 }
00666
00668 SliceRoi& operator+=(const SliceRoi &roi)
00669 {
00670 *this = *this + roi;
00671 return *this;
00672 }
00673
00675 SliceRoi operator- (const SliceRoi &roi) const
00676 {
00677 SliceRoi res(*this);
00678
00679 JFR_ERROR(ImageException, ImageException::NOT_IMPLEMENTED, "this operator hasn't been implemented yet");
00680 return res;
00681 }
00682
00684 SliceRoi& operator-=(const SliceRoi &roi)
00685 {
00686
00687 JFR_ERROR(ImageException, ImageException::NOT_IMPLEMENTED, "this operator hasn't been implemented yet");
00688 return *this;
00689 }
00690
00692 SliceRoi operator* (const SliceRoi &roi) const
00693 {
00694
00695 cv::Rect newRect;
00696 newRect.x = std::max(rect.x, roi.rect.x);
00697 int x2 = std::min(rect.x+rect.width-1, roi.rect.x+roi.rect.width-1);
00698 newRect.width = std::max(0, x2-newRect.x+1);
00699 newRect.y = std::max(rect.y, roi.rect.y);
00700 int y2 = std::min(rect.y+rect.height-1, roi.rect.y+roi.rect.height-1);
00701 newRect.height = std::max(0, y2-newRect.y+1);
00702
00703
00704 if (!hasSlices && !roi.hasSlices)
00705 {
00706 return SliceRoi(newRect);
00707 } else
00708 if (hasSlices && roi.hasSlices)
00709 {
00710
00711 JFR_ERROR(ImageException, ImageException::NOT_IMPLEMENTED, "this operator hasn't been implemented yet");
00712 } else
00713 {
00714 SliceRoi newRoi(newRect);
00715 newRoi.initSlices(false);
00716 newRoi.count_ = 0;
00717
00718 const cv::Rect &oldRect = (hasSlices ? roi.rect : rect);
00719 const SliceRoiImpl &oldSlices = (hasSlices ? slices : roi.slices);
00720 const cv::Rect &oldSlicesRect = (hasSlices ? rect : roi.rect);
00721
00722 int shiftY = std::max(0, oldRect.y - oldSlicesRect.y);
00723 int shiftX = std::max(0, oldRect.x - oldSlicesRect.x);
00724 int minX1 = 1000000, maxX2 = -1000000;
00725
00726
00727
00728 for(int y = 0; y < newRect.height; ++y)
00729 {
00730 SliceImpl **newSlice = &(newRoi.slices[y]);
00731 SliceImpl const * oldSlice = oldSlices[y+shiftY];
00732 for(; oldSlice != NULL; oldSlice = oldSlice->next)
00733 {
00734 if (oldSlice->x < shiftX)
00735 {
00736 if (oldSlice->x+oldSlice->w-1 >= shiftX);
00737 {
00738 (*newSlice) = new SliceImpl(0, std::min(newRect.width, oldSlice->w - shiftX));
00739 if (0 < minX1) minX1 = 0;
00740 int x2 = (*newSlice)->x+(*newSlice)->w-1; if (x2 > maxX2) maxX2 = x2;
00741 newRoi.count_ += (*newSlice)->w;
00742 newSlice = &((*newSlice)->next);
00743 }
00744 }
00745 else
00746 {
00747 if (oldSlice->x-shiftX < newRect.width)
00748 {
00749 (*newSlice) = new SliceImpl(oldSlice->x-shiftX, std::min(newRect.width-(oldSlice->x-shiftX), oldSlice->w));
00750 if ((*newSlice)->x < minX1) minX1 = (*newSlice)->x;
00751 int x2 = (*newSlice)->x+(*newSlice)->w-1; if (x2 > maxX2) maxX2 = x2;
00752 newRoi.count_ += (*newSlice)->w;
00753 newSlice = &((*newSlice)->next);
00754 }
00755 }
00756 }
00757 }
00758
00759
00760 int nremove;
00761
00762 for(nremove = 0; newRoi.slices[nremove] == NULL && nremove < newRect.height; nremove++);
00763 newRect.y += nremove; newRect.height -= nremove;
00764 for(int i = 0; i < newRect.height; ++i) newRoi.slices[i] = newRoi.slices[i+nremove]; newRoi.slices.resize(newRect.height);
00765
00766 for(nremove = 0; newRoi.slices[newRect.height-1-nremove] == NULL && nremove < newRect.height; nremove++);
00767 newRect.height -= nremove;
00768 newRoi.slices.resize(newRect.height);
00769
00770 if (minX1 > 0)
00771 {
00772 newRect.x += minX1; newRect.width -= minX1;
00773 for(int i = 0; i < newRect.height; ++i) for(SliceImpl *slice = newRoi.slices[i]; slice; slice = slice->next) slice->x -= minX1;
00774 maxX2 -= minX1;
00775 }
00776
00777 maxX2 = newRect.width-1-maxX2;
00778 if (maxX2 > 0) newRect.width -= maxX2;
00779
00780
00781
00782
00783 newRoi.checkIntegrity();
00784 return newRoi;
00785 }
00786 }
00787
00789 SliceRoi& operator*=(const SliceRoi &roi)
00790 {
00791 *this = *this * roi;
00792 return *this;
00793 }
00794
00796 SliceRoi operator+ (const cv::Point &p) const
00797 {
00798 SliceRoi res(*this);
00799 res.rect.x += p.x;
00800 res.rect.y += p.y;
00801 return res;
00802 }
00804 SliceRoi operator- (const cv::Point &p) const
00805 {
00806 SliceRoi res(*this);
00807 res.rect.x -= p.x;
00808 res.rect.y -= p.y;
00809 return res;
00810 }
00811
00813 SliceRoi& operator+=(const cv::Point &p)
00814 {
00815 rect.x += p.x;
00816 rect.y += p.y;
00817 return *this;
00818 }
00820 SliceRoi& operator-=(const cv::Point &p)
00821 {
00822 rect.x -= p.x;
00823 rect.y -= p.y;
00824 return *this;
00825 }
00826
00828
00829 void scaleTo(cv::Rect &newRect)
00830 {
00831
00832 cv::Point desiredOr(newRect.x, newRect.y);
00833 if (hasSlices)
00834 {
00835
00836 SliceRoi newRoi(newRect);
00837 newRoi.initSlices(false);
00838 SliceRoiImpl &newSlices = newRoi.slices;
00839
00840 double fw = newRect.width / (double)rect.width;
00841 newRect.x = std::floor(rect.x*fw);
00842
00843
00844
00845 for(SliceRoiImpl::iterator it = slices.begin(); it != slices.end(); ++it)
00846 {
00847 for(SliceImpl *slice = *it; slice != NULL; slice = slice->next)
00848 {
00849
00850 slice->x = std::floor((rect.x + slice->x)*fw - newRect.x);
00851 slice->w = std::ceil(slice->w*fw);
00852 if (slice->x+slice->w > newRect.width) slice->w = newRect.width-slice->x;
00853
00854 }
00855 }
00856
00857
00858
00859 int i = 0;
00860 newRoi.count_ = 0;
00861 double fh = newRect.height / (double)rect.height;
00862 newRect.y = std::floor(rect.y*fh);
00863 for(SliceRoiImpl::iterator it = newSlices.begin(); it != newSlices.end(); ++it, ++i)
00864 {
00865
00866 int jj1 = std::floor(i/fh), jj2 = std::ceil((i+1)/fh);
00867 if (jj2 >= rect.height) jj2 = rect.height-1;
00868 SliceImpl *merged_line[2] = { NULL, NULL};
00869 int midx = 0;
00870 for (int j = jj1+1; j <= jj2; ++j)
00871 {
00872 merge_line(&(merged_line[1-midx]), merged_line[midx], slices[j]);
00873 delete_slice_line(&(merged_line[midx]));
00874 midx = 1-midx;
00875 }
00876 *it = merged_line[midx];
00877 for(SliceImpl *slice = *it; slice; slice = slice->next) newRoi.count_ += slice->w;
00878
00879 }
00880 #ifndef JFR_NDEBUG
00881 newRoi.rect = newRect;
00882 newRoi.checkIntegrity();
00883 #endif
00884 *this = newRoi;
00885 } else
00886 {
00887 count_ = newRect.width*newRect.height;
00888 }
00889 rect = newRect;
00890 if (desiredOr.x >= 0) rect.x = desiredOr.x;
00891 if (desiredOr.y >= 0) rect.y = desiredOr.y;
00892 checkIntegrity();
00893 }
00894
00895
00897 SliceRoi operator* (double f) const
00898 {
00899 SliceRoi res(*this);
00900 res *= f;
00901 return res;
00902 }
00903
00905 SliceRoi& operator*=(double f)
00906 {
00907 cv::Rect newRect(-1,-1, std::ceil(rect.width *f), std::ceil(rect.height*f));
00908 scaleTo(newRect);
00909 return *this;
00910 }
00911
00913 SliceRoi& scale(double f)
00914 {
00915 cv::Point center(rect.x+rect.width/2, rect.y+rect.height/2);
00916 cv::Rect newRect(-1,-1, std::ceil(rect.width *f), std::ceil(rect.height*f));
00917 scaleTo(newRect);
00918 cv::Point newcenter(rect.x+rect.width/2, rect.y+rect.height/2);
00919 cv::Point shift = center-newcenter;
00920 *this += shift;
00921 return *this;
00922 }
00923
00924
00925 void draw()
00926 {
00927 std::cout << "rect: " << rect << std::endl;
00928 for(int i = 0; i < rect.height; ++i)
00929 {
00930 int x0 = 0;
00931 for(SliceImpl *slice = slices[i]; slice != NULL; slice = slice->next)
00932 {
00933 int x1 = slice->x;
00934 int x2 = slice->x+slice->w-1;
00935 for(int j = x0; j < x1; ++j) std::cout << ".";
00936 for(int j = x1; j <= x2; ++j) std::cout << "#";
00937 x0 = x2+1;
00938 }
00939 for(int j = x0+1; j < rect.width; ++j) std::cout << ".";
00940 std::cout << std::endl;
00941 }
00942 }
00943
00944 void checkIntegrity()
00945 {
00946 #ifndef JFR_NDEBUG
00947 JFR_ASSERT(rect.x > -1000000, "ConvexRoi::checkIntegrity failed");
00948 JFR_ASSERT(rect.x < 1000000, "ConvexRoi::checkIntegrity failed");
00949 JFR_ASSERT(rect.y > -1000000, "ConvexRoi::checkIntegrity failed");
00950 JFR_ASSERT(rect.y < 1000000, "ConvexRoi::checkIntegrity failed");
00951 JFR_ASSERT(rect.width >= 0, "ConvexRoi::checkIntegrity failed");
00952 JFR_ASSERT(rect.width < 1000000, "ConvexRoi::checkIntegrity failed");
00953 JFR_ASSERT(rect.height >= 0, "ConvexRoi::checkIntegrity failed");
00954 JFR_ASSERT(rect.height < 1000000, "ConvexRoi::checkIntegrity failed");
00955
00956 if (hasSlices)
00957 {
00958 JFR_ASSERT((int)slices.size() == rect.height, "ConvexRoi::checkIntegrity failed");
00959 int minX1 = 2000000000, maxX2 = -2000000000;
00960 int recount = 0;
00961 for(SliceRoiImpl::iterator it = slices.begin(); it != slices.end(); ++it)
00962 for(SliceImpl *slice = *it; slice; slice = slice->next)
00963 {
00964 JFR_ASSERT(std::abs(slice->x) < 2000000000 && std::abs(slice->w) < 2000000000, "ConvexRoi::checkIntegrity failed")
00965 if (slice->x < minX1) minX1 = slice->x;
00966 int x2 = slice->x+slice->w-1;
00967 if (x2 > maxX2) maxX2 = x2;
00968 recount += slice->w;
00969 }
00970 if (rect.height > 0 && rect.width > 0)
00971 {
00972 JFR_ASSERT(minX1 == 0,"ConvexRoi::checkIntegrity failed");
00973 JFR_ASSERT(maxX2 == rect.width-1, "ConvexRoi::checkIntegrity failed");
00974 }
00975 JFR_ASSERT(recount == count_, "ConvexRoi::checkIntegrity failed");
00976 }
00977 #endif
00978 }
00979
00980 friend std::ostream& operator<<(std::ostream &os, SliceRoi::SliceImpl const &c);
00981 friend std::ostream& operator<<(std::ostream& os, SliceRoi const& roi);
00982 };
00983
00984 std::ostream& operator<<(std::ostream &os, SliceRoi::SliceImpl const &c);
00985 std::ostream& operator<<(std::ostream& os, SliceRoi const& roi);
00986
00987 #endif
00988
00989 #if 0
00990
00991 struct ConvexRange { int y, x, w; };
00992
00993 class GeneralRoi: public std::list<ConvexRange>
00994 {
00995 private:
00996
00997 typedef std::vector<iterator> RoiLines;
00998
00999 private:
01000
01001 RoiLines lines;
01002
01003 public:
01004 GeneralRoi() {}
01005 public:
01006
01007 Roi(Roi const & roi)
01008 {
01009 rect = roi.rect;
01010 if (roi.convex) { convex = new ConvexRoi(); *convex = *(roi.convex); } else convex = NULL;
01011 if (roi.mask) { mask = new image::Image(); *mask = *(roi.mask); } else mask = NULL;
01012 }
01013 Roi& operator=(Roi const & roi)
01014 {
01015 rect = roi.rect;
01016 delete convex; if (roi.convex) { convex = new ConvexRoi(); *convex = *(roi.convex); } else convex = NULL;
01017 delete mask; if (roi.mask) { mask = new image::Image(); *mask = *(roi.mask); } else mask = NULL;
01018 }
01019 Roi(cv::Rect &rect): rect(rect), convex(NULL), mask(NULL) {}
01020 Roi(int x, int y, int width, int height): rect(x,y,width,height), convex(NULL), mask(NULL) {}
01021 Roi(jblas::vec2 &x, jblas::sym_mat22 &P, double factor)
01022 {
01023
01024 }
01025 Roi(int x, int y, image::Image &mask_): rect(x,y,mask_.width(),mask_.height()), convex(new ConvexRoi()), mask(new image::Image(mask_)
01026 {
01027 convex->resize(rect.height);
01028 for(int i = 0; i < rect.height; i++)
01029 {
01030 int j;
01031
01032
01033 }
01034 }
01035 ~Roi() { delete convex; delete mask; }
01036
01037 iterator begin(int i) { return lines[i]; }
01038 iterator end(int i) { return lines[i+1]; }
01039
01040
01041 int top () const { return rect.y; }
01042 int bottom() const { return rect.y+rect.height-1; }
01043 int left () const { return rect.x; }
01044 int right() const { return rect.x+rect.width-1; }
01045 int left (int i) const { return convex ? rect[i].first : left() ; }
01046 int right(int i) const { return convex ? rect[i].second : right(); }
01047 bool test(int x, int y) const
01048 {
01049 if (mask) return mask.at<uchar>(y-top(),x-left());
01050 if (convex) return y>=top() && y <= bottom() && x>=left(y-top()) && x<=right(y-top());
01051 else return y>=top() && y <= bottom() && x>=left() && x<=right();
01052
01053 }
01054 double getRatio() { return 1; }
01055
01056
01057 bool isRect() const { return convex == NULL && mask == NULL; }
01058 bool isConvex() const { return mask == NULL; }
01059
01060
01061 void scale(double factor)
01062 {
01063 rect.x=(int)(rect.x*factor);
01064 rect.y=(int)(rect.y*factor);
01065 rect.width =(int)(rect.width *factor+0.999);
01066 rect.height=(int)(rect.height*factor+0.999);
01067 }
01068 void shift(int x, int y)
01069 {
01070 rect.x += x;
01071 rect.y += y;
01072 }
01073 void add(Roi &roi)
01074 {
01075
01076 }
01077 void remove(Roi &roi)
01078 {
01079
01080 }
01081 void intersect(Roi &roi)
01082 {
01083
01084 }
01085 };
01086 #endif
01087
01088
01089 #if 0
01090
01096 class RoiAbstract {
01097
01098 public:
01099 virtual int top() const = 0;
01100 virtual int bottom() const = 0;
01101 virtual int left() const = 0;
01102 virtual int right() const = 0;
01103 virtual int left(int i) const = 0;
01104 virtual int right(int i) const = 0;
01105 virtual int width() const { return right()-left()+1; }
01106 virtual int height() const { return bottom()-top()+1; }
01110 virtual bool test(int x, int y) const = 0;
01115 virtual bool inTest(int x, int y) const = 0;
01116 virtual bool isConvex() const = 0;
01117
01118 virtual RoiAbstract* clone() = 0;
01119 virtual void scale(double factor) = 0;
01120 virtual void shift(int x, int y) = 0;
01121
01122
01123 std::ostream& operator<<(std::ostream& os)
01124 {
01125 os << "(" << left() << "," << top() << ";" << width() << "," << height() << ")";
01126 return os;
01127 }
01128 };
01129
01130
01131 class RoiRect
01132 #if !USE_TEMPLATE_INLINE
01133 : public RoiAbstract
01134 #endif
01135 {
01136 private:
01137 cv::Rect roi;
01138 public:
01139 RoiRect(cv::Rect &roi): roi(roi) {}
01140 RoiRect(int x, int y, int width, int height): roi(x,y,width,height) {}
01141 int top() const { return roi.y; }
01142 int bottom() const { return roi.y+roi.height-1; }
01143 int left() const { return roi.x; }
01144 int right() const { return roi.x+roi.width-1; }
01145 int left(int i) const { return left(); }
01146 int right(int i) const { return right(); }
01147 bool test(int x, int y) const { return y>=top() && y <= bottom() && x>=left() && x<=right(); }
01148 bool inTest(int x, int y) const { return true; }
01149 bool isConvex() const { return true; }
01150 RoiAbstract* clone() { return new RoiRect(roi); }
01151 void scale(double factor) { roi.x=(int)(roi.x*factor); roi.y=(int)(roi.y*factor); roi.width=(int)(roi.width*factor+0.999); roi.height=(int)(roi.height*factor+0.999); }
01152 void shift(int x, int y) { roi.x += x; roi.y += y; }
01153 };
01154
01155 class RoiEllipse
01156 #if !USE_TEMPLATE_INLINE
01157 : public RoiAbstract
01158 #endif
01159 {
01160 private:
01161 jblas::vec2 x;
01162 jblas::sym_mat22 P;
01163 public:
01164 RoiEllipse(jblas::vec2 &x, jblas::sym_mat22 &P) { }
01165 int top() const { return 0; }
01166 int bottom() const { return 0; }
01167 int left() const { return 0; }
01168 int right() const { return 0; }
01169 int left(int i) const { return 0; }
01170 int right(int i) const { return 0; }
01171 bool test(int x, int y) const { return 0; }
01172 bool inTest(int x, int y) const { return true; }
01173 bool isConvex() const { return true; }
01174 };
01175
01176 class RoiConvex
01177 #if !USE_TEMPLATE_INLINE
01178 : public RoiAbstract
01179 #endif
01180 {
01181 private:
01182 int top_;
01183 int bottom_;
01184 std::vector<std::pair<int,int> > roi;
01185 public:
01186 RoiConvex(int maxHeight) { }
01187 RoiConvex(jblas::vec2 &x, jblas::sym_mat22 &P) { }
01188 RoiConvex(int top, int bottom, std::vector<int>) { }
01189 void intFromEllipse(jblas::vec2 &x, jblas::sym_mat22 &P) { }
01190 int top() const { return top_; }
01191 int bottom() const { return bottom_; }
01192 int left() const { return 0; }
01193 int right() const { return 0; }
01194 int left(int i) const { return roi[i].first; }
01195 int right(int i) const { return roi[i].second; }
01196 bool test(int x, int y) const { return y>=top_ && y<=bottom_ && x>=roi[y].first && x<=roi[y].second; }
01197 bool inTest(int x, int y) const { return true; }
01198 bool isConvex() const { return true; }
01199 };
01200
01201
01202 class RoiMask
01203 #if !USE_TEMPLATE_INLINE
01204 : public RoiAbstract
01205 #endif
01206 {
01207 private:
01208 cv::Rect roi;
01209 image::Image mask;
01210 public:
01211 RoiMask(int top, int left, image::Image &mask) { }
01212 RoiMask(cv::Rect &roi, image::Image &mask) { }
01213 int top() const { return roi.y; }
01214 int bottom() const { return roi.y+roi.height-1; }
01215 int left() const { return 0; }
01216 int right() const { return 0; }
01217 int left(int i) const { return roi.x; }
01218 int right(int i) const { return roi.x+roi.width-1; }
01219 bool test(int x, int y) const { return y>=top() && y <= bottom() && x>=left(y) && y<=right(y); }
01220 bool inTest(int x, int y) const { return mask.data(y)[x]; }
01221 bool isConvex() const { return false; }
01222 };
01223
01224 #endif
01225
01227
01228
01229 class ROI;
01230 typedef boost::shared_ptr<ROI> roi_ptr_t;
01231
01232 class ROI {
01233 public:
01234 int x, y;
01235 int width, height;
01236 ROI(const int ulx = 0, const int uly = 0, const int sx = 0, const int sy = 0) {
01237 x = ulx;
01238 y = uly;
01239 width = sx;
01240 height = sy;
01241 }
01242 veci2 downright() {
01243 veci2 dr;
01244 dr(0) = x + width - 1;
01245 dr(1) = y + height - 1;
01246 return dr;
01247 }
01248 veci2 upleft() {
01249 veci2 ul;
01250 ul(0) = x;
01251 ul(1) = y;
01252 return ul;
01253 }
01254 veci2 size() {
01255 veci2 sz;
01256 sz(0) = width;
01257 sz(1) = height;
01258 return sz;
01259 }
01260 void upleft(const veci & ul){
01261 x = ul(0);
01262 y = ul(1);
01263 }
01264 void downright(const veci & dr){
01265 width = dr(0) - x + 1;
01266 height = dr(1) - y + 1;
01267 }
01268 void size(const veci & sz){
01269 width = sz(0);
01270 height = sz(1);
01271 }
01272
01273 friend std::ostream& operator <<(std::ostream & s, ROI & roi) {
01274 s << "ROI: " << std::endl;
01275 s << " .upper left = " << roi.upleft() << std::endl;
01276 s << " .lower right = " << roi.downright() << std::endl;
01277 s << " .size = " << roi.size() << std::endl;
01278 return s;
01279 }
01280
01281 };
01282
01283
01284 }
01285 }
01286
01287
01288 #endif