Jafar
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
roi.hpp
00001 /*
00002  * roi.hpp
00003  *
00004  *     Project: jafar
00005  *  Created on: Jun 1, 2010
00006  *      Author: jsola
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 //    class RoiAbstract;
00027 //    typedef boost::shared_ptr<RoiAbstract> roi_ptr_t;
00028 /*
00029 Well well... so many solutions...
00030 Do we want a very general ROI, or is convex ROI enough ? with a convex roi some operations can fail (remove, add...)
00031 For a general ROI, do we use a mask (meaning we have to test every pixel), or a slice model ?
00032 For a slice model, do we use a vector of list, just a list, both ?
00033 Do we use std::list, or a custom list which stores its data in an array to optimize memory management ?
00034 
00035 Let's start with simple convex roi, while  thinking to a general roi
00036 
00037 
00038 
00039 
00040 */
00041 
00042     class ConvexRoi;
00043     class SliceRoi;
00044 
00045 //#define NEW_ROI
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; // bounding box
00077         ConvexRoiImpl convex; // convex area, with origin at rect.x,rect.y
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         // constructors
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         // rect interface
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         // convex interface
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         // generic interface, at slice level
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         // most generic interface, at individual pixels level, but harder to use because loses all line consistency
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         // more generic accessors
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           // TODO
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           // TODO
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           // TODO
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           // TODO
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           // first deal with the rects
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           // now with convex
00195           if (!hasConvex && !roi.hasConvex)
00196           {
00197             return ConvexRoi(newRect);
00198           } else
00199           if (hasConvex && roi.hasConvex)
00200           {
00201             // TODO
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 //JFR_DEBUG("newRect begin " << newRect);
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 //JFR_DEBUG("slice y=" << y << " " << newSlice);
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 //JFR_DEBUG("error branch: newRect " << newRect << ", shift " << shift);
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 //JFR_DEBUG("no error branch: lastY " << lastY << ", minX1 " << minX1 << ", maxX2 " << maxX2);
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 //JFR_DEBUG("newRect end " << newRect);
00261 //JFR_DEBUG("newRoi.rect end " << newRoi.rect);
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 // JFR_DEBUG("# scaleTo: oldRect " << rect << ", newRect " << newRect);
00311           cv::Point desiredOr(newRect.x, newRect.y);
00312           if (hasConvex)
00313           {
00314             // init new convex
00315             ConvexRoi newRoi(newRect);
00316             newRoi.initConvex();
00317             ConvexRoiImpl &newConvex = newRoi.convex;
00318 // JFR_DEBUG("convex.size " << newConvex.size());
00319             double fw = newRect.width / (double)rect.width;
00320             newRect.x=std::floor(rect.x*fw);
00321 // JFR_DEBUG("width fw " << fw);
00322             // first scale x
00323             for(ConvexRoiImpl::iterator it = convex.begin(); it != convex.end(); ++it)
00324             {
00325 // JFR_DEBUG_BEGIN(); JFR_DEBUG_SEND("oldSlice " << *it);
00326 /*              int x1 = std::floor((rect.x + it->x)*fw);
00327               int x2 = std::ceil((rect.x + it->x + it->w)*fw - 1);
00328               it->x = x1 - newRect.x;
00329               it->w = x2 - x1 + 1;
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 // JFR_DEBUG_SEND(", newSlice x " << *it); JFR_DEBUG_END();
00335             }
00336             // then scale y
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               // same FIXME than in ellipse constructor
00344               //double jj = (i < newRect.height/2 ? (i+1)/fh : i/fh);
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 // JFR_DEBUG("newSlice y " << *it << " by taking extrema between " << jj1 << " and " << jj2);
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; // bounding box
00482         mutable SliceRoiImpl slices; // area, with origin at rect.x,rect.y
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; // first outside at the right extremity
00516           while (slice1 || slice2)
00517           {
00518             // continuity broken, create new slice
00519             if ((!slice1 || slice1->x > right) && (!slice2 || slice2->x > right))
00520             {
00521               if (*newSlice) // if not first time
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             // merge slice1
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             // merge slice2
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         // constructors
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         // rect interface
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         // convex interface
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         // generic interface, at slice level
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) // go to next line
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         // most generic interface, at individual pixels level, but harder to use because loses all line consistency
00611 /*        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(); }
00612         bool next(Pixel &pix) const
00613         {
00614           ++pix.x;
00615           if (pix.x >= pix.x_end)
00616           {
00617             ++pix.y;
00618             if (pix.y >= y_end) return false;
00619             pix.x = x(pix.y);
00620             pix.x_end = x(pix.y)+w(pix.y);
00621           }
00622           return true;
00623         }
00624 */
00625         // more generic accessors
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           // TODO
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           // TODO
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           // first deal with the rects
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           // now with slices
00704           if (!hasSlices && !roi.hasSlices)
00705           {
00706             return SliceRoi(newRect);
00707           } else
00708           if (hasSlices && roi.hasSlices)
00709           {
00710             // TODO
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 //JFR_DEBUG("newRect begin " << newRect);
00726 
00727             //-- copy slices
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) // start before of new rect
00735                 {
00736                   if (oldSlice->x+oldSlice->w-1 >= shiftX); // ends inside or after new rect
00737                   { // copy and truncate beginning
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                   } // otherwise do nothing, throw it away it's out
00744                 }
00745                 else
00746                 {
00747                   if (oldSlice->x-shiftX < newRect.width) // start inside new rect
00748                   { // copy and truncate end
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                   } // otherwise do nothing, throw it away it's out
00755                 }
00756               }
00757             }
00758 
00759             //-- update rect
00760             int nremove;
00761             // top
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             // bottom
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             // left
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             // right
00777             maxX2 = newRect.width-1-maxX2; // this is now the space to remove at the end
00778             if (maxX2 > 0) newRect.width -= maxX2;
00779 
00780 //JFR_DEBUG("newRect end " << newRect);
00781 //JFR_DEBUG("newRoi.rect end " << newRoi.rect);
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         // FIXME apparently only works for reducing...
00829         void scaleTo(cv::Rect &newRect)
00830         {
00831 // JFR_DEBUG("# scaleTo: oldRect " << rect << ", newRect " << newRect);
00832           cv::Point desiredOr(newRect.x, newRect.y); // desired origin ; FIXME do we really need this ?
00833           if (hasSlices)
00834           {
00835             // init new slices
00836             SliceRoi newRoi(newRect);
00837             newRoi.initSlices(false);
00838             SliceRoiImpl &newSlices = newRoi.slices;
00839 // JFR_DEBUG("convex.size " << newSlices.size());
00840             double fw = newRect.width / (double)rect.width; // width factor
00841             newRect.x = std::floor(rect.x*fw);
00842 // JFR_DEBUG("width fw " << fw);
00843 
00844             // first scale x, easy
00845             for(SliceRoiImpl::iterator it = slices.begin(); it != slices.end(); ++it)
00846             {
00847               for(SliceImpl *slice = *it; slice != NULL; slice = slice->next)
00848               {
00849 // JFR_DEBUG_BEGIN(); JFR_DEBUG_SEND("oldSlice " << slice);
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 // JFR_DEBUG_SEND(", newSlice x " << slice); JFR_DEBUG_END();
00854               }
00855             }
00856 
00857             // then scale y, harder with interpolation
00858             // the idea when shrinking is to keep the widest area, so we merge the different lines
00859             int i = 0;
00860             newRoi.count_ = 0;
00861             double fh = newRect.height / (double)rect.height; // height factor
00862             newRect.y = std::floor(rect.y*fh);
00863             for(SliceRoiImpl::iterator it = newSlices.begin(); it != newSlices.end(); ++it, ++i)
00864             {
00865               // same FIXME than in ellipse constructor
00866               int jj1 = std::floor(i/fh), jj2 = std::ceil((i+1)/fh); // factor of how many lines to add in between each pair of lines
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 // JFR_DEBUG("newSlice y " << *it << " by taking extrema between " << jj1 << " and " << jj2);
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; // size +1
00998       
00999       private:
01000         
01001         RoiLines lines;
01002         
01003       public:
01004         GeneralRoi() {}
01005       public:
01006         // constructors
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           // TODO
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 //            for(j = 0; j < rect.width; j++) if (mask(
01032           // TODO
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         // accessors
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         // introspection
01057         bool isRect() const { return convex == NULL && mask == NULL; }
01058         bool isConvex() const { return mask == NULL; }
01059         
01060         // operations
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           // TODO
01076         }
01077         void remove(Roi &roi) 
01078         {
01079           // TODO
01080         }
01081         void intersect(Roi &roi) 
01082         {
01083           // TODO
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 //        virtual void remove(RoiAbstract &roi) = 0;
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) { /* TODO */ }
01165         int top() const { return 0;/* TODO */ }
01166         int bottom() const { return 0;/* TODO */ }
01167         int left() const { return 0;/* TODO */ }
01168         int right() const { return 0;/* TODO */ }
01169         int left(int i) const { return 0;/* TODO */ }
01170         int right(int i) const { return 0;/* TODO */ }
01171         bool test(int x, int y) const { return 0;/* TODO */ }
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) { /* TODO */ }
01187         RoiConvex(jblas::vec2 &x, jblas::sym_mat22 &P) { /* TODO */ }
01188         RoiConvex(int top, int bottom, std::vector<int>) { /* TODO */ }
01189         void intFromEllipse(jblas::vec2 &x, jblas::sym_mat22 &P) { /* TODO */ }
01190         int top() const { return top_; }
01191         int bottom() const { return bottom_; }
01192         int left() const { return 0;/* TODO */ }
01193         int right() const { return 0;/* TODO */ }
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) { /* TODO */ }
01212         RoiMask(cv::Rect &roi, image::Image &mask) { /* TODO */ }
01213         int top() const { return roi.y; }
01214         int bottom() const { return roi.y+roi.height-1; }
01215         int left() const { return 0;/* TODO */ }
01216         int right() const { return 0;/* TODO */ }
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 /* ROI_HPP_ */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on Wed Oct 15 2014 00:37:21 for Jafar by doxygen 1.7.6.1
LAAS-CNRS