1 // -*- c-basic-offset: 4 -*-
2 
3 /** @file Mask.h
4  *
5  *  @brief definitions of classes to work with mask
6  *
7  *  @author Thomas Modes
8  *
9  */
10 
11 /*  This program is free software; you can redistribute it and/or
12  *  modify it under the terms of the GNU General Public
13  *  License as published by the Free Software Foundation; either
14  *  version 2 of the License, or (at your option) any later version.
15  *
16  *  This software is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  *  General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public
22  *  License along with this software. If not, see
23  *  <http://www.gnu.org/licenses/>.
24  *
25  */
26 
27 #ifndef _PANODATA_MASK_H
28 #define _PANODATA_MASK_H
29 
30 #include <hugin_shared.h>
31 #include "hugin_utils/utils.h"
32 #include "hugin_math/hugin_math.h"
33 
34 namespace HuginBase
35 {
36 namespace PTools { class Transform; }
37 
38 /** vector, which stores coordinates of one polygon */
39 typedef std::vector<hugin_utils::FDiff2D> VectorPolygon;
40 
41 /** polygon can exceed the image maximal maskOffset pixels in each direction
42  *  bigger polygons will be clipped after loading
43  */
44 const int maskOffset=100;
45 
46 /** \brief base class, which stores one mask polygon
47  *
48  *  note: the mask handling (e.g. propagating of positive masks) happens in
49  *  HuginBase::Panorama::updateMasks which is automatic called after a
50  *  change to the panorama object by HuginBase::Panorama::changedFinished
51  */
52 class IMPEX MaskPolygon
53 {
54 public:
55     /** enumeration with type of possible masks */
56     enum MaskType
57     {
58         Mask_negative=0,
59         Mask_positive=1,
60         Mask_Stack_negative=2,
61         Mask_Stack_positive=3,
62         Mask_negative_lens=4
63     };
64     /** constructor */
MaskPolygon()65     MaskPolygon() : m_maskType(Mask_negative), m_imgNr(0), m_invert(false) {};
66     /** checks if given point is inside of the stored polygon */
67     bool isInside(const hugin_utils::FDiff2D p) const;
68     /** returns the winding number of the polygon around point p */
69     int getWindingNumber(const hugin_utils::FDiff2D p) const;
70     /** returns the total winding number of the polygon*/
71     int getTotalWindingNumber() const;
72 
73     // access functions
74     /** returns mask type */
getMaskType()75     MaskType getMaskType() const { return m_maskType; };
76     /** sets mask type */
setMaskType(const MaskType newType)77     void setMaskType(const MaskType newType) { m_maskType=newType; };
78     /** returns true, if mask type is positive */
79     bool isPositive() const;
80     /** returns vector with coordinates of the polygon */
getMaskPolygon()81     VectorPolygon getMaskPolygon() const { return m_polygon; };
82     /** set complete vector with all corrdinates of the polygon */
83     void setMaskPolygon(const VectorPolygon& newMask);
84     /** returns the associated image number, only used when loading a project, otherwise discarded */
getImgNr()85     unsigned int getImgNr() const { return m_imgNr; };
86     /** sets the associated image number, only used when loading a project, otherwise discarded */
setImgNr(const unsigned int newImgNr)87     void setImgNr(const unsigned int newImgNr) { m_imgNr=newImgNr; };
88     /** set mask to normal or inverted */
setInverted(const bool inverted)89     void setInverted(const bool inverted) { m_invert = inverted; };
90     /** returns if mask is inverted */
isInverted()91     bool isInverted() const { return m_invert; };
92 
93     // polygon modifier
94     /** adds point at the end to the polygon */
95     void addPoint(const hugin_utils::FDiff2D p);
96     /** insert point at the position index into the polygon */
97     void insertPoint(const unsigned int index, const hugin_utils::FDiff2D p);
98     /** removes point at the position index from the polygon */
99     void removePoint(const unsigned int index);
100     /** moves the point at position index to the new absolute position p */
101     void movePointTo(const unsigned int index, const hugin_utils::FDiff2D p);
102     /** relativ moves the point at position index by diff */
103     void movePointBy(const unsigned int index, const hugin_utils::FDiff2D diff);
104     /** scales all polygon coordinates by factorx for x position and factory for y position */
105     void scale(const double factorx, const double factory);
106     /** scales x and y axis equally by factor */
scale(const double factor)107     void scale(const double factor) { scale(factor,factor);} ;
108     /** transforms the polygon coordinates by the given transformation */
109     void transformPolygon(const PTools::Transform &trans);
110     /** clips the polygon to the given rectangle */
111     bool clipPolygon(const vigra::Rect2D rect);
112     /** clips the polygon to the circle with center and radius */
113     bool clipPolygon(const hugin_utils::FDiff2D center, const double radius);
114     /** rotate the polygon by 90 degrees */
115     void rotate90(bool clockwise,unsigned int maskWidth,unsigned int maskHeight);
116     /** subsamples the polygon, so that the longest distance between 2 points is max_distance */
117     void subSample(const double max_distance);
118 
119     /** search a point which lies near the polygon line and return the index for inserting the new point */
120     unsigned int FindPointNearPos(const hugin_utils::FDiff2D p, const double tol) const;
121 
122     //operators
123     /** assign operator */
124     MaskPolygon &operator=(const MaskPolygon& otherPoly);
125     /** comparision operator */
126     const bool operator==(const MaskPolygon& otherPoly) const;
127 
128     //input/output functions
129     /** parses the x and y positions from the given string */
130     bool parsePolygonString(const std::string& polygonStr);
131     /** writes the complete k line which describes the mask to the stream, using the given
132      *  newImgNr for the i parameter
133      */
134     void printPolygonLine(std::ostream & o, const unsigned int newImgNr) const;
135 
136 private:
137     /** calculates the bounding box of the polygon to speed up tests */
138     void calcBoundingBox();
139     //variables for internal storage of Mask type, polygon and assigned image number
140     MaskType m_maskType;
141     VectorPolygon m_polygon;
142     unsigned int m_imgNr;
143     bool m_invert;
144     vigra::Rect2D m_boundingBox;
145 };
146 
147 typedef std::vector<MaskPolygon> MaskPolygonVector;
148 
149 /** load the mask from stream */
150 IMPEX void LoadMaskFromStream(std::istream& stream, vigra::Size2D& imageSize, MaskPolygonVector &newMasks, size_t imgNr);
151 /** save the mask into stream */
152 IMPEX void SaveMaskToStream(std::ostream& stream, vigra::Size2D imageSize, MaskPolygon &maskToWrite, size_t imgNr);
153 
154 }; //namespace
155 
156 namespace vigra_ext
157 {
158 
159 template <class SrcImageIterator, class SrcAccessor>
applyMask(vigra::triple<SrcImageIterator,SrcImageIterator,SrcAccessor> img,HuginBase::MaskPolygonVector masks)160 void applyMask(vigra::triple<SrcImageIterator, SrcImageIterator, SrcAccessor> img, HuginBase::MaskPolygonVector masks)
161 {
162     const vigra::Diff2D imgSize = img.second - img.first;
163 
164     if(masks.empty())
165         return;
166     // loop over the image and transform
167 #pragma omp parallel for schedule(dynamic)
168     for(int y=0; y < imgSize.y; ++y)
169     {
170         // create x iterators
171         SrcImageIterator xd(img.first);
172         xd.y += y;
173         for(int x=0; x < imgSize.x; ++x, ++xd.x)
174         {
175             hugin_utils::FDiff2D newPoint(x,y);
176             bool insideMasks=false;
177             unsigned int i=0;
178             while(!insideMasks && (i<masks.size()))
179             {
180                 insideMasks=masks[i].isInside(newPoint);
181                 i++;
182             };
183             if(insideMasks)
184                 *xd=0;
185         }
186     }
187 }
188 
189 } //namespace
190 #endif // _PANODATA_MASK_H
191