/// <summary> /// Estimates LK optical flow. /// </summary> /// <param name="storage">Used storage. Number of pyramid levels is specified within storage. Use storage to gain performance in video* by 2x! </param> /// <param name="prevFeatures">Previous features.</param> /// <param name="currFeatures">Current features.</param> /// <param name="status">Feature status.</param> /// <param name="windowSize">Aperture size.</param> /// <param name="iterations">Maximal number of iterations. If <paramref name="minFeatureShift"/> is reached then number of iterations will be lower.</param> /// <param name="minFeatureShift">Minimal feature shift in horizontal or vertical direction.</param> /// <param name="minEigenValue">Minimal eigen value. /// Eigen values could be interpreted as lengths of ellipse's axes. /// If zero ellipse turn into line therefore there is no corner.</param> public static void EstimateFlow(PyrLKStorage <TColor> storage, PointF[] prevFeatures, out PointF[] currFeatures, out KLTFeatureStatus[] status, int windowSize = 15, int iterations = 30, float minFeatureShift = 0.1f, float minEigenValue = 0.001f) { var initialEstimate = new PointF[prevFeatures.Length]; currFeatures = new PointF[prevFeatures.Length]; status = new KLTFeatureStatus[prevFeatures.Length]; var scaledPrevFeatures = prevFeatures.Apply(x => x.DownScale(storage.PyrLevels)); var usedIndicies = Enumerable.Range(0, prevFeatures.Length).ToArray(); for (int pyrLevel = storage.PyrLevels; pyrLevel >= 0; pyrLevel--) { PointF[] levelCurrFeatures; KLTFeatureStatus[] levelStatus; LKOpticalFlow <TColor> .EstimateFlow(storage, scaledPrevFeatures.GetAt(usedIndicies), out levelCurrFeatures, out levelStatus, windowSize, iterations, minFeatureShift, minEigenValue, initialEstimate, pyrLevel); //update data currFeatures.SetAt(usedIndicies, levelCurrFeatures); status.SetAt(usedIndicies, levelStatus); if (pyrLevel != 0) { scaledPrevFeatures.ApplyInPlace(usedIndicies, x => x.UpScale()); currFeatures.ApplyInPlace(usedIndicies, x => x.UpScale()); initialEstimate = Sub(currFeatures, scaledPrevFeatures); usedIndicies = getValidFeatureIndicies(status); } } }