FastOpticalFlowOp2.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 SLIDINGWINDOWOPTICALFLOWOP2_H_
32 #define SLIDINGWINDOWOPTICALFLOWOP2_H_
33 
34 #include <drain/image/ImageFile.h>
35 #include <sstream>
36 #include <math.h>
37 
38 #include "drain/util/Fuzzy.h"
39 
40 #include "FastOpticalFlowOp.h" // OpticalFlowConfig, OpticalFlowCore1
41 
42 
43 namespace drain
44 {
45 
46 namespace image
47 {
48 
49 
50 
51 
53 
54 public:
55 
56  // Sources
57  static inline
58  size_t getDiffChannelCount(){return 5;};
59 
60  ImageView GXX;
61  ImageView GXY;
62  ImageView GYY;
63 
64  ImageView GXT;
65  ImageView GYT;
66 
67 
69 
78  void setSrcFrames(const ImageTray<const Channel> & srcTray);
79 
80 
81 protected:
82 
83  ~OpticalFlowCore2(){};
84 
85 };
86 
87 
89 
92 template <class R = OpticalFlowCore2 >
93 class SlidingOpticalFlow2 : public SlidingWindow<OpticalFlowConfig, R> {
94 
95 public:
96 
97  SlidingOpticalFlow2(int width = 0, int height = 0) : SlidingWindow<OpticalFlowConfig, R>(width, height) {
98  address = 0;
99  w = u = v = nom = quality = 0.0;
100  }
101 
103  address = 0;
104  w = u = v = nom = quality = 0.0;
105  }
106 
107  virtual inline
108  ~SlidingOpticalFlow2(){};
109 
110  // "Inherit" data types.
111  typedef OpticalFlowCore1::data_t data_t;
112  typedef OpticalFlowCore1::cumul_t cumul_t;
113 
114  virtual
115  inline
116  void setImageLimits() const {
117  this->coordinateHandler.setPolicy(this->GXX.getCoordinatePolicy());
118  this->coordinateHandler.setLimits(this->GXX.getWidth(), this->GXX.getHeight());
119  }
120 
121 
122  virtual
123  void initialize();
124 
125 
126  virtual inline
128 
129  Logger mout(getImgLog(), "SlidingOpticalFlow", __FUNCTION__);
130  mout.error("unimplemented" );
131  /*
132  if (! this->coordinateHandler.validate(p))
133  return;
134 
135  address = this->GXX.address(p.x, p.y);
136 
137  Gxx += this->GXX.template get<data_t>(this->address);
138  Gxy += this->GXY.template get<data_t>(this->address);
139  Gyy += this->GYY.template get<data_t>(this->address);
140  Gxt += this->GXT.template get<data_t>(this->address);
141  Gyt += this->GYT.template get<data_t>(this->address);
142 
143  // Quality only
144  W += this->srcW.template get<data_t>(this->address);
145  */
146  }
147 
148  virtual inline
150 
151  Logger mout(getImgLog(), "SlidingOpticalFlow", __FUNCTION__);
152  mout.error("unimplemented" );
153 
154  /*
155  if (! this->coordinateHandler.validate(p))
156  return;
157 
158  address = this->GXX.address(p.x, p.y);
159 
160  Gxx -= this->GXX.template get<data_t>(this->address);
161  Gxy -= this->GXY.template get<data_t>(this->address);
162  Gyy -= this->GYY.template get<data_t>(this->address);
163  Gxt -= this->GXT.template get<data_t>(this->address);
164  Gyt -= this->GYT.template get<data_t>(this->address);
165 
166  // Quality only
167  W -= this->srcW.template get<data_t>(this->address);
168  */
169  }
170 
171 
172 
174  /*
175  inline
176  data_t predictionError(double u, double v) const {
177  //return u*Dx.get<double>(address) + v*Dy.get<double>(address) - Dt.get<double>(address);
178  if (W > 0.0)
179  //return sqrt((Gtt - 2.0*(Gxt*u + Gyt*v) + Gxx*u*u + 2.0*Gxy*u*v + Gyy*v*v)/W);
180  return sqrt((Gtt + 2.0*(Gxy*u*v - Gxt*u - Gyt*v) + Gxx*u*u + Gyy*v*v)/W);
181  else
182  return 0;
183  };
184  */
185 
186  virtual inline
187  void write(){
188 
189 
190  nom = this->nominator();
191 
192  /*
193  if (this->debugDiag(4)){
194  // std::cerr << this->location << '\t' << this->nominator() << '\t' << this->uDenominator() << ',' << this->vDenominator() << '\n';
195  // this->uField.put(this->location, rand());
196 
197  std::cerr << this->location << " \t"
198  << this->GXX.template get<double>(this->location) << '\t'
199  << '\n';
200  if (nom != 0.0){
201  u = this->uDenominator()/nom;
202  v = this->vDenominator()/nom;
203  std::cerr << " => " << u << ',' << v << '\n';
204  }
205  }
206  */
207 
208  if (nom > 0.00000001){ // todo minQuality
209 
210  u = this->uDenominator()/nom;
211  v = this->vDenominator()/nom;
212  this->uField.put(this->location, this->conf.invertU ? -u : u);
213  this->vField.put(this->location, this->conf.invertV ? -v : v);
214 
215  static const drain::FuzzySigmoid<double> sigmoid(0.0, 127.0, 254.0);
216  quality = sqrt(nom/this->W);
217  this->dstWeight.put(this->location, sigmoid(quality));
218  }
219  else {
220  this->uField.put(this->location, 0);
221  this->vField.put(this->location, 0);
222  this->dstWeight.put(this->location, 0);
223  }
224 
225  }
226 
227 protected:
228 
229  virtual
230  void clear(){
231  this->clearStats();
232  //std::cerr << "SlidingOpticalFlow2::" << __FUNCTION__ << ": " << this->nominator() << ", " << this->uDenominator() << ", " << this->vDenominator() << std::endl;
233  }
234 
235  // Used by addPixel, removePixel
236  mutable size_t address;
237  //mutable data_t dx, dy, dt, w; // inner-loop (instantaneous)
238  mutable data_t w; // inner-loop (instantaneous)
239 
240  // Used by write
241  mutable data_t u, v;
242  mutable data_t nom;
243  mutable data_t quality;
244 
245 };
246 
247 template <class R>
249 
250  Logger mout(getImgLog(), "SlidingOpticalFlow2", __FUNCTION__);
251 
252  this->setImageLimits();
253  this->setLoopLimits();
254  this->location.setLocation(0,0);
255 
256  mout.debug("window: " , *this );
257  mout.debug2();
258  mout << "GXX: " << this->GXX << '\n';
259  mout << "GXY: " << this->GXY << '\n';
260  mout << "GXX: " << this->GYY << '\n';
261  mout << "GXX: " << this->GXT << '\n';
262  mout << "GXX: " << this->GYT << '\n';
263  mout << "W: " << this->srcWeight << '\n';
264  mout << mout.endl;
265  //this->resetAtEdges = true;
266 
267  /*
268  std::cout << "Annapa input\n";
269  drain::Point2D<int> p;
270  std::string s;
271  while (getline(std::cin, s)){
272  //while ((std::cin>>p.x) && (std::cin>>p.y)){
273  std::stringstream sstr(s);
274  sstr >> p.x >> p.y;
275  std::cout << p << "\t =>";
276  int result = this->coordinateHandler.validate(p);
277  std::cout << p << "\t (" << result << ")\n" ;
278  }
279  */
280 
281 }
282 
283 
284 
285 class SlidingOpticalFlowWeighted2 : public SlidingOpticalFlow2<OpticalFlowCore2> {
286 
287 public:
288 
290  }
291 
293 
294 
295  virtual inline
297 
298  if (! this->coordinateHandler.validate(p))
299  return;
300 
301  address = this->GXX.address(p.x, p.y);
302  /*
303  if (p.y > GXX.getHeight()){
304  std::cerr << " coord overflow at " << p << std::endl;
305  }
306  */
307  w = this->srcWeight.get<data_t>(address);
308 
309  W += w;
310  // w already included in cumulants
311  Gxx += this->GXX.get<data_t>(address);
312  Gxy += this->GXY.get<data_t>(address);
313  Gyy += this->GYY.get<data_t>(address);
314  Gxt += this->GXT.get<data_t>(address);
315  Gyt += this->GYT.get<data_t>(address);
316 
317  // Quality only
318  }
319 
320  virtual inline
322 
323  if (! this->coordinateHandler.validate(p))
324  return;
325 
326  address = this->GXX.address(p.x, p.y);
327 
328  // Quality
329  w = this->srcWeight.get<data_t>(address);
330 
331  W -= w;
332  // w already included in cumulants
333  Gxx -= this->GXX.get<data_t>(address);
334  Gxy -= this->GXY.get<data_t>(address);
335  Gyy -= this->GYY.get<data_t>(address);
336  Gxt -= this->GXT.get<data_t>(address);
337  Gyt -= this->GYT.get<data_t>(address);
338 
339 
340  }
341 
342 
343 };
344 
345 //--------------------------------------------------------------std::cout << locationHandled << '\n';----------------------------
346 
347 
350 
371 class FastOpticalFlow2Op : public SlidingWindowOp<SlidingOpticalFlowWeighted2> { // = window_t
372 
373 public:
374 
375  typedef window_t::data_t data_t;
376 
377  FastOpticalFlow2Op(int width=5, int height=5): //, double smoothing=0.01) : //, double gradPow=2.0) : //, double gradWidth = 16) :
378  SlidingWindowOp<SlidingOpticalFlowWeighted2>(__FUNCTION__, "Optical flow computed based on differential accumulation layers.")
379  {
380  //parameters.append(blender.getParameters(), false);
381  //blender.setParameter("mix", "b");
382  // New. Blender will be obsolete
383  parameters.link("resize", resize = 0, "0.0..1.0|pix");
384  parameters.link("threshold", threshold = NAN, "value");
385  parameters.link("spread", spread = 0, "0|1");
386  parameters.link("smooth", smoother = 0, "0|1");
387  setSize(width, height);
388  }
389 
390  inline
392  //std::cerr << __FUNCTION__ << op.getParameters() << '\n';
393  parameters.copyStruct(op.getParameters(), op, *this);
394  }
395 
396 
398  virtual inline
399  //void makeCompatible(const ImageFrame & src, Image & dst) const {
400  void getDstConf(const ImageConf & src, ImageConf & dst) const {
401  //dst.initialize(typeid(OpticalFlowCore2::data_t), src.getWidth(), src.getHeight(), 2, 1);
402  dst.setType(typeid(OpticalFlowCore2::data_t));
403  dst.setArea(src.getGeometry());
404  dst.setChannelCount(2, 1);
405  };
406 
407  virtual inline
408  size_t getDiffChannelCount() const {
409  return window_t::getDiffChannelCount();
410  }
411 
412  virtual inline
413  void traverseChannels(const ImageTray<const Channel> & src, ImageTray<Channel> & dst) const {
414  this->traverseMultiChannel(src, dst);
415  }
416 
418 
421  virtual
422  void computeDifferentials(const ImageTray<const Channel> & src, ImageTray<Channel> & dst) const;
423 
424 
425 
426  virtual
427  void preprocess(const Channel & srcImage, const Channel & srcWeight, Image & dstImage, Image & dstWeight) const;
428 
430  inline
431  bool optPreprocess() const {
432  return optResize() || optThreshold() || optSmoother() || optSpread();
433  }
434 
436  inline
437  bool optResize() const { return resize > 0.0; } ;
438 
439 protected:
440 
441  // NEW
442  //std::vector<double> resize;
443  double resize;
444  double threshold;
445  bool spread;
446  bool smoother;
447 
448 
449 
451  inline
452  bool optThreshold() const { return !std::isnan(threshold); };
453 
454  inline
455  bool optSpread() const { return spread; };
456 
457  inline
458  bool optSmoother() const { return smoother; };
459 
460 
461 
462  inline
463  bool checkQuality(const Channel & alpha, std::size_t address, int DX, int DY) const {
464 
465  if (alpha.get<data_t>(address) == 0.0)
466  return false;
467 
468  if (alpha.get<data_t>(address + DX) == 0.0)
469  return false;
470 
471  if (alpha.get<data_t>(address - DX) == 0.0)
472  return false;
473 
474  if (alpha.get<data_t>(address + DY) == 0.0)
475  return false;
476 
477  if (alpha.get<data_t>(address - DY) == 0.0)
478  return false;
479 
480  return true;
481  }
482 
483 };
484 
485 }
486 }
487 
488 #endif
489 
490 // Drain
A smooth step function, by default from -1.0 to +1.0.
Definition: Fuzzy.h:497
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition: Log.h:308
Logger & error(const TT &... args)
Echoes.
Definition: Log.h:412
Logger & debug(const TT &... args)
Public, yet typically used "internally", when TIMING=true.
Definition: Log.h:676
Logger & debug2(const TT &... args)
Debug information.
Definition: Log.h:686
void copyStruct(const ReferenceMap &m, const T &src, T &dst, extLinkPolicy policy=RESERVE)
Experimental. Copies references and values of a structure to another.
Definition: ReferenceMap.h:399
void setLimits(int xMin, int yMin, int xUpperLimit, int yUpperLimit)
Sets minimum values and outer upper limits for x and y.
Definition: CoordinateHandler.h:135
bool validate(Point2D< int > &p) const
Handles the coordinate, returning true if the position is reversible.
Definition: CoordinateHandler.h:223
void setPolicy(const CoordinatePolicy &p)
Assigns internal function pointers.
Definition: CoordinateHandler.h:160
void setType(const std::type_info &t)
Set storage type.
Definition: ImageConf.h:121
Definition: FastOpticalFlowOp2.h:371
virtual void computeDifferentials(const ImageTray< const Channel > &src, ImageTray< Channel > &dst) const
Computes an image with channels Gxx, Gxy, Gyy, Gxt, Gyt and w (quality of gradients)....
Definition: FastOpticalFlowOp2.cpp:189
virtual void getDstConf(const ImageConf &src, ImageConf &dst) const
Creates a double precision image of 2+1 channels for storing motion (uField,vField) and quality (q).
Definition: FastOpticalFlowOp2.h:400
bool optResize() const
Returns true, if resizing is requested.
Definition: FastOpticalFlowOp2.h:437
bool optThreshold() const
Returns true, if threshold is requested as postprocessing.
Definition: FastOpticalFlowOp2.h:452
bool optPreprocess() const
Returns true, if resizing, thresholding or smoothing is requested.
Definition: FastOpticalFlowOp2.h:431
Struct for image (excluding data)
Definition: ImageConf.h:333
Container applicable for Channels and Images, with alpha support.
Definition: ImageTray.h:267
ImageFrame that also has channels.
Definition: ImageView.h:52
Consider using SlidingStripeOpticalFlow instead.
Definition: FastOpticalFlowOp.h:57
bool invertV
If true, negate Y so that it will increase towards top (North)
Definition: FastOpticalFlowOp.h:70
bool invertU
If true, negate X so that it will increase towards left (West)
Definition: FastOpticalFlowOp.h:67
Definition: FastOpticalFlowOp2.h:52
void setSrcFrames(const ImageTray< const Channel > &srcTray)
Set inputs as channels.
Definition: FastOpticalFlowOp2.cpp:53
Definition: FastOpticalFlowOp.h:75
Currently not in use. See SlidingOpticalFlowWeighted2 below.
Definition: FastOpticalFlowOp2.h:93
virtual void setImageLimits() const
Sets internal limits corresponding to image geometries. Typically using coordHandler.
Definition: FastOpticalFlowOp2.h:116
virtual void write()
Returns the mean squared error of predicted.
Definition: FastOpticalFlowOp2.h:187
virtual void initialize()
Sets class-specific initial values. Does not change general window state (e.g. location)....
Definition: FastOpticalFlowOp2.h:248
virtual void removePixel(Point2D< int > &p)
Removes a pixel from window statistics. Unvalidated location.
Definition: FastOpticalFlowOp2.h:149
virtual void addPixel(Point2D< int > &p)
Adds a pixel to window statistics. Unvalidated location.
Definition: FastOpticalFlowOp2.h:127
virtual void clear()
Clears the applied statistics. Redefined in derived classes.
Definition: FastOpticalFlowOp2.h:230
Definition: FastOpticalFlowOp2.h:285
virtual void removePixel(Point2D< int > &p)
Removes a pixel from window statistics. Unvalidated location.
Definition: FastOpticalFlowOp2.h:321
virtual void addPixel(Point2D< int > &p)
Adds a pixel to window statistics. Unvalidated location.
Definition: FastOpticalFlowOp2.h:296
Template for operators applying pipeline-like sliding window.
Definition: SlidingWindowOp.h:59
Window implementation that uses incremental update of state.
Definition: SlidingWindow.h:50
Point2D< int > location
Current location of this window.
Definition: Window.h:520
Definition: DataSelector.cpp:1277