ImpulseResponseOp.h
1 /*
2 
3 MIT License
4 
5 Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6 
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 SOFTWARE.
24 
25  */
26 /*
27 Part of Rack development has been done in the BALTRAD projects part-financed
28 by the European Union (European Regional Development Fund and European
29 Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30  */
31 #ifndef ImpulseResponse2_H
32 #define ImpulseResponse2_H
33 
34 #include <drain/image/CoordinatePolicy.h>
35 #include <sstream>
36 #include <ostream>
37 //#include "drain/utility>
38 
39 #include "drain/image/FilePng.h"
40 //#include "drain/image/SegmentProber.h"
41 
42 #include "ImageOp.h"
43 
44 namespace drain
45 {
46 namespace image
47 {
48 
49 
53 template <class C>
54 class ImpulseBucket : public C {
55 
56 public:
57 
58  ~ImpulseBucket(){}
59 
60  typedef C conf_t;
61 
63  virtual inline
64  void init(const Channel & src, bool horizontal = true){};
65 
67  virtual
68  void reset() = 0;
69 
71  virtual
72  void addLeft(int i, double value, double weight) = 0;
73 
75  virtual
76  void addRight(int i, double value, double weight) = 0;
77 
79  virtual
80  void addDown(int i, double value, double weight) = 0;
81 
83  virtual
84  void addUp(int i, double value, double weight) = 0;
85 
86 
88  virtual
89  double get(int i) = 0;
90 
92 
95  virtual
96  double getWeight(int i) = 0;
97 
98 protected:
99 
100  //ImpulseBucket(conf_t){}
101 
102 };
103 
104 
105 // Important. Guarantees that bucket (parameters) have been initialized.
106 
107 template <class T>
109 public:
110 
111  inline
113 
114  inline
115  ImpulseResponseOpBase(const typename T::conf_t & conf) : conf(conf){
116  //std::cerr << "decay now:" << conf.decay << '\n';
117  };
118 
119  virtual inline
121 
122  virtual
123  const std::string & getName() const {
124  return this->conf.getName();
125  };
126 
127  virtual
128  const std::string & getDescription() const {
129  return this->conf.getDescription();
130  };
131 
132  // instead, consider conf object of type T::conf_t
133  typename T::conf_t conf;
134 
135 };
136 
137 
139 
146 template <class T>
148 
149 public:
150 
151 
152  inline
154  init();
155  };
156 
157  inline
159  init();
160  };
161 
162  inline
163  ImpulseResponseOp(const typename T::conf_t & conf) : ImpulseResponseOpBase<T>(conf) {
164  init();
165  };
166 
167  inline
168  void init(){
169  this->parameters.append(this->conf.getParameters());
170  this->parameters.link("extendHorz", extendHorz = 0, "pix"); // for avoiding border effects, include pixels beyond main area
171  this->parameters.link("extendVert", extendVert = 0, "pix"); // for avoiding border effects, include pixels beyond main area
172  this->parameters.link("weightThreshold", weightThreshold = 0.05, "[0..1.0]"); //
173 
174  };
175 
176  inline
177  ~ImpulseResponseOp(){};
178 
179 
180  /*
181  virtual inline
182  void make Compatible(const ImageFrame &src, Image &dst) const {
183 
184  drain::Logger mout(getImgLog(), __FILE__, __FUNCTION__);
185  //mout.debug3("src: " , src );
186 
187  if (dst.getType() != src.getType()){
188  mout.note(" changing dst image type: " , dst.getType().name() , '>' , src.getType().name() );
189  }
190 
191  dst.copyShallow(src);
192  mout.warn(dst );
193  // mout .debug3() << "dst: " << dst << mout.endl;
194 
195  };
196  */
197 
198  //virtual void makeCompatible(const ImageFrame & src,Image & dst) const;
199  virtual
200  void traverseChannels(const ImageTray<const Channel> & src, ImageTray<Channel> & dst) const {
201  this->traverseChannelsSeparately(src, dst);
202  }
203 
204  virtual
205  void traverseChannel(const Channel & src, Channel & dst) const;
206 
207  // weighted
208  virtual
209  void traverseChannel(const Channel & src, const Channel & srcWeight, Channel & dst, Channel & dstWeight) const;
210 
211  virtual
212  void traverseChannelHorz(const Channel & src, const Channel & srcWeight, Channel & dst, Channel & dstWeight) const;
213 
214  virtual
215  void traverseChannelVert(const Channel & src, const Channel & srcWeight, Channel & dst, Channel & dstWeight) const;
216 
217  inline
218  void setExtensions(int horz, int vert){
219  extendHorz = horz;
220  extendVert = vert;
221  }
222 
223 protected:
224 
225  int extendHorz;
226  int extendVert;
227  double weightThreshold;
228  //double undetectQuality;
229 
230 };
231 
232 
233 template <class T>
234 void ImpulseResponseOp<T>::traverseChannel(const Channel & src, Channel & dst) const {
235  Logger mout(getImgLog(), __FILE__, __FUNCTION__);
236 
237  mout.debug("delegating to traverseChannel(src, empty, dst, empty)" );
238 
239  drain::image::Image empty;
240  traverseChannel(src, empty, dst, empty);
241 
242 }
243 
244 template <class T>
245 void ImpulseResponseOp<T>::traverseChannel(const Channel & src, const Channel & srcWeight, Channel & dst, Channel & dstWeight) const {
246 
247  Logger mout(getImgLog(), __FILE__, __FUNCTION__);
248 
249  dst.setScaling(src.getScaling());
250  // OLD dstWeight.setScaling(srcWeight.getScaling());
251  // NEW
252  dstWeight.setPhysicalRange({0.0, 1.0}, true);
253 
254  mout.warn(dst.getProperties() );
255 
256  traverseChannelHorz(src, srcWeight, dst, dstWeight);
257  traverseChannelVert(dst, dstWeight, dst, dstWeight);
258 
259 }
260 
261 
262 template <class T>
263 void ImpulseResponseOp<T>::traverseChannelHorz(const Channel & src, const Channel & srcWeight, Channel & dst, Channel & dstWeight) const {
264 
265  Logger mout(getImgLog(), __FILE__, __FUNCTION__);
266 
267  mout.debug(*this );
268 
269  const bool UNWEIGHTED = (srcWeight.isEmpty() || dstWeight.isEmpty());
270 
271  const int width = src.getWidth();
272  const int widthExt = src.getWidth()+extendHorz;
273  const int height = src.getHeight();
274  const double defaultWeight = 1.0; //srcWeight.getMax<double>();
275 
276  //const double weightThreshold = 0.1;
277  double w;
278 
279  const drain::image::CoordinateHandler2D coordHandler(src.getGeometry().area, src.getCoordinatePolicy());
280 
281  drain::Point2D<int> point;
282 
283  T bucket(this->conf);
284  bucket.init(src, true);
285 
286  // NOTE: raw data values, but scaled weight values.
287 
288  for (int j=0; j<height; ++j){
289 
290  bucket.reset();
291 
292  if (UNWEIGHTED){
293 
294  // Collect
295  for (int i=-extendHorz; i<widthExt; ++i){
296 
297  point.setLocation(i, j);
298  coordHandler.handle(point);
299  //if (coordHandler.validate(point)){
300  bucket.addLeft(point.x, src.get<double>(point.x, point.y), defaultWeight);
301  //}
302 
303  point.setLocation(width-1-i, j);
304  coordHandler.handle(point);
305  // if (coordHandler.validate(point)){
306  bucket.addRight(point.x, src.get<double>(point.x, point.y), defaultWeight);
307  //}
308 
309  }
310 
311  // Write
312  for (int i=0; i<width; ++i){
313  dst.putScaled(i,j, bucket.get(i));
314  }
315 
316  }
317  else {
318 
319  // Collect
320  for (int i=-extendHorz; i<widthExt; ++i){
321 
322  point.setLocation(i, j);
323  coordHandler.handle(point);
324  //if (coordHandler.validate(point)){
325  bucket.addLeft(point.x, src.get<double>(point.x, point.y), srcWeight.getScaled(point.x, point.y));
326  //}
327 
328  point.setLocation(width-1-i, j);
329  coordHandler.handle(point);
330  // if (coordHandler.validate(point)){
331  bucket.addRight(point.x, src.get<double>(point.x, point.y), srcWeight.getScaled(point.x, point.y));
332  // }
333 
334  }
335 
336  // Write
337  for (int i=0; i<width; ++i){
338  w = bucket.getWeight(i);
339  if (w > weightThreshold){
340  dst.putScaled(i,j, bucket.get(i));
341  dstWeight.putScaled(i,j, w);
342  }
343  else
344  dstWeight.putScaled(i,j, 0);
345  //dst.putScaled(i,j, bucket.get(i));
346  //dstWeight.putScaled(i,j, bucket.getWeight(i));
347  }
348 
349  }
350 
351  }
352 }
353 
354 template <class T>
355 void ImpulseResponseOp<T>::traverseChannelVert(const Channel & src, const Channel & srcWeight, Channel & dst, Channel & dstWeight) const {
356 
357  Logger mout(getImgLog(), __FILE__, __FUNCTION__);
358 
359  mout.debug(*this );
360 
361  const bool UNWEIGHTED = (srcWeight.isEmpty() || dstWeight.isEmpty());
362 
363  const int width = src.getWidth();
364  const int height = src.getHeight();
365  const int heightExt = src.getHeight() + extendVert;
366  const double defaultWeight = 1.0; //srcWeight.getMax<double>();
367  //const double weightThreshold = 0.1;
368  double w;
369 
370  const drain::image::CoordinateHandler2D coordHandler(src.getGeometry(), src.getCoordinatePolicy());
371 
372  drain::Point2D<int> point;
373 
374  T bucket(this->conf);
375  bucket.init(src, false);
376 
377  // NOTE: raw data values, but scaled weight values.
378 
379  for (int i=0; i<width; i++){
380 
381  bucket.reset();
382 
383  if (UNWEIGHTED){
384 
385  // Collect
386  for (int j=-extendVert; j<heightExt; ++j){
387 
388  point.setLocation(i, j);
389  coordHandler.handle(point); //if (coordHandler.validate(point)){
390  bucket.addLeft(point.y, src.get<double>(point.x, point.y), defaultWeight);
391 
392  point.setLocation(i, height-1-j);
393  coordHandler.handle(point); //if (coordHandler.validate(point))
394  bucket.addRight(point.y, src.get<double>(point.x, point.y), defaultWeight);
395 
396  }
397 
398  // Write
399  for (int j=0; j<height; ++j){
400  dst.putScaled(i,j, bucket.get(j));
401  }
402 
403  }
404  else {
405 
406  // Collect
407  for (int j=-extendVert; j<heightExt; ++j){
408 
409  point.setLocation(i, j);
410  coordHandler.handle(point); //if (coordHandler.validate(point)){
411  bucket.addLeft(point.y, src.get<double>(point.x, point.y), srcWeight.getScaled(point.x, point.y));
412 
413  point.setLocation(i, height-1-j);
414  coordHandler.handle(point); // if (coordHandler.validate(point)){
415  bucket.addRight(point.y, src.get<double>(point.x, point.y), srcWeight.getScaled(point.x, point.y));
416 
417  }
418 
419  // Write
420  for (int j=0; j<height; ++j){
421  w = bucket.getWeight(j);
422  if (w > weightThreshold){
423  dst.putScaled(i,j, bucket.get(j));
424  dstWeight.putScaled(i,j, w);
425  }
426  else
427  dstWeight.putScaled(i,j, 0);
428  }
429 
430  }
431 
432 
433  }
434 }
435 
436 
437 
438 
439 
440 
441 
442 } // image::
443 
444 } // drain::
445 
446 
447 #endif /* ImpulseResponse_H_ */
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition: Log.h:308
Logger & warn(const TT &... args)
Possible error, but execution can continue.
Definition: Log.h:426
Logger & debug(const TT &... args)
Public, yet typically used "internally", when TIMING=true.
Definition: Log.h:676
void append(ReferenceMap &rMap, bool replace=true)
Adopts the references of r. If replace==false, only new entries are appended.
Definition: ReferenceMap.h:320
Image with static geometry.
Definition: ImageChannel.h:60
Definition: CoordinateHandler.h:62
double getScaled(size_t i, size_t j) const
Get intensity in original physical scale.
Definition: ImageFrame.h:287
T get(size_t i) const
Gets the intensity at location i. See address().
Definition: ImageFrame.h:254
void putScaled(size_t i, size_t j, double x)
Put intensity using original physical value.
Definition: ImageFrame.h:241
void setPhysicalRange(const Range< double > &range, bool rescale=false)
Sets the supported range for physical values and optionally adjusts the scaling for maximal resolutio...
Definition: ImageFrame.h:106
const CoordinatePolicy & getCoordinatePolicy() const
Coord policy.
Definition: ImageLike.h:167
Base class for image processing functions.
Definition: ImageOp.h:49
void traverseChannelsSeparately(const ImageTray< const Channel > &src, ImageTray< Channel > &dst) const
Process each (src,dst) channel pair independently. Raise error if their counts differ.
Definition: ImageOp.cpp:340
Container applicable for Channels and Images, with alpha support.
Definition: ImageTray.h:267
Class for multi-channel digital images. Supports dynamic typing with base types (char,...
Definition: Image.h:184
Definition: ImpulseResponseOp.h:54
virtual double get(int i)=0
Return natural (not encoded) value at position i.
virtual void addRight(int i, double value, double weight)=0
When traversing down or right, add a encoded value to bucket in position i.
virtual void reset()=0
Clear statistics before traversing each row or column.
virtual double getWeight(int i)=0
Return weight at position i.
virtual void addLeft(int i, double value, double weight)=0
When traversing up or left, add a encoded value to bucket in position i.
virtual void addDown(int i, double value, double weight)=0
When traversing down or right, add a encoded value to bucket in position i.
virtual void init(const Channel &src, bool horizontal=true)
Adapt to input geometry, type, and scaling.
Definition: ImpulseResponseOp.h:64
virtual void addUp(int i, double value, double weight)=0
When traversing up or left, add a encoded value to bucket in position i.
Definition: ImpulseResponseOp.h:108
virtual const std::string & getName() const
Return the name of an instance.
Definition: ImpulseResponseOp.h:123
virtual const std::string & getDescription() const
Return a brief description.
Definition: ImpulseResponseOp.h:128
A fill operation for one color.
Definition: ImpulseResponseOp.h:147
virtual void traverseChannel(const Channel &src, Channel &dst) const
Apply to single channel.
Definition: ImpulseResponseOp.h:234
Definition: DataSelector.cpp:1277