1#if defined _MSC_VER && _MSC_VER >= 1400
2#pragma warning( disable : 4201 4408 4127 4100)
3#endif
4
5#include <iostream>
6#include <iomanip>
7#include <memory>
8#include <exception>
9#include <ctime>
10#include <ctype.h>
11
12#include "cvconfig.h"
13#include <iostream>
14#include <iomanip>
15#include "opencv2/core/cuda.hpp"
16#include "opencv2/cudalegacy.hpp"
17#include "opencv2/highgui/highgui.hpp"
18#include "opencv2/highgui/highgui_c.h"
19
20#if !defined(HAVE_CUDA)
21int main( int, const char** )
22{
23    std::cout << "Please compile the library with CUDA support" << std::endl;
24    return -1;
25}
26#else
27
28//using std::tr1::shared_ptr;
29using cv::Ptr;
30
31#define PARAM_LEFT  "--left"
32#define PARAM_RIGHT "--right"
33#define PARAM_SCALE "--scale"
34#define PARAM_ALPHA "--alpha"
35#define PARAM_GAMMA "--gamma"
36#define PARAM_INNER "--inner"
37#define PARAM_OUTER "--outer"
38#define PARAM_SOLVER "--solver"
39#define PARAM_TIME_STEP "--time-step"
40#define PARAM_HELP "--help"
41
42Ptr<INCVMemAllocator> g_pGPUMemAllocator;
43Ptr<INCVMemAllocator> g_pHostMemAllocator;
44
45class RgbToMonochrome
46{
47public:
48    float operator ()(unsigned char b, unsigned char g, unsigned char r)
49    {
50        float _r = static_cast<float>(r)/255.0f;
51        float _g = static_cast<float>(g)/255.0f;
52        float _b = static_cast<float>(b)/255.0f;
53        return (_r + _g + _b)/3.0f;
54    }
55};
56
57class RgbToR
58{
59public:
60    float operator ()(unsigned char /*b*/, unsigned char /*g*/, unsigned char r)
61    {
62        return static_cast<float>(r)/255.0f;
63    }
64};
65
66
67class RgbToG
68{
69public:
70    float operator ()(unsigned char /*b*/, unsigned char g, unsigned char /*r*/)
71    {
72        return static_cast<float>(g)/255.0f;
73    }
74};
75
76class RgbToB
77{
78public:
79    float operator ()(unsigned char b, unsigned char /*g*/, unsigned char /*r*/)
80    {
81        return static_cast<float>(b)/255.0f;
82    }
83};
84
85template<class T>
86NCVStatus CopyData(IplImage *image, Ptr<NCVMatrixAlloc<Ncv32f> >& dst)
87{
88    dst = Ptr<NCVMatrixAlloc<Ncv32f> > (new NCVMatrixAlloc<Ncv32f> (*g_pHostMemAllocator, image->width, image->height));
89    ncvAssertReturn (dst->isMemAllocated (), NCV_ALLOCATOR_BAD_ALLOC);
90
91    unsigned char *row = reinterpret_cast<unsigned char*> (image->imageData);
92    T convert;
93    for (int i = 0; i < image->height; ++i)
94    {
95        for (int j = 0; j < image->width; ++j)
96        {
97            if (image->nChannels < 3)
98            {
99                dst->ptr ()[j + i*dst->stride ()] = static_cast<float> (*(row + j*image->nChannels))/255.0f;
100            }
101            else
102            {
103                unsigned char *color = row + j * image->nChannels;
104                dst->ptr ()[j +i*dst->stride ()] = convert (color[0], color[1], color[2]);
105            }
106        }
107        row += image->widthStep;
108    }
109    return NCV_SUCCESS;
110}
111
112template<class T>
113NCVStatus CopyData(const IplImage *image, const NCVMatrixAlloc<Ncv32f> &dst)
114{
115    unsigned char *row = reinterpret_cast<unsigned char*> (image->imageData);
116    T convert;
117    for (int i = 0; i < image->height; ++i)
118    {
119        for (int j = 0; j < image->width; ++j)
120        {
121            if (image->nChannels < 3)
122            {
123                dst.ptr ()[j + i*dst.stride ()] = static_cast<float>(*(row + j*image->nChannels))/255.0f;
124            }
125            else
126            {
127                unsigned char *color = row + j * image->nChannels;
128                dst.ptr ()[j +i*dst.stride()] = convert (color[0], color[1], color[2]);
129            }
130        }
131        row += image->widthStep;
132    }
133    return NCV_SUCCESS;
134}
135
136static NCVStatus LoadImages (const char *frame0Name,
137                      const char *frame1Name,
138                      int &width,
139                      int &height,
140                      Ptr<NCVMatrixAlloc<Ncv32f> > &src,
141                      Ptr<NCVMatrixAlloc<Ncv32f> > &dst,
142                      IplImage *&firstFrame,
143                      IplImage *&lastFrame)
144{
145    IplImage *image;
146    image = cvLoadImage (frame0Name);
147    if (image == 0)
148    {
149        std::cout << "Could not open '" << frame0Name << "'\n";
150        return NCV_FILE_ERROR;
151    }
152
153    firstFrame = image;
154    // copy data to src
155    ncvAssertReturnNcvStat (CopyData<RgbToMonochrome> (image, src));
156
157    IplImage *image2;
158    image2 = cvLoadImage (frame1Name);
159    if (image2 == 0)
160    {
161        std::cout << "Could not open '" << frame1Name << "'\n";
162        return NCV_FILE_ERROR;
163    }
164    lastFrame = image2;
165
166    ncvAssertReturnNcvStat (CopyData<RgbToMonochrome> (image2, dst));
167
168    width  = image->width;
169    height = image->height;
170
171    return NCV_SUCCESS;
172}
173
174template<typename T>
175inline T Clamp (T x, T a, T b)
176{
177    return ((x) > (a) ? ((x) < (b) ? (x) : (b)) : (a));
178}
179
180template<typename T>
181inline T MapValue (T x, T a, T b, T c, T d)
182{
183    x = Clamp (x, a, b);
184    return c + (d - c) * (x - a) / (b - a);
185}
186
187static NCVStatus ShowFlow (NCVMatrixAlloc<Ncv32f> &u, NCVMatrixAlloc<Ncv32f> &v, const char *name)
188{
189    IplImage *flowField;
190
191    NCVMatrixAlloc<Ncv32f> host_u(*g_pHostMemAllocator, u.width(), u.height());
192    ncvAssertReturn(host_u.isMemAllocated(), NCV_ALLOCATOR_BAD_ALLOC);
193
194    NCVMatrixAlloc<Ncv32f> host_v (*g_pHostMemAllocator, u.width (), u.height ());
195    ncvAssertReturn (host_v.isMemAllocated (), NCV_ALLOCATOR_BAD_ALLOC);
196
197    ncvAssertReturnNcvStat (u.copySolid (host_u, 0));
198    ncvAssertReturnNcvStat (v.copySolid (host_v, 0));
199
200    float *ptr_u = host_u.ptr ();
201    float *ptr_v = host_v.ptr ();
202
203    float maxDisplacement = 1.0f;
204
205    for (Ncv32u i = 0; i < u.height (); ++i)
206    {
207        for (Ncv32u j = 0; j < u.width (); ++j)
208        {
209            float d = std::max ( fabsf(*ptr_u), fabsf(*ptr_v) );
210            if (d > maxDisplacement) maxDisplacement = d;
211            ++ptr_u;
212            ++ptr_v;
213        }
214        ptr_u += u.stride () - u.width ();
215        ptr_v += v.stride () - v.width ();
216    }
217
218    CvSize image_size = cvSize (u.width (), u.height ());
219    flowField = cvCreateImage (image_size, IPL_DEPTH_8U, 4);
220    if (flowField == 0) return NCV_NULL_PTR;
221
222    unsigned char *row = reinterpret_cast<unsigned char *> (flowField->imageData);
223
224    ptr_u = host_u.ptr();
225    ptr_v = host_v.ptr();
226    for (int i = 0; i < flowField->height; ++i)
227    {
228        for (int j = 0; j < flowField->width; ++j)
229        {
230            (row + j * flowField->nChannels)[0] = 0;
231            (row + j * flowField->nChannels)[1] = static_cast<unsigned char> (MapValue (-(*ptr_v), -maxDisplacement, maxDisplacement, 0.0f, 255.0f));
232            (row + j * flowField->nChannels)[2] = static_cast<unsigned char> (MapValue (*ptr_u   , -maxDisplacement, maxDisplacement, 0.0f, 255.0f));
233            (row + j * flowField->nChannels)[3] = 255;
234            ++ptr_u;
235            ++ptr_v;
236        }
237        row += flowField->widthStep;
238        ptr_u += u.stride () - u.width ();
239        ptr_v += v.stride () - v.width ();
240    }
241
242    cvShowImage (name, flowField);
243
244    return NCV_SUCCESS;
245}
246
247static IplImage *CreateImage (NCVMatrixAlloc<Ncv32f> &h_r, NCVMatrixAlloc<Ncv32f> &h_g, NCVMatrixAlloc<Ncv32f> &h_b)
248{
249    CvSize imageSize = cvSize (h_r.width (), h_r.height ());
250    IplImage *image  = cvCreateImage (imageSize, IPL_DEPTH_8U, 4);
251    if (image == 0) return 0;
252
253    unsigned char *row = reinterpret_cast<unsigned char*> (image->imageData);
254
255    for (int i = 0; i < image->height; ++i)
256    {
257        for (int j = 0; j < image->width; ++j)
258        {
259            int offset = j * image->nChannels;
260            int pos    = i * h_r.stride () + j;
261            row[offset + 0] = static_cast<unsigned char> (h_b.ptr ()[pos] * 255.0f);
262            row[offset + 1] = static_cast<unsigned char> (h_g.ptr ()[pos] * 255.0f);
263            row[offset + 2] = static_cast<unsigned char> (h_r.ptr ()[pos] * 255.0f);
264            row[offset + 3] = 255;
265        }
266        row += image->widthStep;
267    }
268    return image;
269}
270
271static void PrintHelp ()
272{
273    std::cout << "Usage help:\n";
274    std::cout << std::setiosflags(std::ios::left);
275    std::cout << "\t" << std::setw(15) << PARAM_ALPHA << " - set alpha\n";
276    std::cout << "\t" << std::setw(15) << PARAM_GAMMA << " - set gamma\n";
277    std::cout << "\t" << std::setw(15) << PARAM_INNER << " - set number of inner iterations\n";
278    std::cout << "\t" << std::setw(15) << PARAM_LEFT << " - specify left image\n";
279    std::cout << "\t" << std::setw(15) << PARAM_RIGHT << " - specify right image\n";
280    std::cout << "\t" << std::setw(15) << PARAM_OUTER << " - set number of outer iterations\n";
281    std::cout << "\t" << std::setw(15) << PARAM_SCALE << " - set pyramid scale factor\n";
282    std::cout << "\t" << std::setw(15) << PARAM_SOLVER << " - set number of basic solver iterations\n";
283    std::cout << "\t" << std::setw(15) << PARAM_TIME_STEP << " - set frame interpolation time step\n";
284    std::cout << "\t" << std::setw(15) << PARAM_HELP << " - display this help message\n";
285}
286
287static int ProcessCommandLine(int argc, char **argv,
288                       Ncv32f &timeStep,
289                       char *&frame0Name,
290                       char *&frame1Name,
291                       NCVBroxOpticalFlowDescriptor &desc)
292{
293    timeStep = 0.25f;
294    for (int iarg = 1; iarg < argc; ++iarg)
295    {
296        if (strcmp(argv[iarg], PARAM_LEFT) == 0)
297        {
298            if (iarg + 1 < argc)
299            {
300                frame0Name = argv[++iarg];
301            }
302            else
303                return -1;
304        }
305        if (strcmp(argv[iarg], PARAM_RIGHT) == 0)
306        {
307            if (iarg + 1 < argc)
308            {
309                frame1Name = argv[++iarg];
310            }
311            else
312                return -1;
313        }
314        else if(strcmp(argv[iarg], PARAM_SCALE) == 0)
315        {
316            if (iarg + 1 < argc)
317                desc.scale_factor = static_cast<Ncv32f>(atof(argv[++iarg]));
318            else
319                return -1;
320        }
321        else if(strcmp(argv[iarg], PARAM_ALPHA) == 0)
322        {
323            if (iarg + 1 < argc)
324                desc.alpha = static_cast<Ncv32f>(atof(argv[++iarg]));
325            else
326                return -1;
327        }
328        else if(strcmp(argv[iarg], PARAM_GAMMA) == 0)
329        {
330            if (iarg + 1 < argc)
331                desc.gamma = static_cast<Ncv32f>(atof(argv[++iarg]));
332            else
333                return -1;
334        }
335        else if(strcmp(argv[iarg], PARAM_INNER) == 0)
336        {
337            if (iarg + 1 < argc)
338                desc.number_of_inner_iterations = static_cast<Ncv32u>(atoi(argv[++iarg]));
339            else
340                return -1;
341        }
342        else if(strcmp(argv[iarg], PARAM_OUTER) == 0)
343        {
344            if (iarg + 1 < argc)
345                desc.number_of_outer_iterations = static_cast<Ncv32u>(atoi(argv[++iarg]));
346            else
347                return -1;
348        }
349        else if(strcmp(argv[iarg], PARAM_SOLVER) == 0)
350        {
351            if (iarg + 1 < argc)
352                desc.number_of_solver_iterations = static_cast<Ncv32u>(atoi(argv[++iarg]));
353            else
354                return -1;
355        }
356        else if(strcmp(argv[iarg], PARAM_TIME_STEP) == 0)
357        {
358            if (iarg + 1 < argc)
359                timeStep = static_cast<Ncv32f>(atof(argv[++iarg]));
360            else
361                return -1;
362        }
363        else if(strcmp(argv[iarg], PARAM_HELP) == 0)
364        {
365            PrintHelp ();
366            return 0;
367        }
368    }
369    return 0;
370}
371
372
373int main(int argc, char **argv)
374{
375    char *frame0Name = 0, *frame1Name = 0;
376    Ncv32f timeStep = 0.01f;
377
378    NCVBroxOpticalFlowDescriptor desc;
379
380    desc.alpha = 0.197f;
381    desc.gamma = 50.0f;
382    desc.number_of_inner_iterations  = 10;
383    desc.number_of_outer_iterations  = 77;
384    desc.number_of_solver_iterations = 10;
385    desc.scale_factor = 0.8f;
386
387    int result = ProcessCommandLine (argc, argv, timeStep, frame0Name, frame1Name, desc);
388    if (argc == 1 || result)
389    {
390        PrintHelp();
391        return result;
392    }
393
394    cv::cuda::printShortCudaDeviceInfo(cv::cuda::getDevice());
395
396    std::cout << "OpenCV / NVIDIA Computer Vision\n";
397    std::cout << "Optical Flow Demo: Frame Interpolation\n";
398    std::cout << "=========================================\n";
399    std::cout << "Press:\n ESC to quit\n 'a' to move to the previous frame\n 's' to move to the next frame\n";
400
401    int devId;
402    ncvAssertCUDAReturn(cudaGetDevice(&devId), -1);
403    cudaDeviceProp devProp;
404    ncvAssertCUDAReturn(cudaGetDeviceProperties(&devProp, devId), -1);
405    std::cout << "Using GPU: " << devId << "(" << devProp.name <<
406        "), arch=" << devProp.major << "." << devProp.minor << std::endl;
407
408    g_pGPUMemAllocator  = Ptr<INCVMemAllocator> (new NCVMemNativeAllocator (NCVMemoryTypeDevice, static_cast<Ncv32u>(devProp.textureAlignment)));
409    ncvAssertPrintReturn (g_pGPUMemAllocator->isInitialized (), "Device memory allocator isn't initialized", -1);
410
411    g_pHostMemAllocator = Ptr<INCVMemAllocator> (new NCVMemNativeAllocator (NCVMemoryTypeHostPageable, static_cast<Ncv32u>(devProp.textureAlignment)));
412    ncvAssertPrintReturn (g_pHostMemAllocator->isInitialized (), "Host memory allocator isn't initialized", -1);
413
414    int width, height;
415
416    Ptr<NCVMatrixAlloc<Ncv32f> > src_host;
417    Ptr<NCVMatrixAlloc<Ncv32f> > dst_host;
418
419    IplImage *firstFrame, *lastFrame;
420    if (frame0Name != 0 && frame1Name != 0)
421    {
422        ncvAssertReturnNcvStat (LoadImages (frame0Name, frame1Name, width, height, src_host, dst_host, firstFrame, lastFrame));
423    }
424    else
425    {
426        ncvAssertReturnNcvStat (LoadImages ("frame10.bmp", "frame11.bmp", width, height, src_host, dst_host, firstFrame, lastFrame));
427    }
428
429    Ptr<NCVMatrixAlloc<Ncv32f> > src (new NCVMatrixAlloc<Ncv32f> (*g_pGPUMemAllocator, src_host->width (), src_host->height ()));
430    ncvAssertReturn(src->isMemAllocated(), -1);
431
432    Ptr<NCVMatrixAlloc<Ncv32f> > dst (new NCVMatrixAlloc<Ncv32f> (*g_pGPUMemAllocator, src_host->width (), src_host->height ()));
433    ncvAssertReturn (dst->isMemAllocated (), -1);
434
435    ncvAssertReturnNcvStat (src_host->copySolid ( *src, 0 ));
436    ncvAssertReturnNcvStat (dst_host->copySolid ( *dst, 0 ));
437
438#if defined SAFE_MAT_DECL
439#undef SAFE_MAT_DECL
440#endif
441#define SAFE_MAT_DECL(name, allocator, sx, sy) \
442    NCVMatrixAlloc<Ncv32f> name(*allocator, sx, sy);\
443    ncvAssertReturn(name.isMemAllocated(), -1);
444
445    SAFE_MAT_DECL (u, g_pGPUMemAllocator, width, height);
446    SAFE_MAT_DECL (v, g_pGPUMemAllocator, width, height);
447
448    SAFE_MAT_DECL (uBck, g_pGPUMemAllocator, width, height);
449    SAFE_MAT_DECL (vBck, g_pGPUMemAllocator, width, height);
450
451    SAFE_MAT_DECL (h_r, g_pHostMemAllocator, width, height);
452    SAFE_MAT_DECL (h_g, g_pHostMemAllocator, width, height);
453    SAFE_MAT_DECL (h_b, g_pHostMemAllocator, width, height);
454
455    std::cout << "Estimating optical flow\nForward...\n";
456
457    if (NCV_SUCCESS != NCVBroxOpticalFlow (desc, *g_pGPUMemAllocator, *src, *dst, u, v, 0))
458    {
459        std::cout << "Failed\n";
460        return -1;
461    }
462
463    std::cout << "Backward...\n";
464    if (NCV_SUCCESS != NCVBroxOpticalFlow (desc, *g_pGPUMemAllocator, *dst, *src, uBck, vBck, 0))
465    {
466        std::cout << "Failed\n";
467        return -1;
468    }
469
470    // matrix for temporary data
471    SAFE_MAT_DECL (d_temp, g_pGPUMemAllocator, width, height);
472
473    // first frame color components (GPU memory)
474    SAFE_MAT_DECL (d_r, g_pGPUMemAllocator, width, height);
475    SAFE_MAT_DECL (d_g, g_pGPUMemAllocator, width, height);
476    SAFE_MAT_DECL (d_b, g_pGPUMemAllocator, width, height);
477
478    // second frame color components (GPU memory)
479    SAFE_MAT_DECL (d_rt, g_pGPUMemAllocator, width, height);
480    SAFE_MAT_DECL (d_gt, g_pGPUMemAllocator, width, height);
481    SAFE_MAT_DECL (d_bt, g_pGPUMemAllocator, width, height);
482
483    // intermediate frame color components (GPU memory)
484    SAFE_MAT_DECL (d_rNew, g_pGPUMemAllocator, width, height);
485    SAFE_MAT_DECL (d_gNew, g_pGPUMemAllocator, width, height);
486    SAFE_MAT_DECL (d_bNew, g_pGPUMemAllocator, width, height);
487
488    // interpolated forward flow
489    SAFE_MAT_DECL (ui, g_pGPUMemAllocator, width, height);
490    SAFE_MAT_DECL (vi, g_pGPUMemAllocator, width, height);
491
492    // interpolated backward flow
493    SAFE_MAT_DECL (ubi, g_pGPUMemAllocator, width, height);
494    SAFE_MAT_DECL (vbi, g_pGPUMemAllocator, width, height);
495
496    // occlusion masks
497    SAFE_MAT_DECL (occ0, g_pGPUMemAllocator, width, height);
498    SAFE_MAT_DECL (occ1, g_pGPUMemAllocator, width, height);
499
500    // prepare color components on host and copy them to device memory
501    ncvAssertReturnNcvStat (CopyData<RgbToR> (firstFrame, h_r));
502    ncvAssertReturnNcvStat (CopyData<RgbToG> (firstFrame, h_g));
503    ncvAssertReturnNcvStat (CopyData<RgbToB> (firstFrame, h_b));
504
505    ncvAssertReturnNcvStat (h_r.copySolid ( d_r, 0 ));
506    ncvAssertReturnNcvStat (h_g.copySolid ( d_g, 0 ));
507    ncvAssertReturnNcvStat (h_b.copySolid ( d_b, 0 ));
508
509    ncvAssertReturnNcvStat (CopyData<RgbToR> (lastFrame, h_r));
510    ncvAssertReturnNcvStat (CopyData<RgbToG> (lastFrame, h_g));
511    ncvAssertReturnNcvStat (CopyData<RgbToB> (lastFrame, h_b));
512
513    ncvAssertReturnNcvStat (h_r.copySolid ( d_rt, 0 ));
514    ncvAssertReturnNcvStat (h_g.copySolid ( d_gt, 0 ));
515    ncvAssertReturnNcvStat (h_b.copySolid ( d_bt, 0 ));
516
517    std::cout << "Interpolating...\n";
518    std::cout.precision (4);
519
520    std::vector<IplImage*> frames;
521    frames.push_back (firstFrame);
522
523    // compute interpolated frames
524    for (Ncv32f timePos = timeStep; timePos < 1.0f; timePos += timeStep)
525    {
526        ncvAssertCUDAReturn (cudaMemset (ui.ptr (), 0, ui.pitch () * ui.height ()), NCV_CUDA_ERROR);
527        ncvAssertCUDAReturn (cudaMemset (vi.ptr (), 0, vi.pitch () * vi.height ()), NCV_CUDA_ERROR);
528
529        ncvAssertCUDAReturn (cudaMemset (ubi.ptr (), 0, ubi.pitch () * ubi.height ()), NCV_CUDA_ERROR);
530        ncvAssertCUDAReturn (cudaMemset (vbi.ptr (), 0, vbi.pitch () * vbi.height ()), NCV_CUDA_ERROR);
531
532        ncvAssertCUDAReturn (cudaMemset (occ0.ptr (), 0, occ0.pitch () * occ0.height ()), NCV_CUDA_ERROR);
533        ncvAssertCUDAReturn (cudaMemset (occ1.ptr (), 0, occ1.pitch () * occ1.height ()), NCV_CUDA_ERROR);
534
535        NppStInterpolationState state;
536        // interpolation state should be filled once except pSrcFrame0, pSrcFrame1, and pNewFrame
537        // we will only need to reset buffers content to 0 since interpolator doesn't do this itself
538        state.size  = NcvSize32u (width, height);
539        state.nStep = d_r.pitch ();
540        state.pSrcFrame0 = d_r.ptr ();
541        state.pSrcFrame1 = d_rt.ptr ();
542        state.pFU = u.ptr ();
543        state.pFV = v.ptr ();
544        state.pBU = uBck.ptr ();
545        state.pBV = vBck.ptr ();
546        state.pos = timePos;
547        state.pNewFrame = d_rNew.ptr ();
548        state.ppBuffers[0] = occ0.ptr ();
549        state.ppBuffers[1] = occ1.ptr ();
550        state.ppBuffers[2] = ui.ptr ();
551        state.ppBuffers[3] = vi.ptr ();
552        state.ppBuffers[4] = ubi.ptr ();
553        state.ppBuffers[5] = vbi.ptr ();
554
555        // interpolate red channel
556        nppiStInterpolateFrames (&state);
557
558        // reset buffers
559        ncvAssertCUDAReturn (cudaMemset (ui.ptr (), 0, ui.pitch () * ui.height ()), NCV_CUDA_ERROR);
560        ncvAssertCUDAReturn (cudaMemset (vi.ptr (), 0, vi.pitch () * vi.height ()), NCV_CUDA_ERROR);
561
562        ncvAssertCUDAReturn (cudaMemset (ubi.ptr (), 0, ubi.pitch () * ubi.height ()), NCV_CUDA_ERROR);
563        ncvAssertCUDAReturn (cudaMemset (vbi.ptr (), 0, vbi.pitch () * vbi.height ()), NCV_CUDA_ERROR);
564
565        ncvAssertCUDAReturn (cudaMemset (occ0.ptr (), 0, occ0.pitch () * occ0.height ()), NCV_CUDA_ERROR);
566        ncvAssertCUDAReturn (cudaMemset (occ1.ptr (), 0, occ1.pitch () * occ1.height ()), NCV_CUDA_ERROR);
567
568        // interpolate green channel
569        state.pSrcFrame0 = d_g.ptr ();
570        state.pSrcFrame1 = d_gt.ptr ();
571        state.pNewFrame  = d_gNew.ptr ();
572
573        nppiStInterpolateFrames (&state);
574
575        // reset buffers
576        ncvAssertCUDAReturn (cudaMemset (ui.ptr (), 0, ui.pitch () * ui.height ()), NCV_CUDA_ERROR);
577        ncvAssertCUDAReturn (cudaMemset (vi.ptr (), 0, vi.pitch () * vi.height ()), NCV_CUDA_ERROR);
578
579        ncvAssertCUDAReturn (cudaMemset (ubi.ptr (), 0, ubi.pitch () * ubi.height ()), NCV_CUDA_ERROR);
580        ncvAssertCUDAReturn (cudaMemset (vbi.ptr (), 0, vbi.pitch () * vbi.height ()), NCV_CUDA_ERROR);
581
582        ncvAssertCUDAReturn (cudaMemset (occ0.ptr (), 0, occ0.pitch () * occ0.height ()), NCV_CUDA_ERROR);
583        ncvAssertCUDAReturn (cudaMemset (occ1.ptr (), 0, occ1.pitch () * occ1.height ()), NCV_CUDA_ERROR);
584
585        // interpolate blue channel
586        state.pSrcFrame0 = d_b.ptr ();
587        state.pSrcFrame1 = d_bt.ptr ();
588        state.pNewFrame  = d_bNew.ptr ();
589
590        nppiStInterpolateFrames (&state);
591
592        // copy to host memory
593        ncvAssertReturnNcvStat (d_rNew.copySolid (h_r, 0));
594        ncvAssertReturnNcvStat (d_gNew.copySolid (h_g, 0));
595        ncvAssertReturnNcvStat (d_bNew.copySolid (h_b, 0));
596
597        // convert to IplImage
598        IplImage *newFrame = CreateImage (h_r, h_g, h_b);
599        if (newFrame == 0)
600        {
601            std::cout << "Could not create new frame in host memory\n";
602            break;
603        }
604        frames.push_back (newFrame);
605        std::cout << timePos * 100.0f << "%\r";
606    }
607    std::cout << std::setw (5) << "100%\n";
608
609    frames.push_back (lastFrame);
610
611    Ncv32u currentFrame;
612    currentFrame = 0;
613
614    ShowFlow (u, v, "Forward flow");
615    ShowFlow (uBck, vBck, "Backward flow");
616
617    cvShowImage ("Interpolated frame", frames[currentFrame]);
618
619    bool qPressed = false;
620    while ( !qPressed )
621    {
622        int key = toupper (cvWaitKey (10));
623        switch (key)
624        {
625        case 27:
626            qPressed = true;
627            break;
628        case 'A':
629            if (currentFrame > 0) --currentFrame;
630            cvShowImage ("Interpolated frame", frames[currentFrame]);
631            break;
632        case 'S':
633            if (currentFrame < frames.size()-1) ++currentFrame;
634            cvShowImage ("Interpolated frame", frames[currentFrame]);
635            break;
636        }
637    }
638
639    cvDestroyAllWindows ();
640
641    std::vector<IplImage*>::iterator iter;
642    for (iter = frames.begin (); iter != frames.end (); ++iter)
643    {
644        cvReleaseImage (&(*iter));
645    }
646
647    return 0;
648}
649
650#endif
651