Skip to content

Commit 5372c8b

Browse files
savuoralalek
authored andcommitted
Merge pull request opencv#7774 from savuor:openvx_pyrlk
OpenVX optical flow PyrLK wrappers added (opencv#7774) * wrappers for vx_pyramid added * initial version of Optical Flow PyrLK wrappers added * array downloading code simplified * disabled due to bad accuracy; fixed bugs, e.g. vendor-specific ones * rewritten for new macro use
1 parent 9c7088d commit 5372c8b

File tree

1 file changed

+157
-0
lines changed

1 file changed

+157
-0
lines changed

modules/video/src/lkpyramid.cpp

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
#include "opencl_kernels_video.hpp"
4747
#include "opencv2/core/hal/intrin.hpp"
4848

49+
#include "opencv2/core/openvx/ovx_defs.hpp"
50+
4951
#define CV_DESCALE(x,n) (((x) + (1 << ((n)-1))) >> (n))
5052

5153
namespace
@@ -1055,8 +1057,159 @@ namespace
10551057
return sparse(_prevImg.getUMat(), _nextImg.getUMat(), _prevPts.getUMat(), umatNextPts, umatStatus, umatErr);
10561058
}
10571059
#endif
1060+
1061+
#ifdef HAVE_OPENVX
1062+
bool openvx_pyrlk(InputArray _prevImg, InputArray _nextImg, InputArray _prevPts, InputOutputArray _nextPts,
1063+
OutputArray _status, OutputArray _err)
1064+
{
1065+
using namespace ivx;
1066+
1067+
// Pyramids as inputs are not acceptable because there's no (direct or simple) way
1068+
// to build vx_pyramid on user data
1069+
if(_prevImg.kind() != _InputArray::MAT || _nextImg.kind() != _InputArray::MAT)
1070+
return false;
1071+
1072+
Mat prevImgMat = _prevImg.getMat(), nextImgMat = _nextImg.getMat();
1073+
1074+
if(prevImgMat.type() != CV_8UC1 || nextImgMat.type() != CV_8UC1)
1075+
return false;
1076+
1077+
CV_Assert(prevImgMat.size() == nextImgMat.size());
1078+
Mat prevPtsMat = _prevPts.getMat();
1079+
int checkPrev = prevPtsMat.checkVector(2, CV_32F, false);
1080+
CV_Assert( checkPrev >= 0 );
1081+
size_t npoints = checkPrev;
1082+
1083+
if( !(flags & OPTFLOW_USE_INITIAL_FLOW) )
1084+
_nextPts.create(prevPtsMat.size(), prevPtsMat.type(), -1, true);
1085+
Mat nextPtsMat = _nextPts.getMat();
1086+
CV_Assert( nextPtsMat.checkVector(2, CV_32F, false) == (int)npoints );
1087+
1088+
_status.create((int)npoints, 1, CV_8U, -1, true);
1089+
Mat statusMat = _status.getMat();
1090+
uchar* status = statusMat.ptr();
1091+
for(size_t i = 0; i < npoints; i++ )
1092+
status[i] = true;
1093+
1094+
Mat errMat;
1095+
if( _err.needed() )
1096+
{
1097+
_err.create((int)npoints, 1, CV_32F, -1, true);
1098+
errMat = _err.getMat();
1099+
}
1100+
1101+
try
1102+
{
1103+
Context context = Context::create();
1104+
1105+
if(context.vendorID() == VX_ID_KHRONOS)
1106+
{
1107+
// PyrLK in OVX 1.0.1 performs vxCommitImagePatch incorrecty and crashes
1108+
if(VX_VERSION == VX_VERSION_1_0)
1109+
return false;
1110+
// Implementation ignores border mode
1111+
// So check that minimal size of image in pyramid is big enough
1112+
int width = prevImgMat.cols, height = prevImgMat.rows;
1113+
for(int i = 0; i < maxLevel+1; i++)
1114+
{
1115+
if(width < winSize.width + 1 || height < winSize.height + 1)
1116+
return false;
1117+
else
1118+
{
1119+
width /= 2; height /= 2;
1120+
}
1121+
}
1122+
}
1123+
1124+
Image prevImg = Image::createFromHandle(context, Image::matTypeToFormat(prevImgMat.type()),
1125+
Image::createAddressing(prevImgMat), (void*)prevImgMat.data);
1126+
Image nextImg = Image::createFromHandle(context, Image::matTypeToFormat(nextImgMat.type()),
1127+
Image::createAddressing(nextImgMat), (void*)nextImgMat.data);
1128+
1129+
Graph graph = Graph::create(context);
1130+
1131+
Pyramid prevPyr = Pyramid::createVirtual(graph, (vx_size)maxLevel+1, VX_SCALE_PYRAMID_HALF,
1132+
prevImg.width(), prevImg.height(), prevImg.format());
1133+
Pyramid nextPyr = Pyramid::createVirtual(graph, (vx_size)maxLevel+1, VX_SCALE_PYRAMID_HALF,
1134+
nextImg.width(), nextImg.height(), nextImg.format());
1135+
1136+
ivx::Node::create(graph, VX_KERNEL_GAUSSIAN_PYRAMID, prevImg, prevPyr);
1137+
ivx::Node::create(graph, VX_KERNEL_GAUSSIAN_PYRAMID, nextImg, nextPyr);
1138+
1139+
Array prevPts = Array::create(context, VX_TYPE_KEYPOINT, npoints);
1140+
Array estimatedPts = Array::create(context, VX_TYPE_KEYPOINT, npoints);
1141+
Array nextPts = Array::create(context, VX_TYPE_KEYPOINT, npoints);
1142+
1143+
std::vector<vx_keypoint_t> vxPrevPts(npoints), vxEstPts(npoints), vxNextPts(npoints);
1144+
for(size_t i = 0; i < npoints; i++)
1145+
{
1146+
vx_keypoint_t& prevPt = vxPrevPts[i]; vx_keypoint_t& estPt = vxEstPts[i];
1147+
prevPt.x = prevPtsMat.at<Point2f>(i).x; prevPt.y = prevPtsMat.at<Point2f>(i).y;
1148+
estPt.x = nextPtsMat.at<Point2f>(i).x; estPt.y = nextPtsMat.at<Point2f>(i).y;
1149+
prevPt.tracking_status = estPt.tracking_status = vx_true_e;
1150+
}
1151+
prevPts.addItems(vxPrevPts); estimatedPts.addItems(vxEstPts);
1152+
1153+
if( (criteria.type & TermCriteria::COUNT) == 0 )
1154+
criteria.maxCount = 30;
1155+
else
1156+
criteria.maxCount = std::min(std::max(criteria.maxCount, 0), 100);
1157+
if( (criteria.type & TermCriteria::EPS) == 0 )
1158+
criteria.epsilon = 0.01;
1159+
else
1160+
criteria.epsilon = std::min(std::max(criteria.epsilon, 0.), 10.);
1161+
criteria.epsilon *= criteria.epsilon;
1162+
1163+
vx_enum termEnum = (criteria.type == TermCriteria::COUNT) ? VX_TERM_CRITERIA_ITERATIONS :
1164+
(criteria.type == TermCriteria::EPS) ? VX_TERM_CRITERIA_EPSILON :
1165+
VX_TERM_CRITERIA_BOTH;
1166+
1167+
//minEigThreshold is fixed to 0.0001f
1168+
ivx::Scalar termination = ivx::Scalar::create<VX_TYPE_ENUM>(context, termEnum);
1169+
ivx::Scalar epsilon = ivx::Scalar::create<VX_TYPE_FLOAT32>(context, criteria.epsilon);
1170+
ivx::Scalar numIterations = ivx::Scalar::create<VX_TYPE_UINT32>(context, criteria.maxCount);
1171+
ivx::Scalar useInitial = ivx::Scalar::create<VX_TYPE_BOOL>(context, (vx_bool)(flags & OPTFLOW_USE_INITIAL_FLOW));
1172+
//assume winSize is square
1173+
ivx::Scalar windowSize = ivx::Scalar::create<VX_TYPE_SIZE>(context, (vx_size)winSize.width);
1174+
1175+
ivx::Node::create(graph, VX_KERNEL_OPTICAL_FLOW_PYR_LK, prevPyr, nextPyr, prevPts, estimatedPts,
1176+
nextPts, termination, epsilon, numIterations, useInitial, windowSize);
1177+
1178+
graph.verify();
1179+
graph.process();
1180+
1181+
nextPts.copyTo(vxNextPts);
1182+
for(size_t i = 0; i < npoints; i++)
1183+
{
1184+
vx_keypoint_t kp = vxNextPts[i];
1185+
nextPtsMat.at<Point2f>(i) = Point2f(kp.x, kp.y);
1186+
statusMat.at<uchar>(i) = (bool)kp.tracking_status;
1187+
// OpenVX doesn't return detection errors
1188+
errMat.at<float>(i) = 0;
1189+
}
1190+
1191+
#ifdef VX_VERSION_1_1
1192+
//we should take user memory back before release
1193+
//(it's not done automatically according to standard)
1194+
prevImg.swapHandle(); nextImg.swapHandle();
1195+
#endif
1196+
}
1197+
catch (RuntimeError & e)
1198+
{
1199+
VX_DbgThrow(e.what());
1200+
}
1201+
catch (WrapperError & e)
1202+
{
1203+
VX_DbgThrow(e.what());
1204+
}
1205+
1206+
return true;
1207+
}
1208+
#endif
10581209
};
10591210

1211+
1212+
10601213
void SparsePyrLKOpticalFlowImpl::calc( InputArray _prevImg, InputArray _nextImg,
10611214
InputArray _prevPts, InputOutputArray _nextPts,
10621215
OutputArray _status, OutputArray _err)
@@ -1068,6 +1221,10 @@ void SparsePyrLKOpticalFlowImpl::calc( InputArray _prevImg, InputArray _nextImg,
10681221
ocl::Image2D::isFormatSupported(CV_32F, 1, false),
10691222
ocl_calcOpticalFlowPyrLK(_prevImg, _nextImg, _prevPts, _nextPts, _status, _err))
10701223

1224+
// Disabled due to bad accuracy
1225+
CV_OVX_RUN(false,
1226+
openvx_pyrlk(_prevImg, _nextImg, _prevPts, _nextPts, _status, _err))
1227+
10711228
Mat prevPtsMat = _prevPts.getMat();
10721229
const int derivDepth = DataType<cv::detail::deriv_type>::depth;
10731230

0 commit comments

Comments
 (0)