Loading...
Searching...
No Matches
ImpulseResponseOp.h
1/*
2
3MIT License
4
5Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25 */
26/*
27Part of Rack development has been done in the BALTRAD projects part-financed
28by the European Union (European Regional Development Fund and European
29Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30 */
31#ifndef ImpulseResponse2_H
32#define ImpulseResponse2_H
33
34#include <sstream>
35#include <ostream>
36//#include "drain/utility>
37
38#include "drain/image/ValueHandler.h"
39#include <drain/image/CoordinatePolicy.h>
40#include "drain/image/FilePng.h"
41//#include "drain/image/SegmentProber.h"
42
43#include "ImageOp.h"
44
45namespace drain
46{
47namespace image
48{
49
50
54template <class C, class H=ValueHandler>
55class ImpulseBucket : public C {
56
57public:
58
60
61 typedef C conf_t;
63
64
66 virtual inline
67 void init(const Channel & src, bool horizontal = true){};
68
70 virtual
71 void reset() = 0;
72
74 virtual
75 void addLeft(int i, double value, double weight) = 0;
76
78 virtual
79 void addRight(int i, double value, double weight) = 0;
80
82 virtual
83 void addDown(int i, double value, double weight) = 0;
84
86 virtual
87 void addUp(int i, double value, double weight) = 0;
88
89
91 virtual
92 double get(int i) = 0;
93
95
98 virtual
99 double getWeight(int i) = 0;
100
101 // Experimental
102
103 typedef H value_handler_t;
104
105 ValueHandler & getValueHandler() {
106 return valueHandler;
107 }
108
109protected:
110
111 value_handler_t valueHandler;
112
113 //ImpulseBucket(conf_t){}
114
115};
116
117
118// Important. Guarantees that bucket (parameters) have been initialized.
119/*
120 *
121 * \param T - bucket class, containing ::conf_t
122 */
123template <class T>
125public:
126
127 typedef T bucket_t;
128 typename T::conf_t conf;
129
130 inline
132
133 inline
134 ImpulseResponseOpBase(const ImpulseResponseOpBase & op) : conf(op.conf){
135 };
136
137 inline
138 //ImpulseResponseOpBase(const typename T::conf_t & conf) : conf(conf){
139 ImpulseResponseOpBase(const bucket_t & conf) : conf(conf){
140 //std::cerr << "decay now:" << conf.decay << '\n';
141 };
142
143
144 virtual inline
146
147 virtual
148 const std::string & getName() const {
149 return this->conf.getName();
150 };
151
152 virtual
153 const std::string & getDescription() const {
154 return this->conf.getDescription();
155 };
156
157 // instead, consider conf object of type T::conf_t
158
159};
160
161
163
170template <class T>
172
173public:
174
175 typedef T bucket_t;
176 typedef typename T::conf_t conf_t;
177
178
179 inline
181 init();
182 };
183
184 inline
186 init();
187 };
188
189 inline
190 ImpulseResponseOp(const typename T::conf_t & conf) : ImpulseResponseOpBase<T>(conf) {
191 init();
192 };
193
194 inline
195 void init(){
196 this->parameters.append(this->conf.getParameters());
197 this->parameters.link("extendHorz", extendHorz, "pix"); // for avoiding border effects, include pixels beyond main area
198 this->parameters.link("extendVert", extendVert, "pix"); // for avoiding border effects, include pixels beyond main area
199 this->parameters.link("weightThreshold", weightThreshold, "[0..1.0]"); //
200
201 };
202
203 inline
205
206
207 /*
208 virtual inline
209 void make Compatible(const ImageFrame &src, Image &dst) const {
210
211 drain::Logger mout(getImgLog(), __FILE__, __FUNCTION__);
212 //mout.debug3("src: " , src );
213
214 if (dst.getType() != src.getType()){
215 mout.note(" changing dst image type: " , dst.getType().name() , '>' , src.getType().name() );
216 }
217
218 dst.copyShallow(src);
219 mout.warn(dst );
220 // mout .debug3() << "dst: " << dst << mout.endl;
221
222 };
223 */
224
225 //virtual void makeCompatible(const ImageFrame & src,Image & dst) const;
226 virtual
227 void traverseChannels(const ImageTray<const Channel> & src, ImageTray<Channel> & dst) const {
228 this->traverseChannelsSeparately(src, dst);
229 }
230
231 virtual
232 void traverseChannel(const Channel & src, Channel & dst) const;
233
234 // weighted
235 virtual
236 void traverseChannel(const Channel & src, const Channel & srcWeight, Channel & dst, Channel & dstWeight) const;
237
238 virtual
239 void traverseChannelHorz(const Channel & src, const Channel & srcWeight, Channel & dst, Channel & dstWeight) const;
240
241 virtual
242 void traverseChannelVert(const Channel & src, const Channel & srcWeight, Channel & dst, Channel & dstWeight) const;
243
244 inline
245 void setExtensions(int horz, int vert){
246 extendHorz = horz;
247 extendVert = vert;
248 }
249
250protected:
251
252 int extendHorz = 0;
253 int extendVert = 0;
254 double weightThreshold = 0.1;
255 //double undetectQuality;
256
257};
258
259
260template <class T>
262 Logger mout(getImgLog(), __FILE__, __FUNCTION__);
263
264 mout.debug("delegating to traverseChannel(src, empty, dst, empty)" );
265
267 traverseChannel(src, empty, dst, empty);
268
269}
270
271template <class T>
272void ImpulseResponseOp<T>::traverseChannel(const Channel & src, const Channel & srcWeight, Channel & dst, Channel & dstWeight) const {
273
274 Logger mout(getImgLog(), __FILE__, __FUNCTION__);
275
276 dst.setScaling(src.getScaling());
277 // OLD dstWeight.setScaling(srcWeight.getScaling());
278 // NEW
279 dstWeight.setPhysicalRange({0.0, 1.0}, true);
280
281 mout.warn(dst.getProperties() );
282
283 traverseChannelHorz(src, srcWeight, dst, dstWeight);
284 traverseChannelVert(dst, dstWeight, dst, dstWeight);
285 // DEBUG traverseChannelVert(src, srcWeight, dst, dstWeight);
286
287}
288
289
290template <class T>
291void ImpulseResponseOp<T>::traverseChannelHorz(const Channel & src, const Channel & srcWeight, Channel & dst, Channel & dstWeight) const {
292
293 Logger mout(getImgLog(), __FILE__, __FUNCTION__);
294
295 mout.debug(*this );
296
297 const bool WEIGHTED = !(srcWeight.isEmpty() || dstWeight.isEmpty());
298 mout.attention(DRAIN_LOG(WEIGHTED));
299
300 const int width = src.getWidth();
301 const int widthExt = src.getWidth()+extendHorz;
302 const int height = src.getHeight();
303 const double defaultWeight = 1.0; //srcWeight.getMax<double>();
304
305
306 const CoordinateHandler2D coordHandler(src.getGeometry().area, src.getCoordinatePolicy());
308
309 T bucketOrig(this->conf); // instance
310 ImpulseBucket<typename T::conf_t> & bucket = bucketOrig;
311 bucket.init(src, true);
312
313 const ValueHandler & valueHandler = bucket.getValueHandler();
314
315 // mout.attention(DRAIN_LOG(weightThreshold));
316
317 double value;
318 double weight;
319
320 for (int j=0; j<height; ++j){
321
322 bucket.reset();
323
324 if (WEIGHTED){
325
326 for (int i=-extendHorz; i<widthExt; ++i){
327
328 point.setLocation(i, j);
329 if (coordHandler.validate(point)){
330 value = src.get<double>(point); // src.getScaled(point);
331 if (valueHandler.validate(value)){
332 weight = srcWeight.get<double>(point);
333 bucket.addLeft(point.x, value, weight);
334 }
335 }
336
337 point.setLocation(width-1-i, j);
338 if (coordHandler.validate(point)){
339 value = src.get<double>(point); // src.getScaled(point);
340 if (valueHandler.validate(value)){
341 weight = srcWeight.get<double>(point);
342 bucket.addRight(point.x, value, weight);
343 }
344 }
345
346 }
347
348 // Write
349 for (int i=0; i<width; ++i){
350 weight = bucket.getWeight(i);
351 if (weight > weightThreshold){
352 dst.put(i,j, bucket.get(i)); // dst.putScaled(i,j, bucket.get(i));
353 dstWeight.put(i,j, bucket.getWeight(i));
354 }
355 else {
356 dstWeight.put(i,j, 0); // TODO zero code
357 }
358 }
359
360 }
361 else {
362
363 // Collect
364 for (int i=-extendHorz; i<widthExt; ++i){
365
366 point.setLocation(i, j);
367 if (coordHandler.validate(point)){
368 value = src.get<double>(point);
369 if (valueHandler.validate(value)){
370 bucket.addLeft(point.x, value, defaultWeight);
371 }
372 }
373
374 point.setLocation(width-1-i, j);
375 if (coordHandler.validate(point)){
376 value = src.get<double>(point);
377 if (valueHandler.validate(value)){
378 bucket.addRight(point.x, value, defaultWeight);
379 }
380 }
381
382 }
383
384 // Write
385 for (int i=0; i<width; ++i){
386 dst.put(i,j, bucket.get(i));
387 // dst.putScaled(i,j, bucket.get(i));
388 }
389
390 }
391
392 }
393}
394
395template <class T>
396void ImpulseResponseOp<T>::traverseChannelVert(const Channel & src, const Channel & srcWeight, Channel & dst, Channel & dstWeight) const {
397
398 Logger mout(getImgLog(), __FILE__, __FUNCTION__);
399
400 mout.debug(*this );
401
402 const bool WEIGHTED = !(srcWeight.isEmpty() || dstWeight.isEmpty());
403
404 mout.attention(DRAIN_LOG(WEIGHTED));
405
406 const int width = src.getWidth();
407 const int height = src.getHeight();
408 const int heightExt = src.getHeight() + extendVert;
409 const double defaultWeight = 1.0; //srcWeight.getMax<double>();
410
411 const drain::image::CoordinateHandler2D coordHandler(src.getGeometry(), src.getCoordinatePolicy());
413
414 T bucketOrig(this->conf);
415 ImpulseBucket<typename T::conf_t> & bucket = bucketOrig;
416 bucket.init(src, false);
417
418 const ValueHandler & valueHandler = bucket.getValueHandler();
419
420 // NOTE: raw data values, but scaled weight values.
421
422 double value;
423 double weight;
424
425 for (int i=0; i<width; i++){
426
427 bucket.reset();
428
429 if (WEIGHTED) {
430
431 for (int j=-extendVert; j<heightExt; ++j){
432
433 point.setLocation(i, j);
434 if (coordHandler.validate(point)){
435 value = src.get<double>(point); // src.getScaled(point);
436 if (valueHandler.validate(value)){
437 weight = srcWeight.get<double>(point); // srcWeight.getScaled(point);
438 bucket.addDown(point.y, value, weight);
439 }
440 }
441
442 point.setLocation(i, height-1-j);
443 if (coordHandler.validate(point)){
444 value = src.get<double>(point); // src.getScaled(point);
445 if (valueHandler.validate(value)){
446 weight = srcWeight.get<double>(point); // srcWeight.getScaled(point);
447 bucket.addUp(point.y, value, weight);
448 }
449 }
450
451 }
452
453 // Write
454 for (int j=0; j<height; ++j){
455 weight = bucket.getWeight(j);
456 if (weight > weightThreshold){ // check which are scaled?
457 dst.put(i,j, bucket.get(j));
458 dstWeight.put(i,j, weight);
459 }
460 else {
461 dstWeight.put(i,j, 0); // TODO code
462 }
463 }
464
465 }
466 else { // (UNWEIGHTED)
467
468 // Collect
469 for (int j=-extendVert; j<heightExt; ++j){
470
471 point.setLocation(i, j);
472 if (coordHandler.validate(point)){
473 value = src.get<double>(point);
474 if (valueHandler.validate(value)){
475 weight = srcWeight.get<double>(point); // srcWeight.getScaled(point);
476 bucket.addLeft(point.y, value, defaultWeight);
477 }
478 }
479
480 point.setLocation(i, height-1-j);
481 if (coordHandler.validate(point)){
482 value = src.get<double>(point);
483 if (valueHandler.validate(value)){
484 bucket.addRight(point.y, value, defaultWeight);
485 }
486 }
487
488 }
489
490 // Write
491 for (int j=0; j<height; ++j){
492 dst.putScaled(i,j, bucket.get(j)); // CHECK scaled
493 }
494
495 }
496
497 }
498}
499
500
501
502} // image::
503
504} // drain::
505
506
507#endif /* ImpulseResponse_H_ */
map_t parameters
Parameters (name -> linked variable), typically linked to member variables of the derived class.
Definition BeanLike.h:313
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition Log.h:326
Logger & warn(const TT &... args)
Possible error, but execution can continue.
Definition Log.h:440
Logger & debug(const TT &... args)
Debug information.
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:333
Image with static geometry.
Definition ImageChannel.h:58
Definition CoordinateHandler.h:74
void put(size_t i, T x)
Sets the intensity in location i to x.
Definition ImageFrame.h:191
T get(size_t i) const
Gets the intensity at location i. See address().
Definition ImageFrame.h:263
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:105
const CoordinatePolicy & getCoordinatePolicy() const
Coord policy.
Definition ImageLike.h:179
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:266
Class for multi-channel digital images. Supports dynamic typing with base types (char,...
Definition Image.h:183
Definition ImpulseResponseOp.h:55
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:67
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:124
virtual const std::string & getName() const
Return the name of an instance.
Definition ImpulseResponseOp.h:148
virtual const std::string & getDescription() const
Return a brief description.
Definition ImpulseResponseOp.h:153
A fill operation for one color.
Definition ImpulseResponseOp.h:171
virtual void traverseChannel(const Channel &src, Channel &dst) const
Apply to single channel.
Definition ImpulseResponseOp.h:261
Definition ValueHandler.h:59
Definition Data.h:1473
Definition Point.h:48