1 //*******************************************************************
2 // Copyright (C) 2002 ImageLinks Inc.
3 //
4 // License:  MIT
5 //
6 // See LICENSE.txt file in the top level directory for more details.
7 //
8 // Author:  David Burken
9 //
10 // Description:
11 //
12 // Class to scan pixels and flip target dn pixel value to new dn pixel value.
13 // This was written to fix partial null pixels.
14 //
15 //*************************************************************************
16 // $Id: ossimPixelFlipper.h 19728 2011-06-06 21:31:17Z dburken $
17 #ifndef ossimPixelFlipper_HEADER
18 #define ossimPixelFlipper_HEADER
19 
20 #include <ossim/imaging/ossimImageSourceFilter.h>
21 #include <ossim/base/ossimPolygon.h>
22 #include <mutex>
23 
24 /**
25  *  Class to scan pixels and flip target dn value to a replacement dn
26  *  value.
27  *
28  *  This was written to fix problems with null pixels, i.e. an image has a
29  *  digital number(dn) of 255 for null and it is desired to use a dn of 0 as
30  *  a null.  This can really be used to flip any pixel value to another.
31  *
32  *  @note This filter currently works on the input tile directly and does
33  *  not copy the data.
34  *
35  *  @see theReplacementMode data member documentation for more info.
36  */
37 class OSSIM_DLL ossimPixelFlipper : public ossimImageSourceFilter
38 {
39 public:
40    static const char PF_TARGET_VALUE_KW[];
41    static const char PF_TARGET_RANGE_KW[];
42    static const char PF_REPLACEMENT_VALUE_KW[];
43    static const char PF_REPLACEMENT_MODE_KW[];
44    static const char PF_CLAMP_VALUE_KW[];
45    static const char PF_CLAMP_VALUE_LO_KW[];
46    static const char PF_CLAMP_VALUE_HI_KW[];
47    static const char PF_CLIP_MODE_KW[];
48 
49    /**
50     * Target Replacement Mode:
51     *
52     * Examples given for 3-band pixel values as (R, G, B) with target = 0, and replacement = 1
53 
54     * If mode is REPLACE_BAND_IF_TARGET (default):
55     * Any pixel band with value of target will be replaced.
56     * (0, 0, 0) becomes (1, 1, 1)
57     * (0, 3, 2) becomes (1, 3, 2)
58     *
59     * If mode is REPLACE_BAND_IF_PARTIAL_TARGET:
60     * A band with target value will be replaced only if at least one other band in the pixel does
61     * not have the target.
62     * (0, 0, 0) remains (0, 0, 0)
63     * (0, 3, 2) becomes (1, 3, 2)
64     *
65     * If mode is REPLACE_ALL_BANDS_IF_PARTIAL_TARGET:
66     * All bands of the pixel will be replaced if any but not all bands in the pixel have the
67     * target value.
68     * (0, 0, 0) remains (0, 0, 0)
69     * (0, 3, 2) becomes (1, 1, 1)
70     *
71     * If mode is REPLACE_ONLY_FULL_TARGETS:
72     * All bands in the pixel will be replaced only if they all have the target.
73     * (0, 0, 0) becomes (1, 1, 1)
74     * (0, 3, 2) remains (0, 3, 2)
75     *
76     * If mode is REPLACE_ALL_BANDS_IF_ANY_TARGET:
77     * All bands in the pixel will be replaced if even one band has the target.
78     * (0, 0, 0) becomes (1, 1, 1)
79     * (0, 3, 2) remains (1, 1, 1)
80     */
81    enum ReplacementMode
82    {
83       REPLACE_BAND_IF_TARGET               = 0,
84       REPLACE_BAND_IF_PARTIAL_TARGET       = 1,
85       REPLACE_ALL_BANDS_IF_PARTIAL_TARGET  = 2,
86       REPLACE_ONLY_FULL_TARGETS            = 3,
87       REPLACE_ALL_BANDS_IF_ANY_TARGET      = 4,
88    };
89 
90    /**
91     * When either a lo and/or hi clamp value is set, the clamping mode will be enabled accordingly
92     * and override any target replacement defined
93     */
94    enum ClampingMode
95    {
96       DISABLED                           = 0,
97       CLAMPING_LO                        = 1,
98       CLAMPING_HI                        = 2,
99       CLAMPING_LO_AND_HI                 = 3,
100    };
101 
102    enum ClipMode
103    {
104       NONE = 0,
105       BOUNDING_RECT  = 1,
106       VALID_VERTICES = 2
107    };
108 
109    /** default constructor */
110    ossimPixelFlipper(ossimObject* owner=NULL);
111 
112 
113    /** @return "Pixel flipper" as an ossimString. */
114    virtual ossimString getShortName()const;
115 
116    /** Initializes the state of the object from theInputConnection. */
117    virtual void initialize();
118 
119    /**
120     * @param tile_rect Rectangle to fill tile with.
121     *
122     * @param resLevel Reduced resolution level to grab from.
123     *
124     * @return ossimRefPtr<ossimImageData> This is tile that was filled with
125     * tile_rect.
126     *
127     * @note Callers should check the ossimRefPtr::valid method.
128     * The internal pointer of the ossimRefPtr<ossimImageData> can be
129     * null if the tile_rect did not intersect the input connection's
130     * bounding rectangle.
131     */
132    virtual ossimRefPtr<ossimImageData> getTile(const ossimIrect& tile_rect,
133                                                ossim_uint32 resLevel=0);
134 
135    virtual bool saveState(ossimKeywordlist& kwl,
136                           const char* prefix=0)const;
137 
138    /**
139     * Method to the load (recreate) the state of an object from a keyword
140     * list.  Return true if ok or false on error.
141     */
142    virtual bool loadState(const ossimKeywordlist& kwl,
143                           const char* prefix=0);
144 
145    virtual ossimScalarType getOutputScalarType() const;
146    virtual ossim_float64 getMaxPixelValue (ossim_uint32 band = 0 ) const;
147    virtual ossim_float64 getMinPixelValue (ossim_uint32 band = 0 ) const;
148 
149    virtual std::ostream& print(std::ostream& out) const;
150 
151    /**
152     * @param target_value This is the value to flip.
153     * @note If clamping is specified, it will take precedence over any target value (or range) test
154     */
155    void setTargetValue(ossim_float64 target_value);
156 
157    /**
158     * Instead of a single value for a target, this method allows for specifying a range of values
159     * to flip to the replacement. The replacement mode is still referenced.
160     * @param  This is the value to flip.
161     * @note If clamping is specified, it will take precedence over any target range test.
162     */
163    void setTargetRange(ossim_float64 target_min, ossim_float64 target_max);
164 
165    /**
166     * @param replacement_value This is the value to flip target to.
167     * @note If clamping is specified, it will take precedence over any target replacement.
168     */
169  void setReplacementValue(ossim_float64 replacement_value);
170 
171    /**
172     * @param clamp_value If set all pixel values above this range will (or below if clamp_max_value
173     * = false) be clamped to clamp_value. Must be less than max pixel (or greater than the min
174     * pixel) value of the input and cannot be null.
175     * @note If any clamp limit is defined, it will take precedence over any target value (or range)
176     * replacement. The replacement mode is referenced when deciding whether a pixel should be
177     * clamped or left alone.
178     */
179    void setClampValue(ossim_float64 clamp_value, bool is_high_clamp_value=true);
180    void setClampValues(ossim_float64 clamp_value_lo, ossim_float64 clamp_value_hi);
181 
182    /** @see enum ReplacementMode */
183    void setReplacementMode(ossimPixelFlipper::ReplacementMode mode);
184 
185    /** Accepts a string that must match the enumerator's label (can be lower case) and sets the
186     * replacement mode accordingly. If the string is not understood, the mode remains unchanged and
187     * FALSE is returned. */
188    bool setReplacementMode(const ossimString& modeString);
189 
190    /**
191     * Clipping here refers to bounding rect or valid polygon (spacial) clipping, where all pixels
192     * outside the valid area are mapped to the replacement value.
193     */
194    void setClipMode(const ossimString& modeString);
195    void setClipMode(ClipMode mode);
196 
197    //ossim_float64 getTargetValue()      const;
198    ossim_float64 getReplacementValue() const;
199    //ossim_float64 getClampValue() const;
200    ossimPixelFlipper::ReplacementMode getReplacementMode()  const;
201    ossimString getReplacementModeString() const;
202    ossimString getClipModeString() const;
203    ClipMode getClipMode() const;
204 
205    virtual ossimRefPtr<ossimProperty> getProperty(const ossimString& name)const;
206    virtual void setProperty(ossimRefPtr<ossimProperty> property);
207    virtual void getPropertyNames(std::vector<ossimString>& propertyNames)const;
208 
209 
210 protected:
211    /** destructor */
212    virtual ~ossimPixelFlipper();
213    //! This object can be used outside of an image chain for offline processing of existing tile.
214    template <class T>
215    void flipPixels(T dummy, ossimImageData *inpuTile, ossim_uint32 resLevel);
216 
217    template <class T>
218    void clipTile(T dummy,
219                  ossimImageData *inpuTile,
220                  ossim_uint32 resLevel);
221 
222    /**
223     * Verifies pixel is in range.
224     * @return Returns true if in range else false.
225     */
226    bool inRange(ossim_float64 value) const;
227 
228    void allocateClipTileBuffer(ossimRefPtr<ossimImageData> inputImage);
229 
230    /** The value range to replace. For a single value replacement, both Lo and Hi are equal. Any
231     * pixel within this range will be remapped to the replacement value */
232    ossim_float64 theTargetValueLo;
233    ossim_float64 theTargetValueHi;
234 
235     /** When target values are defined, this is the value the pixel will assume if the pixel falls
236      *  within the target range (according to the rules for replacement mode) */
237    ossim_float64 theReplacementValue;
238    ReplacementMode theReplacementMode; //!< See documentation for ReplacementMode enum above
239 
240   /** The range of desired pixel values. Any pixels outside this range are set to the corresponding
241     * clamp value. Note that theReplacementValue is not referenced when clamping. */
242    ossim_float64 theClampValueLo;
243    ossim_float64 theClampValueHi;
244    ClampingMode  theClampingMode;
245 
246    /**
247     * Border Clip mode
248     *
249     * This will flip to nulls any pixel value outside the specified mode.
250     *
251     * Valid modes are:
252     *
253     * none
254     * bounding_rect
255     * valid_vertices
256     *
257     * if the mode is "none" then nothing is done.
258     * if the mode is "bounding_rect" then the bounding rect for the requested rlevel
259     *                is used and every pixel outside that
260     */
261    ClipMode        theClipMode;
262 
263    /** For lock and unlock. */
264    mutable std::recursive_mutex      theMutex;
265 
266    mutable std::vector<ossimPolygon> theValidVertices;
267    mutable std::vector<ossimIrect>   theBoundingRects;
268 
269    ossimRefPtr<ossimImageData> theClipTileBuffer;
270 
271    TYPE_DATA
272 };
273 
274 
275 #endif
276