Loading...
Searching...
No Matches
FastOpticalFlowOp.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 SLIDING_WINDOW_OPTICALFLOW_OP_H_
32#define SLIDING_WINDOW_OPTICALFLOW_OP_H_
33
34#include <math.h>
35
36//#include "drain/image/ImageTray.h"
37#include "drain/image/SlidingWindow.h"
38#include "SlidingWindowOp.h"
39//#include "QuadraticSmootherOp.h"
40#include "BlenderOp.h"
41
42
43namespace drain
44{
45
46namespace image
47{
48
50
56
57public:
58
59
60 OpticalFlowConfig() : invertU(false), invertV(true) {
61
62 }
63
65 bool invertU;
66
68 bool invertV;
69
70};
71
72
74
75public:
76
77 typedef double data_t;
78 typedef double cumul_t;
79
82
83 inline
84 void setSrcFrameWeight(const ImageFrame & srcW){
85 Logger mout(getImgLog(), "WeightedOpticalFlowCore", __FUNCTION__);
86 this->srcWeight.setView(srcW);
87 //mout.debug("srcW: " , srcW );
88 mout.debug("srcWeight (view): " , this->srcWeight );
89 };
90
91 // Destination images
92
95
98
101
102
104
110 void setDstFrames(ImageTray<Channel> & dstTray);
111
112 inline
113 void setDstFrameWeight(const ImageFrame & dstW){
114 //Logger mout(getImgLog(), "OpticalFlowCore2", __FUNCTION__);
115 this->dstWeight.setView(dstW);
116 //mout.debug("srcW: " , srcW );
117 //mout.debug("view: " , this->srcWeight );
118 };
119
120 inline
121 data_t nominator() const {
122 return static_cast<data_t>(Gxx*Gyy - Gxy*Gxy);
123 };
124
126 inline
127 data_t uDenominator() const {
128 return static_cast<data_t>(Gxy*Gyt - Gyy*Gxt);
129 };
130
132 inline
133 data_t vDenominator() const {
134 return static_cast<data_t>(Gxy*Gxt - Gxx*Gyt);
135 };
136
137
138protected:
139
140 // sum w fx*fx
141 cumul_t Gxx;
142 // sum w fx*fy
143 cumul_t Gxy;
144 // sum w fx*fx
145 cumul_t Gyy;
146 // sum w fx*ft
147 cumul_t Gxt;
148 // sum w fy*ft
149 cumul_t Gyt;
150
151 // sum w ft*ft (needed only for prediction error, and quality index thereof)
152 cumul_t Gtt;
153 data_t W;
154
158 // Consider: weight = > weightSUm
159 //virtual
160 void clearStats(){
161 Gxx = 0.0;
162 Gxy = 0.0;
163 Gyy = 0.0;
164 Gxt = 0.0;
165 Gyt = 0.0;
166 // Quality only:
167 Gtt = 0.0;
168 W = 0.0;
169
170 //std::cerr << __FUNCTION__ << ": " << this->nominator() << ", " << this->uDenominator() << ", " << this->vDenominator() << std::endl;
171
172 }
173
174};
175
177
178public:
179
180 static inline
181 size_t getDiffChannelCount() {return 3;};
182
189
191
198 void setSrcFrames(const ImageTray<const Channel> & srcTray);
199
200
201protected:
202
204
205};
206
207
208
209template <class R = OpticalFlowCore1 >
210class SlidingOpticalFlow : public SlidingWindow<OpticalFlowConfig, R> {
211
212public:
213
214 SlidingOpticalFlow(int width = 0, int height = 0) : SlidingWindow<OpticalFlowConfig, R>(width, height) {
215 //setSize(width,height);
216 }
217
219 //setSize(conf.width, conf.height);
220 }
221
222 virtual
224
225 // "Inherit" data types.
226 typedef OpticalFlowCore1::data_t data_t;
227 typedef OpticalFlowCore1::cumul_t cumul_t;
228
229 // protected:
230 //double areaD;
231
232 virtual
233 inline
234 void setImageLimits() const {
235 //this->adjustCoordHandler(this->coordinateHandler);
236 this->coordinateHandler.setPolicy(this->Dx.getCoordinatePolicy());
237 this->coordinateHandler.setLimits(this->Dx.getHeight(), this->Dy.getHeight());
238 }
239
240
241 virtual
243
244
245
246
247
248 virtual inline
250
251 if (! this->coordinateHandler.validate(p))
252 return;
253
254 address = this->Dx.address(p.x, p.y);
255
256 dx = this->Dx.template get<data_t>(this->address);
257 dy = this->Dy.template get<data_t>(this->address);
258 dt = this->Dt.template get<data_t>(this->address);
259 // now "w = 1";
260
261 // if ((location.x == 100) && (location.y == 100)) std::cout << locationHandled << '\n';
262 /*
263 if (this->debugDiag(4)){
264 std::cout << this->location
265 << dx*dx << '\t'
266 << dx*dy << '\t'
267 << dy*dy << '\t'
268 << dx*dt << '\t'
269 << dy*dt << '\n';
270 }
271 */
272
273
274 this->Gxx += dx*dx;
275 this->Gxy += dx*dy;
276 this->Gyy += dy*dy;
277 this->Gxt += dx*dt;
278 this->Gyt += dy*dt;
279
280 // Quality only
281 this->Gtt -= dt*dt;
282 this->W += 1.0;
283 }
284
285 virtual inline
287
288 if (! this->coordinateHandler.validate(p))
289 return;
290
291 address = this->Dx.address(p.x, p.y);
292
293 dx = this->Dx.template get<data_t>(address);
294 dy = this->Dy.template get<data_t>(address);
295 dt = this->Dt.template get<data_t>(address);
296 //now "w = 1";
297
298 this->Gxx -= dx*dx;
299 this->Gxy -= dx*dy;
300 this->Gyy -= dy*dy;
301 this->Gxt -= dx*dt;
302 this->Gyt -= dy*dt;
303
304 // Quality only
305 this->Gtt -= dt*dt;
306 this->W -= 1.0;
307 }
308
309
311 inline
312 data_t predictionError(double u, double v) const {
313 //return u*Dx.get<double>(address) + v*Dy.get<double>(address) - Dt.get<double>(address);
314 if (this->W > 0.0)
315 //return sqrt((Gtt - 2.0*(Gxt*u + Gyt*v) + Gxx*u*u + 2.0*Gxy*u*v + Gyy*v*v)/W);
316 return sqrt((this->Gtt + 2.0*(this->Gxy*u*v - this->Gxt*u - this->Gyt*v) + this->Gxx*u*u + this->Gyy*v*v)/this->W);
317 else
318 return 0;
319 };
320
321 virtual inline
322 void write(){
323
324 /*
325 if (this->debugDiag(4)){
326
327 dx = this->Dx.template get<double>(address);
328 dy = this->Dy.template get<double>(address);
329 dt = this->Dt.template get<double>(address);
330 //w = srcWeight.get<data_t>(address);
331
332 std::cout << this->location << " \t"
333 << dx*dx << '\t'
334 << dx*dy << '\t'
335 << dy*dy << '\t'
336 << dx*dt << '\t'
337 << dy*dt << '\n';
338 }
339 */
340
341 nom = this->nominator();
342 /*
343 Logger mout(getImgLog(), "SlidingOpticalFlow", __FUNCTION__);
344 mout.warn("start: " , location );
345 mout.note("uField: " , uField );
346 mout.note("vField: " , vField );
347 mout.note("w: " , dstWeight );
348 File::write(uField, "uField.png");
349 File::write(vField, "vField.png");
350 File::write(dstWeight, "w.png");
351 mout.error("halt" );
352 */
353
354 if (nom > 0.01){ // todo minQuality
355 //if (w > 0.05){ // todo minQuality
356
357 u = this->uDenominator()/nom;
358 v = this->vDenominator()/nom;
359 quality = sqrt(nom/this->W);
360 //quality = this->srcWeight.template get<data_t>(this->location); // iGradient stability
361 //quality = predictionError(u, v); // TODO multiply with gradQuality
362 //quality = this->srcWeight.getScaled(this->location.x, this->location.y);
363 //quality = sqrt(nom/W) * this->srcWeight.getScaled(this->location.x, this->location.y); // predictionError(u, v); // TODO multiply with gradQuality
364 //quality = sqrt(nom/(u*u + v*v));
365 //quality = sqrt(nom/(Gxx*Gxx + Gyy+Gyy));
366
367
368
369 /*
370 if (this->location.x == this->location.y)
371 if ((this->location.x & 7) == 0){
372 std::cout << this->location << ' ';
373 std::cout << "\t v=(" << u << ',' << v << ")\t";
374 //std::cout << "Diff:\t" << dx << '\t' << dy << '\t' << dt << "\tuvq:\t";
375 //std::cout << uDenominator()/nom << '\t' << vDenominator()/nom << '\t' << quality << '\n';
376 //std::cout << "\t w=(" << this->srcWeight.template get<data_t>(this->location) << ',' << (W/areaD) << ")\t";
377 //std::cout << "\t w=(" << w << ',' << W << ',' << this->srcWeight.template get<data_t>(this->location) << ")\t";
378 std::cout << "\t w=(" << (W/areaD) << ")\t";
379 std::cout << quality << '\n';
380 }
381 */
382
383 this->uField.put(this->location, this->conf.invertU ? -u : u);
384 this->vField.put(this->location, this->conf.invertV ? -v : v);
385 //this->dstWeight.put(this->location, ( 1.0 - 1.0/(1.0+quality)) * this->dstWeight.getScaling().getScale());
386 //this->dstWeight.putScaled(this->location.x, this->location.y, quality);
387 this->dstWeight.put(this->location, quality);
388 //this->dstWeight.put(this->location, this->dstWeight.getScaling().inv( 1.0 - 1.0/(1.0+quality)));
389 }
390 else {
391 this->uField.put(this->location, 0);
392 this->vField.put(this->location, 0);
393 this->dstWeight.put(this->location, 0);
394 }
395
396 }
397
398protected:
399
400 virtual
401 void clear(){
402 std::cerr << "SlidingOpticalFlow::" << __FUNCTION__ << std::endl;
403 this->clearStats();
404 }
405
406 // Used by addPixel, removePixel
407 mutable size_t address;
408 mutable data_t dx, dy, dt, w; // inner-loop (instantaneous)
409
410 // Used by write
411 mutable data_t u, v;
412 mutable data_t nom;
413 mutable data_t quality;
414
415};
416
417template <class R>
419
420 Logger mout(getImgLog(), "SlidingOpticalFlow", __FUNCTION__);
421
422 //this->areaD = this->getArea();
423 this->setImageLimits();
424 this->setLoopLimits();
425
426 mout.debug("window: " , *this );
427 mout.debug3("Dx: " , this->Dx );
428 mout.debug3("Dy: " , this->Dy );
429 mout.debug3("Dt: " , this->Dt );
430
431 //clear();
432 //fill(0, 0);
433
434}
435
436
437/*
438class SlidingOpticalFlow : public SlidingOpticalFlowBase<OpticalFlowCore1> {
439
440public:
441
442 SlidingOpticalFlow(const config & conf) : SlidingOpticalFlowBase<OpticalFlowCore1>(conf) {
443 //setSize(conf.width, conf.height);
444 }
445
446};
447*/
448
449class SlidingOpticalFlowWeighted : public SlidingOpticalFlow<OpticalFlowCore1> {
450
451public:
452
454 }
455
457
458 virtual
459 inline
461
462 if (! coordinateHandler.validate(p))
463 return;
464
465 address = Dx.address(p.x, p.y);
466
467 dx = Dx.get<data_t>(address);
468 dy = Dy.get<data_t>(address);
469 dt = Dt.get<data_t>(address);
470 w = srcWeight.get<data_t>(address);
471
472 // if ((location.x == 100) && (location.y == 100)) std::cout << locationHandled << '\n';
473 /*
474 if ((location.x == 70) && (location.y == 120)){
475 Logger mout(getImgLog(), "SlidingOpticalFlow", __FUNCTION__);
476 mout.note(this->location , '\t' , p );
477 }
478 */
479
480 Gxx += w*dx*dx;
481 Gxy += w*dx*dy;
482 Gyy += w*dy*dy;
483 Gxt += w*dx*dt;
484 Gyt += w*dy*dt;
485 // Quality only:
486 Gtt += w*dt*dt;
487 W += w;
488 }
489
490 virtual inline
492
493 if (! coordinateHandler.validate(p))
494 return;
495
496 address = Dx.address(p.x, p.y);
497
498 dx = Dx.get<data_t>(address);
499 dy = Dy.get<data_t>(address);
500 dt = Dt.get<data_t>(address);
501 w = srcWeight.get<data_t>(address);
502 // w = 1;
503
504 Gxx -= w*dx*dx;
505 Gxy -= w*dx*dy;
506 Gyy -= w*dy*dy;
507 Gxt -= w*dx*dt;
508 Gyt -= w*dy*dt;
509 // Quality only:
510 Gtt -= w*dt*dt;
511 W -= w;
512 }
513
514};
515
516//--------------------------------------------------------------std::cout << locationHandled << '\n';----------------------------
517
518
521
542class FastOpticalFlowOp : public SlidingWindowOp<SlidingOpticalFlowWeighted> {
543
544public:
545
546 FastOpticalFlowOp(int width=5, int height=5): //, double smoothing=0.01) : //, double gradPow=2.0) : //, double gradWidth = 16) :
547 SlidingWindowOp<SlidingOpticalFlowWeighted>(__FUNCTION__, "A pipeline implementation of optical flow."), blender(width, height, "avg", "blend", 1) {
548 parameters.append(blender.getParameters(), false);
549 }
550
552 virtual inline
553 void getDstConf(const ImageConf & src, ImageConf & dst) const {
554 dst.setType(typeid(OpticalFlowCore1::data_t));
555 dst.setGeometry(src.getWidth(), src.getHeight(), 2, 1);
556 }
557
558 /*
559 void make Compatible(const ImageFrame & src, Image & dst) const {
560 dst.initialize(typeid(OpticalFlowCore1::data_t), src.getWidth(), src.getHeight(), 2, 1);
561 };
562 */
563
565
568 virtual
570
571
572 //virtual void traverseChannels(const ImageTray<const Channel> & srcTray, ImageTray<Channel> & dstTray) const;
573
574 virtual inline
575 void traverseChannels(const ImageTray<const Channel> & src, ImageTray<Channel> & dst) const {
576 this->traverseMultiChannel(src, dst);
577 }
578
579 virtual inline
580 void traverseChannel(const Channel & src, Channel & dst) const {
581 Logger mout(getImgLog(), __FILE__, __FUNCTION__);
582 mout.error("Not implemented (1/1)" );
583 }
584
585 virtual inline
586 size_t getDiffChannelCount() const {
587 return window_t::getDiffChannelCount();
588 }
589
590
591 inline
592 bool preSmooth() const {
593 return !blender.getSmootherKey().empty();
594 }
595
596 mutable
597 BlenderOp blender;
598
599};
600
601}
602}
603
604#endif
605
606// Drain
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition Log.h:313
Logger & debug(const TT &... args)
Debug information.
Definition Log.h:667
Logger & error(const TT &... args)
Echoes.
Definition Log.h:417
void append(ReferenceMap &rMap, bool replace=true)
Adopts the references of r. If replace==false, only new entries are appended.
Definition ReferenceMap.h:336
Image with static geometry.
Definition ImageChannel.h:58
void setLimits(int xMin, int yMin, int xUpperLimit, int yUpperLimit)
Sets minimum values and outer upper limits for x and y.
Definition CoordinateHandler.h:147
bool validate(Point2D< int > &p) const
Handles the coordinate, returning true if the position is reversible.
Definition CoordinateHandler.h:235
void setPolicy(const CoordinatePolicy &p)
Assigns internal function pointers.
Definition CoordinateHandler.h:172
void setType(const std::type_info &t)
Set storage type.
Definition ImageConf.h:121
Definition FastOpticalFlowOp.h:542
virtual void computeDifferentials(const ImageTray< const Channel > &src, ImageTray< Channel > &dst) const
Computes an image with channels dx, dy, dt and w (quality of gradients). User may redefine this.
Definition FastOpticalFlowOp.cpp:114
virtual void traverseChannel(const Channel &src, Channel &dst) const
Apply to single channel.
Definition FastOpticalFlowOp.h:580
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 FastOpticalFlowOp.h:553
Struct for image (excluding data)
Definition ImageConf.h:333
Image with static geometry.
Definition ImageFrame.h:62
void put(size_t i, T x)
Sets the intensity in location i to x. See \address.
Definition ImageFrame.h:187
T get(size_t i) const
Gets the intensity at location i. See address().
Definition ImageFrame.h:249
Container applicable for Channels and Images, with alpha support.
Definition ImageTray.h:266
ImageFrame that also has channels.
Definition ImageView.h:52
void setView(const ImageFrame &src)
Views the whole image.
Definition ImageView.h:65
Consider using SlidingStripeOpticalFlow instead.
Definition FastOpticalFlowOp.h:55
bool invertV
If true, negate Y so that it will increase towards top (North)
Definition FastOpticalFlowOp.h:68
bool invertU
If true, negate X so that it will increase towards left (West)
Definition FastOpticalFlowOp.h:65
Definition FastOpticalFlowOp.h:176
ImageView Dt
Precomputed time diffential.
Definition FastOpticalFlowOp.h:188
ImageView Dy
Precomputed vertical diffential.
Definition FastOpticalFlowOp.h:186
ImageView Dx
Precomputed horizontal diffential.
Definition FastOpticalFlowOp.h:184
void setSrcFrames(const ImageTray< const Channel > &srcTray)
Set inputs as channels 0:Dx, 1:Dy, 2:Dt, 3/alpha: weight.
Definition FastOpticalFlowOp.cpp:80
Definition FastOpticalFlowOp.h:73
ImageView uField
Horizontal velocity.
Definition FastOpticalFlowOp.h:94
data_t uDenominator() const
Returns the horizontal component of motion. Must be scaled by nominator().
Definition FastOpticalFlowOp.h:127
void setDstFrames(ImageTray< Channel > &dstTray)
Set outputs as channels (uField, vField, w)
Definition FastOpticalFlowOp.cpp:48
ImageView dstWeight
Quality of the velocity.
Definition FastOpticalFlowOp.h:100
ImageView vField
Vertical velocity.
Definition FastOpticalFlowOp.h:97
data_t vDenominator() const
Returns the vertical component of motion. Must be scaled by nominator().
Definition FastOpticalFlowOp.h:133
ImageView srcWeight
Precomputed weight field (optional)
Definition FastOpticalFlowOp.h:81
Definition FastOpticalFlowOp.h:449
virtual void removePixel(Point2D< int > &p)
Removes a pixel from window statistics. Unvalidated location.
Definition FastOpticalFlowOp.h:491
virtual void addPixel(Point2D< int > &p)
Adds a pixel to window statistics. Unvalidated location.
Definition FastOpticalFlowOp.h:460
Definition FastOpticalFlowOp.h:210
virtual void setImageLimits() const
Sets internal limits corresponding to image geometries. Typically using coordHandler.
Definition FastOpticalFlowOp.h:234
virtual void write()
Write the result in the target image.
Definition FastOpticalFlowOp.h:322
virtual void initialize()
Sets class-specific initial values. Does not change general window state (e.g. location)....
Definition FastOpticalFlowOp.h:418
virtual void removePixel(Point2D< int > &p)
Removes a pixel from window statistics. Unvalidated location.
Definition FastOpticalFlowOp.h:286
data_t predictionError(double u, double v) const
Returns the mean squared error of predicted.
Definition FastOpticalFlowOp.h:312
virtual void addPixel(Point2D< int > &p)
Adds a pixel to window statistics. Unvalidated location.
Definition FastOpticalFlowOp.h:249
virtual void clear()
Clears the applied statistics. Redefined in derived classes.
Definition FastOpticalFlowOp.h:401
Template for operators applying pipeline-like sliding window.
Definition SlidingWindowOp.h:57
Window implementation that uses incremental update of state.
Definition SlidingWindow.h:50
Base class for configurations applied in image processing windows, e.g. for operators of type WindowO...
Definition Window.h:55
Container for source and target images, and their setters.
Definition Window.h:154
Point2D< int > location
Current location of this window.
Definition Window.h:521
Definition DataSelector.cpp:1277
Definition Point.h:48