diff --git a/modules/video/src/lkpyramid.cpp b/modules/video/src/lkpyramid.cpp index b32c298240..c23a670495 100644 --- a/modules/video/src/lkpyramid.cpp +++ b/modules/video/src/lkpyramid.cpp @@ -46,6 +46,8 @@ #include "opencl_kernels_video.hpp" #include "opencv2/core/hal/intrin.hpp" +#include "opencv2/core/openvx/ovx_defs.hpp" + #define CV_DESCALE(x,n) (((x) + (1 << ((n)-1))) >> (n)) namespace @@ -1055,8 +1057,159 @@ namespace return sparse(_prevImg.getUMat(), _nextImg.getUMat(), _prevPts.getUMat(), umatNextPts, umatStatus, umatErr); } #endif + +#ifdef HAVE_OPENVX + bool openvx_pyrlk(InputArray _prevImg, InputArray _nextImg, InputArray _prevPts, InputOutputArray _nextPts, + OutputArray _status, OutputArray _err) + { + using namespace ivx; + + // Pyramids as inputs are not acceptable because there's no (direct or simple) way + // to build vx_pyramid on user data + if(_prevImg.kind() != _InputArray::MAT || _nextImg.kind() != _InputArray::MAT) + return false; + + Mat prevImgMat = _prevImg.getMat(), nextImgMat = _nextImg.getMat(); + + if(prevImgMat.type() != CV_8UC1 || nextImgMat.type() != CV_8UC1) + return false; + + CV_Assert(prevImgMat.size() == nextImgMat.size()); + Mat prevPtsMat = _prevPts.getMat(); + int checkPrev = prevPtsMat.checkVector(2, CV_32F, false); + CV_Assert( checkPrev >= 0 ); + size_t npoints = checkPrev; + + if( !(flags & OPTFLOW_USE_INITIAL_FLOW) ) + _nextPts.create(prevPtsMat.size(), prevPtsMat.type(), -1, true); + Mat nextPtsMat = _nextPts.getMat(); + CV_Assert( nextPtsMat.checkVector(2, CV_32F, false) == (int)npoints ); + + _status.create((int)npoints, 1, CV_8U, -1, true); + Mat statusMat = _status.getMat(); + uchar* status = statusMat.ptr(); + for(size_t i = 0; i < npoints; i++ ) + status[i] = true; + + Mat errMat; + if( _err.needed() ) + { + _err.create((int)npoints, 1, CV_32F, -1, true); + errMat = _err.getMat(); + } + + try + { + Context context = Context::create(); + + if(context.vendorID() == VX_ID_KHRONOS) + { + // PyrLK in OVX 1.0.1 performs vxCommitImagePatch incorrecty and crashes + if(VX_VERSION == VX_VERSION_1_0) + return false; + // Implementation ignores border mode + // So check that minimal size of image in pyramid is big enough + int width = prevImgMat.cols, height = prevImgMat.rows; + for(int i = 0; i < maxLevel+1; i++) + { + if(width < winSize.width + 1 || height < winSize.height + 1) + return false; + else + { + width /= 2; height /= 2; + } + } + } + + Image prevImg = Image::createFromHandle(context, Image::matTypeToFormat(prevImgMat.type()), + Image::createAddressing(prevImgMat), (void*)prevImgMat.data); + Image nextImg = Image::createFromHandle(context, Image::matTypeToFormat(nextImgMat.type()), + Image::createAddressing(nextImgMat), (void*)nextImgMat.data); + + Graph graph = Graph::create(context); + + Pyramid prevPyr = Pyramid::createVirtual(graph, (vx_size)maxLevel+1, VX_SCALE_PYRAMID_HALF, + prevImg.width(), prevImg.height(), prevImg.format()); + Pyramid nextPyr = Pyramid::createVirtual(graph, (vx_size)maxLevel+1, VX_SCALE_PYRAMID_HALF, + nextImg.width(), nextImg.height(), nextImg.format()); + + ivx::Node::create(graph, VX_KERNEL_GAUSSIAN_PYRAMID, prevImg, prevPyr); + ivx::Node::create(graph, VX_KERNEL_GAUSSIAN_PYRAMID, nextImg, nextPyr); + + Array prevPts = Array::create(context, VX_TYPE_KEYPOINT, npoints); + Array estimatedPts = Array::create(context, VX_TYPE_KEYPOINT, npoints); + Array nextPts = Array::create(context, VX_TYPE_KEYPOINT, npoints); + + std::vector vxPrevPts(npoints), vxEstPts(npoints), vxNextPts(npoints); + for(size_t i = 0; i < npoints; i++) + { + vx_keypoint_t& prevPt = vxPrevPts[i]; vx_keypoint_t& estPt = vxEstPts[i]; + prevPt.x = prevPtsMat.at(i).x; prevPt.y = prevPtsMat.at(i).y; + estPt.x = nextPtsMat.at(i).x; estPt.y = nextPtsMat.at(i).y; + prevPt.tracking_status = estPt.tracking_status = vx_true_e; + } + prevPts.addItems(vxPrevPts); estimatedPts.addItems(vxEstPts); + + if( (criteria.type & TermCriteria::COUNT) == 0 ) + criteria.maxCount = 30; + else + criteria.maxCount = std::min(std::max(criteria.maxCount, 0), 100); + if( (criteria.type & TermCriteria::EPS) == 0 ) + criteria.epsilon = 0.01; + else + criteria.epsilon = std::min(std::max(criteria.epsilon, 0.), 10.); + criteria.epsilon *= criteria.epsilon; + + vx_enum termEnum = (criteria.type == TermCriteria::COUNT) ? VX_TERM_CRITERIA_ITERATIONS : + (criteria.type == TermCriteria::EPS) ? VX_TERM_CRITERIA_EPSILON : + VX_TERM_CRITERIA_BOTH; + + //minEigThreshold is fixed to 0.0001f + ivx::Scalar termination = ivx::Scalar::create(context, termEnum); + ivx::Scalar epsilon = ivx::Scalar::create(context, criteria.epsilon); + ivx::Scalar numIterations = ivx::Scalar::create(context, criteria.maxCount); + ivx::Scalar useInitial = ivx::Scalar::create(context, (vx_bool)(flags & OPTFLOW_USE_INITIAL_FLOW)); + //assume winSize is square + ivx::Scalar windowSize = ivx::Scalar::create(context, (vx_size)winSize.width); + + ivx::Node::create(graph, VX_KERNEL_OPTICAL_FLOW_PYR_LK, prevPyr, nextPyr, prevPts, estimatedPts, + nextPts, termination, epsilon, numIterations, useInitial, windowSize); + + graph.verify(); + graph.process(); + + nextPts.copyTo(vxNextPts); + for(size_t i = 0; i < npoints; i++) + { + vx_keypoint_t kp = vxNextPts[i]; + nextPtsMat.at(i) = Point2f(kp.x, kp.y); + statusMat.at(i) = (bool)kp.tracking_status; + // OpenVX doesn't return detection errors + errMat.at(i) = 0; + } + +#ifdef VX_VERSION_1_1 + //we should take user memory back before release + //(it's not done automatically according to standard) + prevImg.swapHandle(); nextImg.swapHandle(); +#endif + } + catch (RuntimeError & e) + { + VX_DbgThrow(e.what()); + } + catch (WrapperError & e) + { + VX_DbgThrow(e.what()); + } + + return true; + } +#endif }; + + void SparsePyrLKOpticalFlowImpl::calc( InputArray _prevImg, InputArray _nextImg, InputArray _prevPts, InputOutputArray _nextPts, OutputArray _status, OutputArray _err) @@ -1068,6 +1221,10 @@ void SparsePyrLKOpticalFlowImpl::calc( InputArray _prevImg, InputArray _nextImg, ocl::Image2D::isFormatSupported(CV_32F, 1, false), ocl_calcOpticalFlowPyrLK(_prevImg, _nextImg, _prevPts, _nextPts, _status, _err)) + // Disabled due to bad accuracy + CV_OVX_RUN(false, + openvx_pyrlk(_prevImg, _nextImg, _prevPts, _nextPts, _status, _err)) + Mat prevPtsMat = _prevPts.getMat(); const int derivDepth = DataType::depth;