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