+ }
+
+ const CvMat* imgI;
+ const CvMat* imgJ;
+ const CvPoint2D32f* featuresA;
+ CvPoint2D32f* featuresB;
+ char* status;
+ float* error;
+ CvTermCriteria criteria;
+ CvSize winSize;
+ int level;
+ int flags;
+};
+
+
+}
+
+
+CV_IMPL void
+cvCalcOpticalFlowPyrLK( const void* arrA, const void* arrB,
+ void* pyrarrA, void* pyrarrB,
+ const CvPoint2D32f * featuresA,
+ CvPoint2D32f * featuresB,
+ int count, CvSize winSize, int level,
+ char *status, float *error,
+ CvTermCriteria criteria, int flags )
+{
+ cv::AutoBuffer<uchar> pyrBuffer;
+ cv::AutoBuffer<uchar> buffer;
+ cv::AutoBuffer<char> _status;
+
+ const int MAX_ITERS = 100;
+
+ CvMat stubA, *imgA = (CvMat*)arrA;
+ CvMat stubB, *imgB = (CvMat*)arrB;
+ CvMat pstubA, *pyrA = (CvMat*)pyrarrA;
+ CvMat pstubB, *pyrB = (CvMat*)pyrarrB;
+ CvSize imgSize;
+
+ uchar **imgI = 0;
+ uchar **imgJ = 0;
+ int *step = 0;
+ double *scale = 0;
+ CvSize* size = 0;
+
+ int i, l;
+
+ imgA = cvGetMat( imgA, &stubA );
+ imgB = cvGetMat( imgB, &stubB );
+
+ if( CV_MAT_TYPE( imgA->type ) != CV_8UC1 )
+ CV_Error( CV_StsUnsupportedFormat, "" );
+
+ if( !CV_ARE_TYPES_EQ( imgA, imgB ))
+ CV_Error( CV_StsUnmatchedFormats, "" );
+
+ if( !CV_ARE_SIZES_EQ( imgA, imgB ))
+ CV_Error( CV_StsUnmatchedSizes, "" );
+
+ if( imgA->step != imgB->step )
+ CV_Error( CV_StsUnmatchedSizes, "imgA and imgB must have equal steps" );
+
+ imgSize = cvGetMatSize( imgA );
+
+ if( pyrA )
+ {
+ pyrA = cvGetMat( pyrA, &pstubA );
+
+ if( pyrA->step*pyrA->height < icvMinimalPyramidSize( imgSize ) )
+ CV_Error( CV_StsBadArg, "pyramid A has insufficient size" );
+ }
+ else
+ {
+ pyrA = &pstubA;
+ pyrA->data.ptr = 0;
+ }
+
+ if( pyrB )
+ {
+ pyrB = cvGetMat( pyrB, &pstubB );
+
+ if( pyrB->step*pyrB->height < icvMinimalPyramidSize( imgSize ) )
+ CV_Error( CV_StsBadArg, "pyramid B has insufficient size" );
+ }
+ else
+ {
+ pyrB = &pstubB;
+ pyrB->data.ptr = 0;
+ }
+
+ if( count == 0 )
+ return;
+
+ if( !featuresA || !featuresB )
+ CV_Error( CV_StsNullPtr, "Some of arrays of point coordinates are missing" );
+
+ if( count < 0 )
+ CV_Error( CV_StsOutOfRange, "The number of tracked points is negative or zero" );
+
+ if( winSize.width <= 1 || winSize.height <= 1 )
+ CV_Error( CV_StsBadSize, "Invalid search window size" );
+
+ icvInitPyramidalAlgorithm( imgA, imgB, pyrA, pyrB,
+ level, &criteria, MAX_ITERS, flags,
+ &imgI, &imgJ, &step, &size, &scale, &pyrBuffer );
+
+ if( !status )
+ {
+ _status.allocate(count);
+ status = _status;
+ }
+
+ memset( status, 1, count );
+ if( error )
+ memset( error, 0, count*sizeof(error[0]) );
+
+ if( !(flags & CV_LKFLOW_INITIAL_GUESSES) )
+ memcpy( featuresB, featuresA, count*sizeof(featuresA[0]));
+
+ for( i = 0; i < count; i++ )
+ {
+ featuresB[i].x = (float)(featuresB[i].x * scale[level] * 0.5);
+ featuresB[i].y = (float)(featuresB[i].y * scale[level] * 0.5);
+ }
+
+ /* do processing from top pyramid level (smallest image)
+ to the bottom (original image) */
+ for( l = level; l >= 0; l-- )
+ {
+ CvMat imgI_l, imgJ_l;
+ cvInitMatHeader(&imgI_l, size[l].height, size[l].width, imgA->type, imgI[l], step[l]);
+ cvInitMatHeader(&imgJ_l, size[l].height, size[l].width, imgB->type, imgJ[l], step[l]);
+
+ cv::parallel_for(cv::BlockedRange(0, count),
+ cv::LKTrackerInvoker(&imgI_l, &imgJ_l, featuresA,
+ featuresB, status, error,
+ criteria, winSize, l, flags));