1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
8 //
9 //
10 // License Agreement
11 // For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15 // Third party copyrights are property of their respective owners.
16 //
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
19 //
20 // * Redistribution's of source code must retain the above copyright notice,
21 // this list of conditions and the following disclaimer.
22 //
23 // * Redistribution's in binary form must reproduce the above copyright notice,
24 // this list of conditions and the following disclaimer in the documentation
25 // and/or other materials provided with the distribution.
26 //
27 // * The name of the copyright holders may not be used to endorse or promote products
28 // derived from this software without specific prior written permission.
29 //
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
40 //
41 //M*/
42
43 #include "precomp.hpp"
44
45 using namespace cv;
46 using namespace cv::cuda;
47
48 #if !defined (HAVE_CUDA) || defined (CUDA_DISABLER)
49
create(Size,int,int,bool)50 Ptr<SparsePyrLKOpticalFlow> cv::cuda::SparsePyrLKOpticalFlow::create(Size, int, int, bool) { throw_no_cuda(); return Ptr<SparsePyrLKOpticalFlow>(); }
51
create(Size,int,int,bool)52 Ptr<DensePyrLKOpticalFlow> cv::cuda::DensePyrLKOpticalFlow::create(Size, int, int, bool) { throw_no_cuda(); return Ptr<SparsePyrLKOpticalFlow>(); }
53
54 #else /* !defined (HAVE_CUDA) */
55
56 namespace pyrlk
57 {
58 void loadConstants(int2 winSize, int iters, cudaStream_t stream);
59
60 void sparse1(PtrStepSzf I, PtrStepSzf J, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount,
61 int level, dim3 block, dim3 patch, cudaStream_t stream);
62 void sparse4(PtrStepSz<float4> I, PtrStepSz<float4> J, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount,
63 int level, dim3 block, dim3 patch, cudaStream_t stream);
64
65 void dense(PtrStepSzb I, PtrStepSzf J, PtrStepSzf u, PtrStepSzf v, PtrStepSzf prevU, PtrStepSzf prevV,
66 PtrStepSzf err, int2 winSize, cudaStream_t stream);
67 }
68
69 namespace
70 {
71 class PyrLKOpticalFlowBase
72 {
73 public:
74 PyrLKOpticalFlowBase(Size winSize, int maxLevel, int iters, bool useInitialFlow);
75
76 void sparse(const GpuMat& prevImg, const GpuMat& nextImg, const GpuMat& prevPts, GpuMat& nextPts,
77 GpuMat& status, GpuMat* err, Stream& stream);
78
79 void dense(const GpuMat& prevImg, const GpuMat& nextImg, GpuMat& u, GpuMat& v, Stream& stream);
80
81 protected:
82 Size winSize_;
83 int maxLevel_;
84 int iters_;
85 bool useInitialFlow_;
86
87 private:
88 std::vector<GpuMat> prevPyr_;
89 std::vector<GpuMat> nextPyr_;
90 };
91
PyrLKOpticalFlowBase(Size winSize,int maxLevel,int iters,bool useInitialFlow)92 PyrLKOpticalFlowBase::PyrLKOpticalFlowBase(Size winSize, int maxLevel, int iters, bool useInitialFlow) :
93 winSize_(winSize), maxLevel_(maxLevel), iters_(iters), useInitialFlow_(useInitialFlow)
94 {
95 }
96
calcPatchSize(Size winSize,dim3 & block,dim3 & patch)97 void calcPatchSize(Size winSize, dim3& block, dim3& patch)
98 {
99 if (winSize.width > 32 && winSize.width > 2 * winSize.height)
100 {
101 block.x = deviceSupports(FEATURE_SET_COMPUTE_12) ? 32 : 16;
102 block.y = 8;
103 }
104 else
105 {
106 block.x = 16;
107 block.y = deviceSupports(FEATURE_SET_COMPUTE_12) ? 16 : 8;
108 }
109
110 patch.x = (winSize.width + block.x - 1) / block.x;
111 patch.y = (winSize.height + block.y - 1) / block.y;
112
113 block.z = patch.z = 1;
114 }
115
sparse(const GpuMat & prevImg,const GpuMat & nextImg,const GpuMat & prevPts,GpuMat & nextPts,GpuMat & status,GpuMat * err,Stream & stream)116 void PyrLKOpticalFlowBase::sparse(const GpuMat& prevImg, const GpuMat& nextImg, const GpuMat& prevPts, GpuMat& nextPts, GpuMat& status, GpuMat* err, Stream& stream)
117 {
118 if (prevPts.empty())
119 {
120 nextPts.release();
121 status.release();
122 if (err) err->release();
123 return;
124 }
125
126 dim3 block, patch;
127 calcPatchSize(winSize_, block, patch);
128
129 CV_Assert( prevImg.channels() == 1 || prevImg.channels() == 3 || prevImg.channels() == 4 );
130 CV_Assert( prevImg.size() == nextImg.size() && prevImg.type() == nextImg.type() );
131 CV_Assert( maxLevel_ >= 0 );
132 CV_Assert( winSize_.width > 2 && winSize_.height > 2 );
133 CV_Assert( patch.x > 0 && patch.x < 6 && patch.y > 0 && patch.y < 6 );
134 CV_Assert( prevPts.rows == 1 && prevPts.type() == CV_32FC2 );
135
136 if (useInitialFlow_)
137 CV_Assert( nextPts.size() == prevPts.size() && nextPts.type() == prevPts.type() );
138 else
139 ensureSizeIsEnough(1, prevPts.cols, prevPts.type(), nextPts);
140
141 GpuMat temp1 = (useInitialFlow_ ? nextPts : prevPts).reshape(1);
142 GpuMat temp2 = nextPts.reshape(1);
143 cuda::multiply(temp1, Scalar::all(1.0 / (1 << maxLevel_) / 2.0), temp2, 1, -1, stream);
144
145 ensureSizeIsEnough(1, prevPts.cols, CV_8UC1, status);
146 status.setTo(Scalar::all(1), stream);
147
148 if (err)
149 ensureSizeIsEnough(1, prevPts.cols, CV_32FC1, *err);
150
151 // build the image pyramids.
152
153 BufferPool pool(stream);
154
155 prevPyr_.resize(maxLevel_ + 1);
156 nextPyr_.resize(maxLevel_ + 1);
157
158 int cn = prevImg.channels();
159
160 if (cn == 1 || cn == 4)
161 {
162 prevImg.convertTo(prevPyr_[0], CV_32F, stream);
163 nextImg.convertTo(nextPyr_[0], CV_32F, stream);
164 }
165 else
166 {
167 GpuMat buf = pool.getBuffer(prevImg.size(), CV_MAKE_TYPE(prevImg.depth(), 4));
168
169 cuda::cvtColor(prevImg, buf, COLOR_BGR2BGRA, 0, stream);
170 buf.convertTo(prevPyr_[0], CV_32F, stream);
171
172 cuda::cvtColor(nextImg, buf, COLOR_BGR2BGRA, 0, stream);
173 buf.convertTo(nextPyr_[0], CV_32F, stream);
174 }
175
176 for (int level = 1; level <= maxLevel_; ++level)
177 {
178 cuda::pyrDown(prevPyr_[level - 1], prevPyr_[level], stream);
179 cuda::pyrDown(nextPyr_[level - 1], nextPyr_[level], stream);
180 }
181
182 pyrlk::loadConstants(make_int2(winSize_.width, winSize_.height), iters_, StreamAccessor::getStream(stream));
183
184 for (int level = maxLevel_; level >= 0; level--)
185 {
186 if (cn == 1)
187 {
188 pyrlk::sparse1(prevPyr_[level], nextPyr_[level],
189 prevPts.ptr<float2>(), nextPts.ptr<float2>(),
190 status.ptr(),
191 level == 0 && err ? err->ptr<float>() : 0, prevPts.cols,
192 level, block, patch,
193 StreamAccessor::getStream(stream));
194 }
195 else
196 {
197 pyrlk::sparse4(prevPyr_[level], nextPyr_[level],
198 prevPts.ptr<float2>(), nextPts.ptr<float2>(),
199 status.ptr(),
200 level == 0 && err ? err->ptr<float>() : 0, prevPts.cols,
201 level, block, patch,
202 StreamAccessor::getStream(stream));
203 }
204 }
205 }
206
dense(const GpuMat & prevImg,const GpuMat & nextImg,GpuMat & u,GpuMat & v,Stream & stream)207 void PyrLKOpticalFlowBase::dense(const GpuMat& prevImg, const GpuMat& nextImg, GpuMat& u, GpuMat& v, Stream& stream)
208 {
209 CV_Assert( prevImg.type() == CV_8UC1 );
210 CV_Assert( prevImg.size() == nextImg.size() && prevImg.type() == nextImg.type() );
211 CV_Assert( maxLevel_ >= 0 );
212 CV_Assert( winSize_.width > 2 && winSize_.height > 2 );
213
214 // build the image pyramids.
215
216 prevPyr_.resize(maxLevel_ + 1);
217 nextPyr_.resize(maxLevel_ + 1);
218
219 prevPyr_[0] = prevImg;
220 nextImg.convertTo(nextPyr_[0], CV_32F, stream);
221
222 for (int level = 1; level <= maxLevel_; ++level)
223 {
224 cuda::pyrDown(prevPyr_[level - 1], prevPyr_[level], stream);
225 cuda::pyrDown(nextPyr_[level - 1], nextPyr_[level], stream);
226 }
227
228 BufferPool pool(stream);
229
230 GpuMat uPyr[] = {
231 pool.getBuffer(prevImg.size(), CV_32FC1),
232 pool.getBuffer(prevImg.size(), CV_32FC1),
233 };
234 GpuMat vPyr[] = {
235 pool.getBuffer(prevImg.size(), CV_32FC1),
236 pool.getBuffer(prevImg.size(), CV_32FC1),
237 };
238
239 uPyr[0].setTo(Scalar::all(0), stream);
240 vPyr[0].setTo(Scalar::all(0), stream);
241 uPyr[1].setTo(Scalar::all(0), stream);
242 vPyr[1].setTo(Scalar::all(0), stream);
243
244 int2 winSize2i = make_int2(winSize_.width, winSize_.height);
245 pyrlk::loadConstants(winSize2i, iters_, StreamAccessor::getStream(stream));
246
247 int idx = 0;
248
249 for (int level = maxLevel_; level >= 0; level--)
250 {
251 int idx2 = (idx + 1) & 1;
252
253 pyrlk::dense(prevPyr_[level], nextPyr_[level],
254 uPyr[idx], vPyr[idx], uPyr[idx2], vPyr[idx2],
255 PtrStepSzf(), winSize2i,
256 StreamAccessor::getStream(stream));
257
258 if (level > 0)
259 idx = idx2;
260 }
261
262 uPyr[idx].copyTo(u, stream);
263 vPyr[idx].copyTo(v, stream);
264 }
265
266 class SparsePyrLKOpticalFlowImpl : public SparsePyrLKOpticalFlow, private PyrLKOpticalFlowBase
267 {
268 public:
SparsePyrLKOpticalFlowImpl(Size winSize,int maxLevel,int iters,bool useInitialFlow)269 SparsePyrLKOpticalFlowImpl(Size winSize, int maxLevel, int iters, bool useInitialFlow) :
270 PyrLKOpticalFlowBase(winSize, maxLevel, iters, useInitialFlow)
271 {
272 }
273
getWinSize() const274 virtual Size getWinSize() const { return winSize_; }
setWinSize(Size winSize)275 virtual void setWinSize(Size winSize) { winSize_ = winSize; }
276
getMaxLevel() const277 virtual int getMaxLevel() const { return maxLevel_; }
setMaxLevel(int maxLevel)278 virtual void setMaxLevel(int maxLevel) { maxLevel_ = maxLevel; }
279
getNumIters() const280 virtual int getNumIters() const { return iters_; }
setNumIters(int iters)281 virtual void setNumIters(int iters) { iters_ = iters; }
282
getUseInitialFlow() const283 virtual bool getUseInitialFlow() const { return useInitialFlow_; }
setUseInitialFlow(bool useInitialFlow)284 virtual void setUseInitialFlow(bool useInitialFlow) { useInitialFlow_ = useInitialFlow; }
285
calc(InputArray _prevImg,InputArray _nextImg,InputArray _prevPts,InputOutputArray _nextPts,OutputArray _status,OutputArray _err,Stream & stream)286 virtual void calc(InputArray _prevImg, InputArray _nextImg,
287 InputArray _prevPts, InputOutputArray _nextPts,
288 OutputArray _status,
289 OutputArray _err,
290 Stream& stream)
291 {
292 const GpuMat prevImg = _prevImg.getGpuMat();
293 const GpuMat nextImg = _nextImg.getGpuMat();
294 const GpuMat prevPts = _prevPts.getGpuMat();
295 GpuMat& nextPts = _nextPts.getGpuMatRef();
296 GpuMat& status = _status.getGpuMatRef();
297 GpuMat* err = _err.needed() ? &(_err.getGpuMatRef()) : NULL;
298
299 sparse(prevImg, nextImg, prevPts, nextPts, status, err, stream);
300 }
301 };
302
303 class DensePyrLKOpticalFlowImpl : public DensePyrLKOpticalFlow, private PyrLKOpticalFlowBase
304 {
305 public:
DensePyrLKOpticalFlowImpl(Size winSize,int maxLevel,int iters,bool useInitialFlow)306 DensePyrLKOpticalFlowImpl(Size winSize, int maxLevel, int iters, bool useInitialFlow) :
307 PyrLKOpticalFlowBase(winSize, maxLevel, iters, useInitialFlow)
308 {
309 }
310
getWinSize() const311 virtual Size getWinSize() const { return winSize_; }
setWinSize(Size winSize)312 virtual void setWinSize(Size winSize) { winSize_ = winSize; }
313
getMaxLevel() const314 virtual int getMaxLevel() const { return maxLevel_; }
setMaxLevel(int maxLevel)315 virtual void setMaxLevel(int maxLevel) { maxLevel_ = maxLevel; }
316
getNumIters() const317 virtual int getNumIters() const { return iters_; }
setNumIters(int iters)318 virtual void setNumIters(int iters) { iters_ = iters; }
319
getUseInitialFlow() const320 virtual bool getUseInitialFlow() const { return useInitialFlow_; }
setUseInitialFlow(bool useInitialFlow)321 virtual void setUseInitialFlow(bool useInitialFlow) { useInitialFlow_ = useInitialFlow; }
322
calc(InputArray _prevImg,InputArray _nextImg,InputOutputArray _flow,Stream & stream)323 virtual void calc(InputArray _prevImg, InputArray _nextImg, InputOutputArray _flow, Stream& stream)
324 {
325 const GpuMat prevImg = _prevImg.getGpuMat();
326 const GpuMat nextImg = _nextImg.getGpuMat();
327
328 BufferPool pool(stream);
329 GpuMat u = pool.getBuffer(prevImg.size(), CV_32FC1);
330 GpuMat v = pool.getBuffer(prevImg.size(), CV_32FC1);
331
332 dense(prevImg, nextImg, u, v, stream);
333
334 GpuMat flows[] = {u, v};
335 cuda::merge(flows, 2, _flow, stream);
336 }
337 };
338 }
339
create(Size winSize,int maxLevel,int iters,bool useInitialFlow)340 Ptr<SparsePyrLKOpticalFlow> cv::cuda::SparsePyrLKOpticalFlow::create(Size winSize, int maxLevel, int iters, bool useInitialFlow)
341 {
342 return makePtr<SparsePyrLKOpticalFlowImpl>(winSize, maxLevel, iters, useInitialFlow);
343 }
344
create(Size winSize,int maxLevel,int iters,bool useInitialFlow)345 Ptr<DensePyrLKOpticalFlow> cv::cuda::DensePyrLKOpticalFlow::create(Size winSize, int maxLevel, int iters, bool useInitialFlow)
346 {
347 return makePtr<DensePyrLKOpticalFlowImpl>(winSize, maxLevel, iters, useInitialFlow);
348 }
349
350 #endif /* !defined (HAVE_CUDA) */
351