Example #1
0
        /// <summary>
        /// Estimates LK optical flow.
        /// </summary>
        /// <param name="prevImg">Previous image.</param>
        /// <param name="currImg">Current image.</param>
        /// <param name="prevFeatures">Previous features.</param>
        /// <param name="currFeatures">Current features.</param>
        /// <param name="status">Feature status.</param>
        /// <param name="error">Normalized tracking error [0..1].</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>
        /// <param name="maxError">Maximal allowable error for <paramref name="error"/>.</param>
        /// <param name="initialEstimate">Initial estimate shifts input features by specified amount. Default is zero.
        /// Used for pyramidal implementation.</param>
        public static void EstimateFlow(Image <TColor, float> prevImg, Image <TColor, float> currImg,
                                        PointF[] prevFeatures, out PointF[] currFeatures,
                                        out KLTFeatureStatus[] status, out float[] error,
                                        int windowSize = 15, int iterations = 30, float minFeatureShift = 0.1f, float minEigenValue = 0.01f, float maxError = 0.1f, PointF[] initialEstimate = null)
        {
            storage = new PyrLKStorage <TColor>(0);
            storage.Process(prevImg, currImg);

            EstimateFlow(storage,
                         prevFeatures, out currFeatures, out status, out error,
                         windowSize, iterations, minFeatureShift, minEigenValue, maxError, initialEstimate, 0);

            storage.Dispose();
        }
        /// <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="error">Normalized tracking error [0..1].</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>
        /// <param name="maxError">Maximal allowable error for <paramref name="error"/>.</param>
        public static void EstimateFlow(PyrLKStorage <TColor> storage,
                                        PointF[] prevFeatures, out PointF[] currFeatures,
                                        out KLTFeatureStatus[] status, out float[] error,
                                        int windowSize = 15, int iterations = 30, float minFeatureShift = 0.1f, float minEigenValue = 0.001f, float maxError = 0.1f)
        {
            var initialEstimate = new PointF[prevFeatures.Length];

            currFeatures = new PointF[prevFeatures.Length];
            error        = new float[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;
                float[]            levelError;
                KLTFeatureStatus[] levelStatus;
                LKOpticalFlow <TColor> .EstimateFlow(storage,
                                                     scaledPrevFeatures.GetAt(usedIndicies), out levelCurrFeatures, out levelStatus, out levelError,
                                                     windowSize, iterations, minFeatureShift, minEigenValue, maxError, initialEstimate, pyrLevel);

                //update data
                currFeatures.SetAt(usedIndicies, levelCurrFeatures);
                error.SetAt(usedIndicies, levelError);
                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);
                }
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="storage">Memory storage used for pyramid and derivative calculation.
        /// By using storage instead images if using sequential image input (e.g. frame by frame video) </param>
        /// <param name="prevFeatures">Previous features.</param>
        /// <param name="currFeatures">Current features.</param>
        /// <param name="status">Feature status.</param>
        /// <param name="error">Normalized tracking error [0..1].</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>
        /// <param name="maxError">Maximal allowable error for <paramref name="error"/>.</param>
        /// <param name="initialEstimate">Initial estimate shifts input features by specified amount. Default is zero.</param>
        /// <param name="storagePyrLevel">Used pyramid level for the input storage. Default is zero.</param>
        public static void EstimateFlow(PyrLKStorage <TColor> storage,
                                        PointF[] prevFeatures, out PointF[] currFeatures,
                                        out KLTFeatureStatus[] status, out float[] error,
                                        int windowSize           = 15, int iterations = 30, float minFeatureShift = 0.1f, float minEigenValue = 0.01f, float maxError = 0.1f,
                                        PointF[] initialEstimate = null, int storagePyrLevel = 0)
        {
            LKOpticalFlow <TColor> .storage         = storage;
            LKOpticalFlow <TColor> .storagePyrLevel = storagePyrLevel;
            initialEstimate = initialEstimate ?? new PointF[prevFeatures.Length];

            PointF[]           _currFeatures = new PointF[prevFeatures.Length];
            KLTFeatureStatus[] _status       = new KLTFeatureStatus[prevFeatures.Length];
            float[]            _error        = new float[prevFeatures.Length];

            Parallel.For(0, prevFeatures.Length, (int featureIdx) =>
                         //for (int featureIdx = 0; featureIdx < prevFeatures.Length; featureIdx++)
            {
                PointF currFeature;
                float featureError;
                KLTFeatureStatus featureStatus;

                EstimateFeatureFlow(storage.PrevImgPyr[storagePyrLevel], storage.CurrImgPyr[storagePyrLevel],
                                    prevFeatures[featureIdx], out currFeature, out featureStatus, out featureError, windowSize, iterations, minFeatureShift, minEigenValue, maxError, initialEstimate[featureIdx]);

                lock (_currFeatures)
                    lock (_error)
                        lock (_status)
                        {
                            _currFeatures[featureIdx] = currFeature;
                            _error[featureIdx]        = featureError;
                            _status[featureIdx]       = featureStatus;
                        }
            });

            currFeatures = _currFeatures;
            error        = _error;
            status       = _status;
        }