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 <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
44namespace drain
45{
46namespace image
47{
48
49
53template <class C>
54class ImpulseBucket : public C {
55
56public:
57
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
98protected:
99
100 //ImpulseBucket(conf_t){}
101
102};
103
104
105// Important. Guarantees that bucket (parameters) have been initialized.
106
107template <class T>
109public:
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
146template <class T>
148
149public:
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
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
223protected:
224
225 int extendHorz;
226 int extendVert;
227 double weightThreshold;
228 //double undetectQuality;
229
230};
231
232
233template <class T>
235 Logger mout(getImgLog(), __FILE__, __FUNCTION__);
236
237 mout.debug("delegating to traverseChannel(src, empty, dst, empty)" );
238
240 traverseChannel(src, empty, dst, empty);
241
242}
243
244template <class T>
245void 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
262template <class T>
263void 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
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
354template <class T>
355void 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
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:312
Logger & warn(const TT &... args)
Possible error, but execution can continue.
Definition Log.h:430
Logger & debug(const TT &... args)
Debug information.
Definition Log.h:666
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:77
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
Definition Point.h:48