Ocean
Loading...
Searching...
No Matches
Motion.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#ifndef META_OCEAN_CV_MOTION_H
9#define META_OCEAN_CV_MOTION_H
10
11#include "ocean/cv/CV.h"
17
19#include "ocean/base/Worker.h"
20
21namespace Ocean
22{
23
24namespace CV
25{
26
27// Forward declaration.
28template <typename TMetric>
29class MotionT;
30
31/**
32 * Definition of a Motion class that applies sum absolute difference calculations as metric.
33 * @see MotionSSD, MotionZeroMeanSSD, Motion.
34 * @ingroup cv
35 */
37
38/**
39 * Definition of a Motion class that applies sum square difference calculations as metric.
40 * @see MotionSAD, MotionZeroMeanSSD, Motion.
41 * @ingroup cv
42 */
44
45/**
46 * Definition of a Motion class that applies zero-mean sum square difference calculations as metric.
47 * @see MotionSAD, MotionSSD, Motion.
48 * @ingroup cv
49 */
51
52/**
53 * This class implements patch-based motion techniques.
54 * @tparam TMetric The metric that is applied for measurements with pixel accuracy
55 * @see MotionSAD, MotionSSD, MotionZeroMeanSSD.
56 * @ingroup cv
57 */
58template <typename TMetric = SumSquareDifferences>
60{
61 public:
62
63 /**
64 * Tracks a set of given points between two frames with pixel accuracy.
65 * Actually, this function simply creates two frame pyramids and invokes the corresponding function needing frame pyramid as parameters.<br>
66 * The motion is determined by application of an image patch centered around the point to be tracked.<br>
67 * The points are tracked unidirectional (from the previous frame to the current frame).<br>
68 * If a point is near the frame border, a mirrored image patch is applied
69 * @param previousFrame The previous frame in which the previous points are located, must be valid
70 * @param currentFrame The current frame, with same pixel format and pixel orientation as the previous frame, must be valid
71 * @param previousPoints The points that are located in the previous frame (the points to be tracked from the previous frame to the current frame), with ranges [0, previousFrame.width())x[0, previousFrame.height())
72 * @param roughPoints Rough locations of the previous points in the current frame (if known), otherwise simply provide the previous points again, one for each previous point, with ranges [0, currentFrame.width())x[0, currentFrame.height())
73 * @param currentPoints Resulting current points, that have been tracked from the previous frame to the current frame, with ranges [0, currentFrame.width())x[0, currentFrame.height())
74 * @param maximalOffset Maximal expected offset between two corresponding points in pixel, defined in the domain of previous/current frame, with range [1, infinity)
75 * @param coarsestLayerRadiusX The search radius on the coarsest pyramid layer in horizontal direction, in pixel, with range [0, infinity)
76 * @param coarsestLayerRadiusY The search radius on the coarsest pyramid layer in vertical direction, in pixel, with range [0, infinity)
77 * @param downsamplingMode The down sampling mode that is applied to create the pyramid layers
78 * @param worker Optional worker object to distribute the computation
79 * @param metricResults Optional resulting matching quality of the applied metric, nullptr if the results do not matter
80 * @param metricIdentityResults Optional resulting matching quality of the applied metric between both frames at the identity location (the previous and rough position), nullptr if the results do not matter
81 * @return True, if succeeded
82 * @tparam tPatchSize The size of the square patch (the edge length) in pixel, with range [3, infinity), must be odd, recommended is 5, 7, 15, 31, or 63
83 */
84 template <unsigned int tPatchSize>
85 static bool trackPointsInPyramidMirroredBorder(const Frame& previousFrame, const Frame& currentFrame, const PixelPositions& previousPoints, const PixelPositions& roughPoints, PixelPositions& currentPoints, const unsigned int maximalOffset, const unsigned int coarsestLayerRadiusX, const unsigned int coarsestLayerRadiusY, const FramePyramid::DownsamplingMode downsamplingMode = FramePyramid::DM_FILTER_14641, Worker* worker = nullptr, std::vector<uint32_t>* metricResults = nullptr, std::vector<uint32_t>* metricIdentityResults = nullptr);
86
87 /**
88 * Tracks a set of given points between two frame pyramids, with pixel accuracy.
89 * The points are tracked unidirectional (from the previous frame to the current frame).<br>
90 * The motion is determined by application of an image patch centered around the point to be tracked.<br>
91 * If a point is near the frame border, a mirrored image patch is applied.
92 * @param previousPyramid The frame pyramid of the previous frame in which the previous points are located, must be valid
93 * @param currentPyramid The frame pyramid of the current frame, with same pixel format and pixel origin as the previous frame pyramid, must be valid
94 * @param previousPoints The points that are located in the previous frame (the points to be tracked from the previous frame to the current frame), with ranges [0, previousPyramid.finestWidth())x[0, previousPyramid.finestHeight())
95 * @param roughPoints Rough locations of the previous points in the current frame (if known), otherwise simply provide the previous points again, one for each previous point, with ranges [0, currentPyramid.finestWidth())x[0, currentPyramid.finestHeight())
96 * @param currentPoints Resulting current points, that have been tracked from the previous frame to the current frame, with ranges [0, currentPyramid.finestWidth())x[0, currentPyramid.finestHeight())
97 * @param coarsestLayerRadiusX The search radius on the coarsest pyramid layer in horizontal direction, in pixel, with range [0, infinity)
98 * @param coarsestLayerRadiusY The search radius on the coarsest pyramid layer in vertical direction, in pixel, with range [0, infinity)
99 * @param worker Optional worker object to distribute the computation
100 * @param metricResults Optional resulting matching quality of the applied metric, nullptr if the results do not matter
101 * @param metricIdentityResults Optional resulting matching quality of the applied metric between both frames at the identity location (the previous and rough position), nullptr if the results do not matter
102 * @return True, if succeeded
103 * @tparam tPatchSize The size of the square patch (the edge length) in pixel, with range [3, infinity), must be odd, recommended is 5, 7, 15, 31, or 63
104 */
105 template <unsigned int tPatchSize>
106 static bool trackPointsInPyramidMirroredBorder(const FramePyramid& previousPyramid, const FramePyramid& currentPyramid, const PixelPositions& previousPoints, const PixelPositions& roughPoints, PixelPositions& currentPoints, const unsigned int coarsestLayerRadiusX, const unsigned int coarsestLayerRadiusY, Worker* worker = nullptr, std::vector<uint32_t>* metricResults = nullptr, std::vector<uint32_t>* metricIdentityResults = nullptr);
107
108 /**
109 * Determines the motion for one given point between two frames by application of an image patch.
110 * Patch pixels outside the frame are mirrored into the frame before comparison.
111 * @param frame0 The first frame, must be valid
112 * @param frame1 The second frame, must be valid
113 * @param width0 Width of the first frame in pixel, with range [tPatchSize/2, infinity)
114 * @param height0 Height of the first frame in pixel, with range [tPatchSize/2, infinity)
115 * @param width1 Width of the second frame in pixel, with range [tPatchSize/2, infinity)
116 * @param height1 Height of the second frame in pixel, with range [tPatchSize/2, infinity)
117 * @param position0 The position in the first frame, with range [0, width - 1]x[0, height - 1]
118 * @param radiusX The search radius in horizontal direction, in pixel, with range [0, width - 1]
119 * @param radiusY The search radius in vertical direction, in pixel, with range [0, height - 1]
120 * @param frame0PaddingElements The number of padding elements at the end of each row of the first frame, in elements, with range [0, infinity)
121 * @param frame1PaddingElements The number of padding elements at the end of each row of the second frame, in elements, with range [0, infinity)
122 * @param rough1 The optional rough guess of the point in the second frame, an invalid position if unknown
123 * @param metricResult Optional resulting matching quality of the applied metric, nullptr if the result does not matter
124 * @param metricIdentityResult Optional resulting matching quality of the applied metric between both frames at the identity location (the previous and rough position), nullptr if the result does not matter
125 * @return Best matching position in the second frame
126 * @tparam tChannels The number of frame channels, with range [1u, infinity)
127 * @tparam tPatchSize The size of the square patch (the edge length) in pixel, with range [3, infinity), must be odd, recommended is 5, 7, 15, 31, or 63
128 */
129 template <unsigned int tChannels, unsigned int tPatchSize>
130 static PixelPosition pointMotionInFrameMirroredBorder(const uint8_t* const frame0, const uint8_t* const frame1, const unsigned int width0, const unsigned int height0, const unsigned int width1, const unsigned int height1, const PixelPosition& position0, const unsigned int radiusX, const unsigned int radiusY, const unsigned int frame0PaddingElements, const unsigned int frame1PaddingElements, const PixelPosition& rough1 = PixelPosition(), uint32_t* const metricResult = nullptr, uint32_t* const metricIdentityResult = nullptr);
131
132 /**
133 * Determines the motion for one given point between two frames by application of an image patch.
134 * Patch pixels outside the frame are mirrored into the frame before comparison.
135 * @param frame0 The first frame, must be valid
136 * @param frame1 The second frame, must be valid
137 * @param channels The number of frame channels, with range [1, 4]
138 * @param width0 Width of the first frame in pixel, with range [tPatchSize/2, infinity)
139 * @param height0 Height of the first frame in pixel, with range [tPatchSize/2, infinity)
140 * @param width1 Width of the second frame in pixel, with range [tPatchSize/2, infinity)
141 * @param height1 Height of the second frame in pixel, with range [tPatchSize/2, infinity)
142 * @param position0 The position in the first frame, with range [0, width - 1]x[0, height - 1]
143 * @param radiusX The search radius in horizontal direction, in pixel, with range [0, width - 1]
144 * @param radiusY The search radius in vertical direction, in pixel, with range [0, height - 1]
145 * @param frame0PaddingElements The number of padding elements at the end of each row of the first frame, in elements, with range [0, infinity)
146 * @param frame1PaddingElements The number of padding elements at the end of each row of the second frame, in elements, with range [0, infinity)
147 * @param rough1 The optional rough guess of the point in the second frame, an invalid position if unknown
148 * @param metricResult Optional resulting matching quality of the applied metric, nullptr if the result does not matter
149 * @param metricIdentityResult Optional resulting matching quality of the applied metric between both frames at the identity location (the previous and rough position), nullptr if the result does not matter
150 * @return Best matching position in the second frame
151 * @tparam tPatchSize The size of the square patch (the edge length) in pixel, with range [3, infinity), must be odd, recommended is 5, 7, 15, 31, or 63
152 */
153 template <unsigned int tPatchSize>
154 static inline PixelPosition pointMotionInFrameMirroredBorder(const uint8_t* const frame0, const uint8_t* const frame1, const unsigned int channels, const unsigned int width0, const unsigned int height0, const unsigned int width1, const unsigned int height1, const PixelPosition& position0, const unsigned int radiusX, const unsigned int radiusY, const unsigned int frame0PaddingElements, const unsigned int frame1PaddingElements, const PixelPosition& rough1 = PixelPosition(), uint32_t* const metricResult = nullptr, uint32_t* const metricIdentityResult = nullptr);
155
156 protected:
157
158 /**
159 * Tracks a subset of given points between two frame pyramids.
160 * The points are tracked unidirectional (from the previous frame to the current frame).<br>
161 * If a point is near the frame border, a mirrored image patch is applied.<br>
162 * @param previousPyramid Previous frame pyramid
163 * @param currentPyramid Current frame pyramid, with same frame type as the previous frame
164 * @param numberLayers The number of pyramid layers that will be used for tracking, with range [1, min(pyramids->layers(), coarsest layer that match with the patch size)]
165 * @param previousPoints A set of points that are located in the previous frame
166 * @param roughPoints The rough points in the current frame (if known), otherwise the prevousPoints may be provided
167 * @param currentPoints Resulting current points, that have been tracking between the two points
168 * @param coarsestLayerRadiusX The search radius on the coarsest pyramid layer in horizontal direction, in pixel, with range [0, infinity)
169 * @param coarsestLayerRadiusY The search radius on the coarsest pyramid layer in vertical direction, in pixel, with range [0, infinity)
170 * @param metricResults Optional resulting results of the applied metric, nullptr if the results do not matter
171 * @param metricIdentityResults Optional resulting results of the applied metric in both frames at the same previous position, nullptr if the results do not matter
172 * @param firstPoint The first point to be handled, with range [0, numberPoints - 1]
173 * @param numberPoints The number of points to handled, with range [1, infinity)
174 * @tparam tPatchSize The size of the square patch (the edge length) in pixel, with range [3, infinity), must be odd, recommended is 5, 7, 15, 31, or 63
175 */
176 template <unsigned int tPatchSize>
177 static void trackPointsInPyramidMirroredBorderSubset(const FramePyramid* previousPyramid, const FramePyramid* currentPyramid, const unsigned int numberLayers, const PixelPositions* previousPoints, const PixelPositions* roughPoints, PixelPositions* currentPoints, const unsigned int coarsestLayerRadiusX, const unsigned int coarsestLayerRadiusY, uint32_t* metricResults, uint32_t* metricIdentityResults, const unsigned int firstPoint, const unsigned int numberPoints);
178};
179
180template <typename TMetric>
181template <unsigned int tPatchSize>
182bool MotionT<TMetric>::trackPointsInPyramidMirroredBorder(const Frame& previousFrame, const Frame& currentFrame, const PixelPositions& previousPoints, const PixelPositions& roughPoints, PixelPositions& currentPoints, const unsigned int maximalOffset, const unsigned int coarsestLayerRadiusX, const unsigned int coarsestLayerRadiusY, const FramePyramid::DownsamplingMode downsamplingMode, Worker* worker, std::vector<uint32_t>* metricResults, std::vector<uint32_t>* metricIdentityResults)
183{
184 static_assert(tPatchSize % 2u == 1u, "Invalid image patch size, must be odd!");
185 static_assert(tPatchSize >= 3u, "Invalid image patch size!");
186
187 ocean_assert(previousFrame && currentFrame);
188
189 ocean_assert(previousFrame.frameType().pixelFormat() == currentFrame.frameType().pixelFormat());
190 ocean_assert(previousFrame.frameType().pixelOrigin() == currentFrame.frameType().pixelOrigin());
191
192 ocean_assert(previousPoints.size() == roughPoints.size());
193
194 const unsigned int idealLayers = FramePyramid::idealLayers(previousFrame.width(), previousFrame.height(), (tPatchSize / 2u) * 4u, (tPatchSize / 2u) * 4u, 2u, maximalOffset);
195
196 if (idealLayers == 0u)
197 {
198 return false;
199 }
200
201 const FramePyramid previousPyramid(previousFrame, downsamplingMode, idealLayers, false /*copyFirstLayer*/, worker);
202 const FramePyramid currentPyramid(currentFrame, downsamplingMode, idealLayers, false /*copyFirstLayer*/, worker);
203
204 return trackPointsInPyramidMirroredBorder<tPatchSize>(previousPyramid, currentPyramid, previousPoints, roughPoints, currentPoints, coarsestLayerRadiusX, coarsestLayerRadiusY, worker, metricResults, metricIdentityResults);
205}
206
207template <typename TMetric>
208template <unsigned int tPatchSize>
209bool MotionT<TMetric>::trackPointsInPyramidMirroredBorder(const FramePyramid& previousPyramid, const FramePyramid& currentPyramid, const PixelPositions& previousPoints, const PixelPositions& roughPoints, PixelPositions& currentPoints, const unsigned int coarsestLayerRadiusX, const unsigned int coarsestLayerRadiusY, Worker* worker, std::vector<uint32_t>* metricResults, std::vector<uint32_t>* metricIdentityResults)
210{
211 static_assert(tPatchSize % 2u == 1u, "Invalid image patch size, must be odd!");
212 static_assert(tPatchSize >= 3u, "Invalid image patch size, must be larger than 2!");
213
214 ocean_assert(previousPyramid.frameType().pixelFormat() == currentPyramid.frameType().pixelFormat());
215 ocean_assert(previousPyramid.frameType().pixelOrigin() == currentPyramid.frameType().pixelOrigin());
216
217 const unsigned int idealLayers = CV::FramePyramid::idealLayers(previousPyramid.finestWidth(), previousPyramid.finestHeight(), (tPatchSize / 2u) * 4u, (tPatchSize / 2u) * 4u, 2u);
218 const unsigned int numberLayers = std::min(std::min(previousPyramid.layers(), currentPyramid.layers()), idealLayers);
219
220 if (numberLayers == 0u)
221 {
222 return false;
223 }
224
225 currentPoints.resize(previousPoints.size());
226
227 if (metricResults != nullptr)
228 {
229 metricResults->resize(previousPoints.size());
230 }
231
232 if (metricIdentityResults != nullptr)
233 {
234 metricIdentityResults->resize(previousPoints.size());
235 }
236
237 if (worker != nullptr)
238 {
239 worker->executeFunction(Worker::Function::createStatic(&MotionT::trackPointsInPyramidMirroredBorderSubset<tPatchSize>, &previousPyramid, &currentPyramid, numberLayers, &previousPoints, &roughPoints, &currentPoints, coarsestLayerRadiusX, coarsestLayerRadiusY, metricResults ? metricResults->data() : nullptr, metricIdentityResults ? metricIdentityResults->data() : nullptr, 0u, 0u), 0u, (unsigned int)(previousPoints.size()));
240 }
241 else
242 {
243 trackPointsInPyramidMirroredBorderSubset<tPatchSize>(&previousPyramid, &currentPyramid, numberLayers, &previousPoints, &roughPoints, &currentPoints, coarsestLayerRadiusX, coarsestLayerRadiusY, metricResults ? metricResults->data() : nullptr, metricIdentityResults ? metricIdentityResults->data() : nullptr, 0u, (unsigned int)(previousPoints.size()));
244 }
245
246 return true;
247}
248
249template <typename TMetric>
250template <unsigned int tChannels, unsigned int tPatchSize>
251PixelPosition MotionT<TMetric>::pointMotionInFrameMirroredBorder(const uint8_t* const frame0, const uint8_t* const frame1, const unsigned int width0, const unsigned int height0, const unsigned int width1, const unsigned int height1, const PixelPosition& position0, const unsigned int radiusX, const unsigned int radiusY, const unsigned int frame0PaddingElements, const unsigned int frame1PaddingElements, const PixelPosition& rough1, uint32_t* const metricResult, uint32_t* const metricIdentityResult)
252{
253 static_assert(tChannels != 0u, "Invalid number of data channels!");
254 static_assert(tPatchSize % 2u == 1u, "Invalid size of the image patch, must be odd!");
255
256 constexpr unsigned int tPatchSize_2 = tPatchSize / 2u;
257
258 ocean_assert(frame0 != nullptr && frame1 != nullptr);
259 ocean_assert(radiusX != 0u || radiusY != 0u);
260
261 ocean_assert(width0 >= tPatchSize_2 && height0 >= tPatchSize_2);
262 ocean_assert(width1 >= tPatchSize_2 && height1 >= tPatchSize_2);
263
264 ocean_assert(position0.x() < width0);
265 ocean_assert(position0.y() < height0);
266
267 const PixelPosition position1((rough1 && rough1.x() < width1 && rough1.y() < height1) ? rough1 : position0);
268 ocean_assert(position1.x() < width1);
269 ocean_assert(position1.y() < height1);
270
271 const unsigned int leftCenter1 = (unsigned int)(max(0, int(position1.x() - radiusX)));
272 const unsigned int topCenter1 = (unsigned int)(max(0, int(position1.y() - radiusY)));
273
274 const unsigned int rightCenter1 = min(position1.x() + radiusX, width1 - 1u);
275 const unsigned int bottomCenter1 = min(position1.y() + radiusY, height1 - 1u);
276
277 ocean_assert(leftCenter1 < width1 && leftCenter1 <= rightCenter1 && rightCenter1 < width1);
278 ocean_assert(topCenter1 < height1 && topCenter1 <= bottomCenter1 && bottomCenter1 < height1);
279
280 PixelPosition bestPosition;
281 uint32_t bestMetric = uint32_t(-1);
282 uint32_t bestSqrDistance = uint32_t(-1);
283
284 // check whether position0 is entirely inside the frame (including the patch with size tPatchSize x tPatchSize)
285 if ((position0.x() >= tPatchSize_2 && position0.y() >= tPatchSize_2 && position0.x() + tPatchSize_2 < width0 && position0.y() + tPatchSize_2 < height0))
286 {
287 for (unsigned int y1 = topCenter1; y1 <= bottomCenter1; ++y1)
288 {
289 for (unsigned int x1 = leftCenter1; x1 <= rightCenter1; ++x1)
290 {
291 // check whether we can use the fast metric function
292
293 const uint32_t metric = (x1 - tPatchSize_2 < width1 - (tPatchSize - 1u) && y1 - tPatchSize_2 < height1 - (tPatchSize - 1u)) ?
294 TMetric::template patch8BitPerChannel<tChannels, tPatchSize>(frame0, frame1, width0, width1, position0.x(), position0.y(), x1, y1, frame0PaddingElements, frame1PaddingElements) :
295 TMetric::template patchMirroredBorder8BitPerChannel<tChannels, tPatchSize>(frame0, frame1, width0, height0, width1, height1, position0.x(), position0.y(), x1, y1, frame0PaddingElements, frame1PaddingElements);
296
297 const PixelPosition position(x1, y1);
298
299 if (metric < bestMetric || (metric == bestMetric && position1.sqrDistance(position) < bestSqrDistance))
300 {
301 bestMetric = metric;
302 bestPosition = position;
303
304 bestSqrDistance = position1.sqrDistance(position);
305 }
306
307 if (metricIdentityResult && x1 == position1.x() && y1 == position1.y())
308 {
309 *metricIdentityResult = metric;
310 }
311 }
312 }
313 }
314 else
315 {
316 for (unsigned int y1 = topCenter1; y1 <= bottomCenter1; ++y1)
317 {
318 for (unsigned int x1 = leftCenter1; x1 <= rightCenter1; ++x1)
319 {
320 const uint32_t metric = TMetric::template patchMirroredBorder8BitPerChannel<tChannels, tPatchSize>(frame0, frame1, width0, height0, width1, height1, position0.x(), position0.y(), x1, y1, frame0PaddingElements, frame1PaddingElements);
321
322 const PixelPosition position(x1, y1);
323
324 if (metric < bestMetric || (metric == bestMetric && position1.sqrDistance(position) < bestSqrDistance))
325 {
326 bestMetric = metric;
327 bestPosition = position;
328
329 bestSqrDistance = position1.sqrDistance(position);
330 }
331
332 if (metricIdentityResult && x1 == position1.x() && y1 == position1.y())
333 {
334 *metricIdentityResult = metric;
335 }
336 }
337 }
338 }
339
340 ocean_assert(bestMetric != uint32_t(-1) && bestPosition.isValid());
341
342 if (metricResult)
343 {
344 *metricResult = bestMetric;
345 }
346
347 ocean_assert(abs(int(bestPosition.x()) - int(position1.x())) <= int(radiusX));
348 ocean_assert(abs(int(bestPosition.y()) - int(position1.y())) <= int(radiusY));
349
350 return bestPosition;
351}
352
353template <typename TMetric>
354template <unsigned int tPatchSize>
355inline PixelPosition MotionT<TMetric>::pointMotionInFrameMirroredBorder(const uint8_t* const frame0, const uint8_t* const frame1, const unsigned int channels, const unsigned int width0, const unsigned int height0, const unsigned int width1, const unsigned int height1, const PixelPosition& position0, const unsigned int radiusX, const unsigned int radiusY, const unsigned int frame0PaddingElements, const unsigned int frame1PaddingElements, const PixelPosition& rough1, uint32_t* const metricResult, uint32_t* const metricIdentityResult)
356{
357 ocean_assert(channels >= 1u);
358
359 switch (channels)
360 {
361 case 1u:
362 return pointMotionInFrameMirroredBorder<1u, tPatchSize>(frame0, frame1, width0, height0, width1, height1, position0, radiusX, radiusY, frame0PaddingElements, frame1PaddingElements, rough1, metricResult, metricIdentityResult);
363
364 case 2u:
365 return pointMotionInFrameMirroredBorder<2u, tPatchSize>(frame0, frame1, width0, height0, width1, height1, position0, radiusX, radiusY, frame0PaddingElements, frame1PaddingElements, rough1, metricResult, metricIdentityResult);
366
367 case 3u:
368 return pointMotionInFrameMirroredBorder<3u, tPatchSize>(frame0, frame1, width0, height0, width1, height1, position0, radiusX, radiusY, frame0PaddingElements, frame1PaddingElements, rough1, metricResult, metricIdentityResult);
369
370 case 4u:
371 return pointMotionInFrameMirroredBorder<4u, tPatchSize>(frame0, frame1, width0, height0, width1, height1, position0, radiusX, radiusY, frame0PaddingElements, frame1PaddingElements, rough1, metricResult, metricIdentityResult);
372 }
373
374 ocean_assert(false && "Invalid pixel format!");
375 return rough1;
376}
377
378template <typename TMetric>
379template <unsigned int tPatchSize>
380void MotionT<TMetric>::trackPointsInPyramidMirroredBorderSubset(const FramePyramid* previousPyramid, const FramePyramid* currentPyramid, const unsigned int numberLayers, const PixelPositions* previousPoints, const PixelPositions* roughPoints, PixelPositions* currentPoints, const unsigned int coarsestLayerRadiusX, const unsigned int coarsestLayerRadiusY, uint32_t* metricResults, uint32_t* metricIdentityResults, const unsigned int firstPoint, const unsigned int numberPoints)
381{
382 static_assert(tPatchSize % 2u == 1u, "Invalid image patch size!");
383 static_assert(tPatchSize >= 3u, "Invalid image patch size!");
384
385 ocean_assert(previousPyramid && currentPyramid);
386 ocean_assert(previousPoints && roughPoints && currentPoints);
387
388 ocean_assert(*previousPyramid && *currentPyramid);
389
390 ocean_assert(previousPyramid->frameType().pixelFormat() == currentPyramid->frameType().pixelFormat());
391 ocean_assert(previousPyramid->frameType().pixelOrigin() == currentPyramid->frameType().pixelOrigin());
392
393 ocean_assert(previousPyramid->layers() >= 1u && currentPyramid->layers() >= 1u);
394
395 ocean_assert(previousPoints->size() == roughPoints->size());
396 ocean_assert(currentPoints->size() == previousPoints->size());
397
398 ocean_assert(coarsestLayerRadiusX != 0u || coarsestLayerRadiusY != 0u);
399
400 ocean_assert(firstPoint + numberPoints <= previousPoints->size());
401
402 ocean_assert(numberLayers >= 1u);
403 ocean_assert(numberLayers <= previousPyramid->layers());
404 ocean_assert(numberLayers <= currentPyramid->layers());
405
406 ocean_assert(previousPyramid->layer(numberLayers - 1u).width() >= tPatchSize / 2u);
407 ocean_assert(previousPyramid->layer(numberLayers - 1u).height() >= tPatchSize / 2u);
408
409 ShiftVector<PixelPosition> intermediateRoughPoints(firstPoint, numberPoints);
410
411 const unsigned int lowestCurrentWidth = currentPyramid->layer(numberLayers - 1u).width();
412 const unsigned int lowestCurrentHeight = currentPyramid->layer(numberLayers - 1u).height();
413 const unsigned int lowestLayerFactor = currentPyramid->sizeFactor(numberLayers - 1u);
414 ocean_assert(lowestCurrentWidth >= 1u && lowestCurrentHeight >= 1u);
415
416 const unsigned int channels = previousPyramid->frameType().channels();
417 ocean_assert(channels >= 1u && channels <= 4u);
418
419 for (unsigned int n = firstPoint; n < firstPoint + numberPoints; ++n)
420 {
421 const PixelPosition& roughPoint = (*roughPoints)[n];
422
423 const unsigned int x = min((roughPoint.x() + lowestLayerFactor / 2u) / lowestLayerFactor, lowestCurrentWidth - 1u);
424 const unsigned int y = min((roughPoint.y() + lowestLayerFactor / 2u) / lowestLayerFactor, lowestCurrentHeight - 1u);
425
426 intermediateRoughPoints[n] = PixelPosition(x, y);
427 }
428
429 unsigned int layerRadiusX = coarsestLayerRadiusX;
430 unsigned int layerRadiusY = coarsestLayerRadiusY;
431
432 for (unsigned int layerIndex = numberLayers - 1u; layerIndex < numberLayers; --layerIndex)
433 {
434 const Frame& previousFrame = (*previousPyramid)[layerIndex];
435 const Frame& currentFrame = (*currentPyramid)[layerIndex];
436
437 const unsigned int previousWidth = previousFrame.width();
438 const unsigned int previousHeight = previousFrame.height();
439
440 const unsigned int currentWidth = currentFrame.width();
441 const unsigned int currentHeight = currentFrame.height();
442
443 for (unsigned int i = firstPoint; i < firstPoint + numberPoints; ++i)
444 {
445 ocean_assert(intermediateRoughPoints[i].x() < currentWidth && intermediateRoughPoints[i].y() < currentHeight);
446
447 PixelPosition& intermediateRoughPoint = intermediateRoughPoints[i];
448
449 uint32_t* const metricResult = metricResults ? metricResults + i : nullptr;
450 uint32_t* const metricIdentityResult = (layerIndex == 0u && metricIdentityResults) ? metricIdentityResults + i : nullptr;
451
452 ocean_assert(layerIndex < 31u);
453 const unsigned int layerFactor = 1u << layerIndex;
454
455 const PixelPosition previousPosition(min(((*previousPoints)[i].x() + layerFactor / 2u) / layerFactor, previousWidth - 1u), min(((*previousPoints)[i].y() + layerFactor / 2u) / layerFactor, previousHeight - 1u));
456
457 if (previousPosition.x() < previousWidth && previousPosition.y() < previousHeight)
458 {
459 const PixelPosition position(pointMotionInFrameMirroredBorder<tPatchSize>(previousFrame.constdata<uint8_t>(), currentFrame.constdata<uint8_t>(), channels, previousWidth, previousHeight, currentWidth, currentHeight, previousPosition, layerRadiusX, layerRadiusY, previousFrame.paddingElements(), currentFrame.paddingElements(), intermediateRoughPoint, metricResult, metricIdentityResult));
460
461 ocean_assert(position.x() < currentWidth && position.y() < currentHeight);
462
463 // if we are back on the finest layer, than we store the tracked point as final result
464 if (layerIndex == 0u)
465 {
466 ocean_assert(i < currentPoints->size());
467 (*currentPoints)[i] = position;
468 }
469 else
470 {
471 // we store the tracked point as rough intermediate point for the next finer layer
472 const unsigned int higherWidth = currentPyramid->layer(layerIndex - 1u).width();
473 const unsigned int higherHeight = currentPyramid->layer(layerIndex - 1u).height();
474
475 intermediateRoughPoint = PixelPosition(min(position.x() * 2u, higherWidth - 1u), min(position.y() * 2u, higherHeight - 1u));
476 }
477 }
478 else
479 {
480 // if we are back on the finest layer, than we store the rough point as final result, otherwise we guess the rough intermediate point for the next layer
481 if (layerIndex == 0u)
482 {
483 ocean_assert(i < currentPoints->size());
484 (*currentPoints)[i] = intermediateRoughPoint;
485 }
486 else
487 {
488 intermediateRoughPoint = PixelPosition((intermediateRoughPoint.x() * 2u + layerFactor / 2u) / layerFactor, (intermediateRoughPoint.y() * 2u + layerFactor / 2u) / layerFactor);
489 }
490 }
491 }
492
493 // all layers expect the coarsest layer will apply a search radius of 2 pixels (a search region of 5x5)
494
495 layerRadiusX = 2u;
496 layerRadiusY = 2u;
497 }
498}
499
500}
501
502}
503
504#endif // META_OCEAN_CV_MOTION_H
This class implements a frame pyramid.
Definition FramePyramid.h:46
static unsigned int idealLayers(const unsigned int width, const unsigned int height, const unsigned int invalidCoarsestWidthOrHeight, unsigned int *coarsestLayerWidth=nullptr, unsigned int *coarsestLayerHeight=nullptr)
Determines the number of layers until an invalid frame size would be reached in the next layer.
unsigned int finestWidth() const
Returns the width of the finest (first) layer.
Definition FramePyramid.h:828
DownsamplingMode
Definition of individual down sampling modes.
Definition FramePyramid.h:53
@ DM_FILTER_14641
Down sampling is realized by a 5x5 Gaussian filter.
Definition FramePyramid.h:81
static constexpr unsigned int sizeFactor(const unsigned int layerIndex)
Returns the size factor of a specified layer in relation to the finest layer.
Definition FramePyramid.h:884
unsigned int layers() const
Returns the number of layers this pyramid holds.
Definition FramePyramid.h:811
const FrameType & frameType() const
Returns the frame type of the finest layer.
Definition FramePyramid.h:861
unsigned int finestHeight() const
Returns the height of the finest (first) layer.
Definition FramePyramid.h:834
const Frame & layer(const unsigned int layer) const
Returns the frame of a specified layer.
Definition FramePyramid.h:773
This class implements patch-based motion techniques.
Definition Motion.h:60
static void trackPointsInPyramidMirroredBorderSubset(const FramePyramid *previousPyramid, const FramePyramid *currentPyramid, const unsigned int numberLayers, const PixelPositions *previousPoints, const PixelPositions *roughPoints, PixelPositions *currentPoints, const unsigned int coarsestLayerRadiusX, const unsigned int coarsestLayerRadiusY, uint32_t *metricResults, uint32_t *metricIdentityResults, const unsigned int firstPoint, const unsigned int numberPoints)
Tracks a subset of given points between two frame pyramids.
Definition Motion.h:380
static PixelPosition pointMotionInFrameMirroredBorder(const uint8_t *const frame0, const uint8_t *const frame1, const unsigned int width0, const unsigned int height0, const unsigned int width1, const unsigned int height1, const PixelPosition &position0, const unsigned int radiusX, const unsigned int radiusY, const unsigned int frame0PaddingElements, const unsigned int frame1PaddingElements, const PixelPosition &rough1=PixelPosition(), uint32_t *const metricResult=nullptr, uint32_t *const metricIdentityResult=nullptr)
Determines the motion for one given point between two frames by application of an image patch.
Definition Motion.h:251
static bool trackPointsInPyramidMirroredBorder(const Frame &previousFrame, const Frame &currentFrame, const PixelPositions &previousPoints, const PixelPositions &roughPoints, PixelPositions &currentPoints, const unsigned int maximalOffset, const unsigned int coarsestLayerRadiusX, const unsigned int coarsestLayerRadiusY, const FramePyramid::DownsamplingMode downsamplingMode=FramePyramid::DM_FILTER_14641, Worker *worker=nullptr, std::vector< uint32_t > *metricResults=nullptr, std::vector< uint32_t > *metricIdentityResults=nullptr)
Tracks a set of given points between two frames with pixel accuracy.
Definition Motion.h:182
bool isValid() const
Returns whether this pixel position object holds two valid parameters.
T y() const
Returns the vertical coordinate position of this object.
Definition PixelPosition.h:468
unsigned int sqrDistance(const PixelPositionT< T > &position) const
Returns the square difference between two pixel positions.
Definition PixelPosition.h:487
T x() const
Returns the horizontal coordinate position of this object.
Definition PixelPosition.h:456
static Caller< void > createStatic(typename StaticFunctionPointerMaker< void, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass >::Type function)
Creates a new caller container for a static function with no function parameter.
Definition Caller.h:2877
This class implements Ocean's image class.
Definition Frame.h:1879
const T * constdata(const unsigned int planeIndex=0u) const
Returns a pointer to the read-only pixel data of a specific plane.
Definition Frame.h:4332
const FrameType & frameType() const
Returns the frame type of this frame.
Definition Frame.h:3936
unsigned int paddingElements(const unsigned int planeIndex=0u) const
Returns the optional number of padding elements at the end of each row for a specific plane.
Definition Frame.h:4206
unsigned int width() const
Returns the width of the frame format in pixel.
Definition Frame.h:3241
PixelOrigin pixelOrigin() const
Returns the pixel origin of the frame.
Definition Frame.h:3286
PixelFormat pixelFormat() const
Returns the pixel format of the frame.
Definition Frame.h:3251
unsigned int height() const
Returns the height of the frame in pixel.
Definition Frame.h:3246
unsigned int channels() const
Returns the number of individual channels the frame has.
Definition Frame.h:3271
This class implements a vector with shifted elements.
Definition ShiftVector.h:27
This class implements a worker able to distribute function calls over different threads.
Definition Worker.h:33
bool executeFunction(const Function &function, const unsigned int first, const unsigned int size, const unsigned int firstIndex=(unsigned int)(-1), const unsigned int sizeIndex=(unsigned int)(-1), const unsigned int minimalIterations=1u, const unsigned int threadIndex=(unsigned int)(-1))
Executes a callback function separable by two function parameters.
std::vector< PixelPosition > PixelPositions
Definition of a vector holding pixel positions (with positive coordinate values).
Definition PixelPosition.h:46
PixelPositionT< unsigned int > PixelPosition
Definition of the default PixelPosition object with a data type allowing only positive coordinate val...
Definition PixelPosition.h:32
The namespace covering the entire Ocean framework.
Definition Accessor.h:15