PixelVectorOp.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 PixelVectorOP_H_
32 #define PixelVectorOP_H_
33 
34 #include <cmath>
35 
36 #include "ImageOp.h"
37 //#include "drain/util/Functor.h"
38 //#include "drain/util/Fuzzy.h"
39 //#include "drain/util/Registry.h"
40 #include "drain/util/FunctorBank.h"
41 
42 #include "drain/util/FunctorPack.h"
43 
44 namespace drain
45 {
46 
47 namespace image
48 {
49 
50 
51 
53 
61 class PixelVectorOp : public ImageOp
62 {
63 public:
64 
65  virtual
66  void getDstConf(const ImageConf &srcConf, ImageConf & dstConf) const;
67  //void makeCompatible(const ImageFrame &src, Image &dst) const;
68 
69  std::string functorDef;
70  // std::string functorParams;
71 
72 protected:
73 
74  PixelVectorOp(const std::string & name, const std::string & description) :
75  ImageOp(name, description + " Post-scaling with desired functor."), rescale(0.0), POW(1.0), INVPOW(1.0) { //, l(1){ , rescale(0.0),
76  // parameters.separator = ':';
77  parameters.link("functor", this->functorDef);
78  // parameters.link("params", this->functorParams);
79  };
80 
81  double rescale;
82  double POW;
83  double INVPOW;
84 
85 };
86 
87 
88 
89 class GrayOp : public PixelVectorOp
90 {
91 
92 public:
93 
94  std::string coefficients;
95  bool normalize;
96 
97  // static char coeffSeparator = ':';
98 
99  GrayOp() : PixelVectorOp(__FUNCTION__, "Convert multi-channel image to single."){
100  parameters.clear();
101  parameters.link("coeff", coefficients="1.0", "c[:c2:c3:...]");
102  parameters.link("normalize", normalize=true, "true|false");
103  //parameters.separator = 0;
104  };
105 
106  virtual
107  void traverseChannels(const ImageTray<const Channel> & src, ImageTray<Channel> & dst) const;
108 
109 
110 
112  virtual inline
113  void traverseChannel(const Channel & src, Channel &dst) const {
114  drain::Logger mout(getImgLog(), __FILE__, __FUNCTION__);
115  mout.warn("already a single-channel image?");
116  dst.copyData(src);
117  //throw std::runtime_error(name+"(ImageOp)::"+__FUNCTION__+"(src,dst) unimplemented.");
118  };
119 
120 
121 };
122 
123 
124 
125 template <class F>
127 {
128 
129 public:
130 
131  BinaryPixelVectorOp(const std::string & name, const std::string & description) : PixelVectorOp(name, description){
132  };
133 
134  virtual
135  inline
136  void process(const ImageFrame &src, Image &dst) const {
137  Logger mout(getImgLog(), __FILE__, __FUNCTION__); //REPL getImgLog(), name+"(PixelVectorOp)", __FUNCTION__);
138  mout.debug("delegating: process(src, dst, dst)" );
139  process(src, dst, dst);
140  };
141 
142  //double getValue(double src) const {return 0.0;};
143 
144  virtual
145  inline
146  void process(const ImageFrame &src1, const ImageFrame &src2, Image &dst) const {
147 
148  Logger mout(getImgLog(), __FILE__, __FUNCTION__); //REPL getImgLog(), name+"(PixelVectorOp)", __FUNCTION__);
149 
150  mout.debug("imitating: " );
151  //process2WithTemp(src, dst);
152 
153  if (src2.hasOverlap(dst)){
154  Image tmp;
155  tmp.copyDeep(src2);
156  makeCompatible(src1.getConf(), dst);
157  traverseFrame(src1, tmp, dst);
158  /*
159  const ImageTray<const Channel> srcTray1(src1);
160  const ImageTray<const Channel> srcTray2(tmp);
161  ImageTray<Channel> dstTray(dst);
162  traverseChannels(srcTray1, srcTray2, dstTray);
163  */
164  }
165  else {
166  makeCompatible(src1.getConf(), dst);
167  /*
168  const ImageTray<const Channel> srcTray1(src1);
169  const ImageTray<const Channel> srcTray2(src2);
170  ImageTray<Channel> dstTray(dst);
171  traverseChannels(srcTray1, srcTray2, dstTray); */
172  traverseFrame(src1, src2, dst); // lower
173  }
174  };
175 
176  virtual
177  void traverseChannels(const ImageTray<const Channel> & srcTray, ImageTray<Channel> & dstTray) const {
178  Logger mout(getImgLog(), __FILE__, __FUNCTION__);
179  mout.unimplemented("traverseChannels for one srcTray only " );
180  }
181 
182  virtual
183  void traverseChannels(const ImageTray<const Channel> & src, const ImageTray<const Channel> & src2,
184  ImageTray<Channel> & dst) const;
185 
186  void traverseFrame(const ImageFrame &src1, const ImageFrame &src2, ImageFrame &dst) const {
187 
188  Logger mout(getImgLog(), __FILE__, __FUNCTION__); //REPL getImgLog(), name+"(PixelVectorOp)", __FUNCTION__);
189  mout.debug("delegate to: traverseChannels(src, dst, dst)" );
190 
191  ImageTray<const Channel> src1Channels;
192  src1Channels.setChannels(src1);
193 
194  ImageTray<const Channel> src2Channels;
195  src2Channels.setChannels(src2);
196 
197  ImageTray<Channel> dstChannels;
198  dstChannels.setChannels(dst);
199 
200  traverseChannels(src1Channels, src2Channels, dstChannels);
201  }
202 
203  /*
204  inline
205  double getValue(double src, double src2) const {
206  const BinaryFunctor & f = functor;
207  return f(src, src2);
208  }
209  */
210 protected:
211 
212  F binaryFunctor;
213 
214 };
215 
216 template <class F>
217 void BinaryPixelVectorOp<F>::traverseChannels(const ImageTray<const Channel> & src1, const ImageTray<const Channel> & src2,
218  ImageTray<Channel> & dst) const {
219 
220 
221  Logger mout(getImgLog(), __FILE__, __FUNCTION__); //REPL getImgLog(), name+"(PixelVectorOp)", __FUNCTION__);
222 
223  if (src1.empty())
224  mout.error("src1 empty" );
225 
226  if (src2.empty())
227  mout.error("src2 empty" );
228 
229  if (dst.empty())
230  mout.error("dst empty" );
231 
232  Channel & dstChannel = dst.get();
233 
234  if (src1.getGeometry() != src2.getGeometry()){
235  mout.warn("src1" , src1.getGeometry() );
236  mout.warn("src2" , src2.getGeometry() );
237  mout.note("dstChannel" , dstChannel );
238  mout.error("src1 and src2 geometry error" );
239  return;
240  }
241 
242  const int width = src1.getGeometry().getWidth(); //std::min(src1.getWidth(),src2.getWidth());
243  const int height = src1.getGeometry().getHeight(); //std::min(src1.getHeight(),src2.getHeight());
244  const size_t channels = src1.size(); // std::min(src1.getChannelCount(),src2.getChannelCount());
245 
246  double x=0.0, sum=0.0;
247 
248  mout.debug3(*this );
249  //mout.debug3("src1: " , src1 );
250  //mout.debug3("src2: " , src2 );
251  //mout.debug3("dst: " , dst );
252 
253  FunctorBank & functorBank = getFunctorBank();
254 
255  std::string functorName;
256  std::string functorParams;
257 
258  drain::StringTools::split2(functorDef, functorName, functorParams, "/");
259 
260 
261  if (!functorBank.has(functorName)){
262  //functorBank.help(std::cerr);
263  mout.note(functorBank );
264  mout.error("functor '" , functorName , "' not found: " , functorDef );
265  return;
266  }
267 
268  UnaryFunctor & scalingFunctor = functorBank.clone(functorName); // consider get? Or static from clone()
269 
270  //mout.debug(scalingFunctor.getName() , ':' , scalingFunctor.getDescription() );
271  //scalingFunctor.setScale(dstChannel.scaling.getMax<double>(), 0.0);
272  const std::type_info & t = dstChannel.getType();
273  if (Type::call<drain::typeIsSmallInt>(t)){
274  const double m = Type::call<typeMax, double>(t);
275  scalingFunctor.setScale(m, 0.0); // TODO consider invScale, invOffset?
276  mout.info("small int type, scaling with its maximum (" , m , ')' );
277  }
278 
279  //scalingFunctor.setParameters(functorParams);
280  try {
281  scalingFunctor.setParameters(functorParams, '=', '/');
282  } catch (const std::exception & e) {
283  mout.info(scalingFunctor);
284  mout.warn(scalingFunctor.getParameters());
285  mout.error(e.what());
286  }
287 
288  mout.debug2(scalingFunctor.getName() , ':' , scalingFunctor );
289 
290  const double coeff = (rescale>0.0) ? 1.0/rescale : 1.0/static_cast<double>(channels);
291  const bool USE_POW = (POW != 1.0);
292  const bool USE_INVPOW = (INVPOW != 1.0);
293  mout.debug3("coeff " , coeff );
294  const BinaryFunctor & f = binaryFunctor;
295  size_t a;
296  for (int j = 0; j < height; j++) {
297  for (int i = 0; i < width; i++) {
298 
299  sum = 0.0;
300  a = dstChannel.address(i,j);
301  for (size_t k = 0; k < channels; k++){
302  // getValue( src1.get(k).get<double>(a) , src2.get(k).get<double>(a) );
303  x = f(src1.get(k).get<double>(a) , src2.get(k).get<double>(a)) ;
304  if (USE_POW)
305  sum += pow(x, POW);
306  else
307  sum += x;
308  }
309  if (USE_INVPOW)
310  dstChannel.put(a, scalingFunctor(pow(coeff*sum, INVPOW)));
311  else
312  dstChannel.put(a, scalingFunctor(coeff*sum));
313  }
314  }
315 
316 }
317 
318 
320 
334 class DistanceOp : public BinaryPixelVectorOp<SubtractionFunctor> {
335 
336 public:
337 
338  DistanceOp() : BinaryPixelVectorOp<SubtractionFunctor>(__FUNCTION__, "Computes the distance of pixel vectors."){
339  POW = 2.0;
340  INVPOW = 0.5;
341  //functorDef="FuzzyStep/0:200";
342  };
343 
344 };
345 
346 
348 
363 class ProductOp : public BinaryPixelVectorOp<MultiplicationFunctor>
364 {
365 public:
366 
367  ProductOp() : BinaryPixelVectorOp<MultiplicationFunctor>(__FUNCTION__, "Computes the dot product of pixel vectors."){
368  POW = 1.0;
369  INVPOW = 0.5;
370  //functorDef="FuzzyStep/0:200";
371  };
372 
373 };
374 
376 
389 class MagnitudeOp : public BinaryPixelVectorOp<MultiplicationFunctor> {
390 
391 public:
392 
393  //MagnitudeOp(const std::string & mapping = "linear", double l=2.0) : PixelVectorOp(__FUNCTION__,"Computes the magnitude of a pixel vector."){
394  MagnitudeOp() : BinaryPixelVectorOp<MultiplicationFunctor>(__FUNCTION__, "Computes the magnitude of a pixel vector."){
395  POW = 1.0; // because x*x natively
396  INVPOW = 0.5;
397  //functorDef="FuzzyStep/0:200";
398  };
399 
400  virtual
401  inline
402  void process(const ImageFrame &src, Image &dst) const {
403  Logger mout(getImgLog(), __FILE__, __FUNCTION__); //REPL getImgLog(), name+"(PixelVectorOp)", __FUNCTION__);
404  mout.debug("delegating to: process(src, src, dst)" );
406  };
407 
408  virtual
409  inline
410  void traverseFrame(const ImageFrame &src, ImageFrame & dst) const {
411  Logger mout(getImgLog(), __FILE__, __FUNCTION__); //REPL getImgLog(), name+"::PixelVectorOp[src, dst]", __FUNCTION__);
412  mout.warn("delegating to: traverseFrame(src, src, dst)" );
414  }
415 
416  virtual
417  inline
418  void traverseChannels(const ImageTray<const Channel> & src, ImageTray<Channel> & dst) const {
419  Logger mout(getImgLog(), __FILE__, __FUNCTION__); //REPL getImgLog(), name+"::PixelVectorOp[src,dst]", __FUNCTION__);
420  mout.debug("delegate to: traverseChannels(src, SRC, dst)" );
422  }
423 
424 };
425 
426 
427 }
428 }
429 
430 
431 #endif /*PixelVectorOP_H_*/
432 
433 // Drain
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
virtual void clear()
Removes all the elements of the map.
Definition: ReferenceMap.h:374
static bool split2(const std::string &s, T1 &first, T2 &second, const C &separators, const std::string &trimChars=" \t\n")
Splits and trims a given std::string to a std Sequence.
Definition: PixelVectorOp.h:127
virtual void process(const ImageFrame &src, Image &dst) const
Main interface. Typically splits processing to each channel.
Definition: PixelVectorOp.h:136
Image with static geometry.
Definition: ImageChannel.h:60
Computes the distance between intensity vectors.
Definition: PixelVectorOp.h:334
Definition: PixelVectorOp.h:90
virtual void traverseChannel(const Channel &src, Channel &dst) const
Apply to single channel.
Definition: PixelVectorOp.h:113
Struct for image (excluding data)
Definition: ImageConf.h:333
Image with static geometry.
Definition: ImageFrame.h:67
void copyData(const ImageFrame &src)
Copies data. Does not change encoding, geometry, or coordinate policy.
Definition: ImageFrame.cpp:209
bool hasOverlap(const ImageFrame &image) const
Checks if images have a common memory segment.
Definition: ImageFrame.h:341
Base class for image processing functions.
Definition: ImageOp.h:49
virtual void makeCompatible(const ImageConf &src, Image &dst) const
Depending on the operator, modifies the geometry and type of dst.
Definition: ImageOp.cpp:54
ImageOp(const std::string &name=__FUNCTION__, const std::string &description="")
Definition: ImageOp.h:156
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
void copyDeep(const ImageFrame &src)
Copies the type, geometry, coordinate policy and data of the given image.
Definition: Image.h:314
Computes pixel magnitude, that is, euclidean norm of the intensity vector.
Definition: PixelVectorOp.h:389
virtual void process(const ImageFrame &src, Image &dst) const
Main interface. Typically splits processing to each channel.
Definition: PixelVectorOp.h:402
A base class for operations between of multi-channel pixels (intensity vectors) of two images.
Definition: PixelVectorOp.h:62
virtual void getDstConf(const ImageConf &srcConf, ImageConf &dstConf) const
Given source image, determine respective dest image configuration.
Definition: PixelVectorOp.cpp:40
Computes dot product of intensities of two images.
Definition: PixelVectorOp.h:364
Definition: DataSelector.cpp:1277
FunctorBank & getFunctorBank()
Definition: FunctorBank.cpp:51