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