/// <summary>
        /// Matches the provided template pyramid against the linearized memory maps pyramid.  
        /// </summary>
        /// <param name="linPyr">Linearized memory pyramid.</param>
        /// <param name="templPyr">Template pyramid.</param>
        /// <param name="minMatchingPercentage">Minimum matching percentage [0..100].</param>
        /// <returns>List of found matches.</returns>
        public static List<Match> MatchTemplate(this LinearizedMapPyramid linPyr, ITemplatePyramid templPyr, int minMatchingPercentage = 85)
        {
            if (linPyr.PyramidalMaps.Length != templPyr.Templates.Length)
                throw new Exception("Number of pyramids in linear pyramid must match the number of templates in template pyramid!" + "\n" +
                                    "Check if the number of neighborhood per level is the same as the number of features per level for template!");

            List<Match>[] pyrMatches = new List<Match>[linPyr.PyramidalMaps.Length];

            //match at the lowest level
            int lowestLevelIdx = linPyr.PyramidalMaps.Length - 1;
            var searchArea = new Rectangle(new Point(), linPyr.PyramidalMaps[lowestLevelIdx].ImageSize); //search whole image
            pyrMatches[lowestLevelIdx] = matchTemplate(linPyr.PyramidalMaps[lowestLevelIdx], templPyr.Templates[lowestLevelIdx], searchArea, minMatchingPercentage, true);

            //refine matches
            for (int pyrLevel = (lowestLevelIdx - 1); pyrLevel >= 0; pyrLevel--)
            {
                LinearizedMaps maps = linPyr.PyramidalMaps[pyrLevel];
                ITemplate template = templPyr.Templates[pyrLevel];
                Size imageValidSize = maps.ImageValidSize;
                pyrMatches[pyrLevel] = new List<Match>();

                int previousNeigborhood = linPyr.PyramidalMaps[pyrLevel + 1].NeigborhoodSize;

                for (int candidateIdx = 0; candidateIdx < pyrMatches[pyrLevel+1].Count; candidateIdx++) //for every candidate of previous pyramid level...
                {
                    //translate match to lower pyrmaid level
                    Match canidate = pyrMatches[pyrLevel + 1][candidateIdx];
                    canidate.X = canidate.X * 2 + 1;
                    canidate.Y = canidate.Y * 2 + 1;
                    canidate.Template = template;

                    //translate search area to lower pyramid level
                    searchArea = new Rectangle //in originalImageSize coordinate system
                    {
                        X = System.Math.Max(0, canidate.X - previousNeigborhood),
                        Y = System.Math.Max(0, canidate.Y - previousNeigborhood),
                        Width = previousNeigborhood * 2,
                        Height = previousNeigborhood * 2
                    };
                    searchArea = searchArea.Intersect(imageValidSize);

                    var foundCandidates = matchTemplate(linPyr.PyramidalMaps[pyrLevel], template, searchArea, minMatchingPercentage, pyrLevel != 0 /*filter partial object for all levels except for the original one*/);
                    pyrMatches[pyrLevel].AddRange(foundCandidates);
                }
            }

            return pyrMatches[0]; //matches of the highest pyr level
        }
예제 #2
0
        public override void OnMouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left || !this.IsSelected || isDrawn)
            {
                return;
            }

            var ptSecond = Element.ToImageCoordinate(e.Location.ToPt()).Round();

            roi = new Rectangle
            {
                X      = System.Math.Min(ptFirst.X, ptSecond.X),
                Y      = System.Math.Min(ptFirst.Y, ptSecond.Y),
                Width  = System.Math.Abs(ptFirst.X - ptSecond.X),
                Height = System.Math.Abs(ptFirst.Y - ptSecond.Y)
            };

            roi.Width  = Math.Max(MIN_RECT_SIZE, roi.Width);
            roi.Height = Math.Max(MIN_RECT_SIZE, roi.Height);

            var imageSize = Element.Image.Size.ToSize();

            this.Annotation.Polygon = roi.Vertices().Select(x => x.Clamp(imageSize)).ToArray();
        }
 /// <summary>
 ///	Inflate Shared Method
 /// </summary>
 ///
 /// <remarks>
 ///	Produces a new Rectangle by inflating an existing 
 ///	Rectangle by the specified coordinate values.
 /// </remarks>
 public static Rectangle Inflate(Rectangle rect, int x, int y)
 {
     Rectangle r = new Rectangle(rect.Location, rect.Size);
     r.Inflate(x, y);
     return r;
 }
        /// <summary>
        /// Creates template from the input image by using provided parameters.
        /// </summary>
        /// <param name="orientation">Orientation image.</param>
        /// <param name="maxNumberOfFeatures">Maximum number of features per template. The features will be extracted so that their locations are semi-uniformly spread.</param>
        /// <param name="classLabel">Template class label.</param>
        /// <param name="featureImportanceFunc">Function which returns feature's strength.</param>
        public void Initialize(Image<Gray, int> orientation, int maxNumberOfFeatures, string classLabel, Func<Feature, int> featureImportanceFunc = null)
        {
            maxNumberOfFeatures = System.Math.Max(0, System.Math.Min(maxNumberOfFeatures, GlobalParameters.MAX_NUM_OF_FEATURES));
            featureImportanceFunc = (featureImportanceFunc != null) ? featureImportanceFunc: (feature) => 0;

            Image<Gray, Byte> importantQuantizedOrient = FeatureMap.Calculate(orientation, 0);
            List<Feature> features = ExtractTemplate(importantQuantizedOrient, maxNumberOfFeatures, featureImportanceFunc);

            BoundingRect = GetBoundingRectangle(features);
            //if (boundingRect.X == 1 && boundingRect.Y  == 1 && boundingRect.Width == 18)
            //    Console.WriteLine();

            for (int i = 0; i < features.Count; i++)
            {
                features[i].X -= BoundingRect.X;
                features[i].Y -= BoundingRect.Y;

                //if(features[i].X < 0 || features[i].Y < 0)
                //    Console.WriteLine();

                //PATCH!!!
                features[i].X = System.Math.Max(0, features[i].X);
                features[i].Y = System.Math.Max(0, features[i].Y);
            }

            this.Features = features.ToArray();
            this.Size = BoundingRect.Size;
            this.ClassLabel = classLabel;
        }
        private void pictureBox_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left)
                return;

            Point ptSecond = e.Location.ToPt();

            roi = new Rectangle
            {
                X = System.Math.Min(ptFirst.X, ptSecond.X),
                Y = System.Math.Min(ptFirst.Y, ptSecond.Y),
                Width = System.Math.Abs(ptFirst.X - ptSecond.X),
                Height = System.Math.Abs(ptFirst.Y - ptSecond.Y)
            };
        }
        public KalmanTrackingDemo()
        {
            InitializeComponent();

#if FILE_CAPTURE
            roi = new Rectangle(220, 445, 80, 25); //user defined rectangle for sample video
            isROISelected = true;
#endif
            bar_ValueChanged(null, null); //write values to variables
            initalizeHistograms(); //create histograms

            try
            {
#if FILE_CAPTURE
                string videoDir = Path.Combine(Directory.GetParent(Directory.GetCurrentDirectory()).FullName, "Resources", "Sequence");
                videoCapture = new ImageDirectoryReader(videoDir, "*.jpg");
#else
                videoCapture = new CameraCapture(0);
#endif
            }
            catch (Exception)
            {
                MessageBox.Show("Cannot find any camera!");
                return;
            }

            this.FormClosing += CamshiftDemo_FormClosing;
            Application.Idle += videoCapture_InitFrame;
            videoCapture.Open();
        }
        /// <summary>
        /// Matches the provided template against the linear memory maps.
        /// </summary>
        /// <param name="linMaps">Linear maps.</param>
        /// <param name="template">Template.</param>
        /// <param name="minMatchingPercentage">Minimum matching percentage [0..100].</param>
        /// <returns>List of found matches.</returns>
        public static List<Match> MatchTemplate(this LinearizedMaps linMaps, ITemplate template, int minMatchingPercentage)
        {
            var searchArea = new Rectangle(new Point(), linMaps.ImageSize);

            return matchTemplate(linMaps, template, searchArea, minMatchingPercentage);
        }
 /// <summary>
 ///	IntersectsWith Method
 /// </summary>
 ///
 /// <remarks>
 ///	Checks if a Rectangle intersects with this one.
 /// </remarks>
 public bool IntersectsWith(Rectangle rect)
 {
     return !((Left >= rect.Right) || (Right <= rect.Left) ||
         (Top >= rect.Bottom) || (Bottom <= rect.Top));
 }
 /// <summary>
 ///	Contains Method
 /// </summary>
 ///
 /// <remarks>
 ///	Checks if a Rectangle lies entirely within this 
 ///	Rectangle.
 /// </remarks>
 public bool Contains(Rectangle rect)
 {
     return (rect == Intersect(this, rect));
 }
        void videoCapture_NewFrame(object sender, EventArgs e)
        {
            frame = videoCapture.ReadAs<Bgr, byte>();
            if (frame == null)
                return;

            long preprocessTime, matchTime;
            var bestRepresentatives = findObjects(frame, out preprocessTime, out matchTime);

            /************************************ drawing ****************************************/
            foreach (var m in bestRepresentatives)
            {
                frame.Draw(m.BoundingRect, new Bgr(0, 0, 255), 1);
              
                if (m.Template is ImageTemplateWithMask)
                {
                    var mask = ((ImageTemplateWithMask)m.Template).BinaryMask;
                    if (mask == null) continue; //just draw bounding boxes

                    var area = new Rectangle(m.X, m.Y, mask.Width, mask.Height);
                    if (area.X < 0 || area.Y < 0 || area.Right >= frame.Width || area.Bottom >= frame.Height) continue; //must be fully inside

                    using (var someImage = new Image<Bgr, byte>(mask.Width, mask.Height, Bgr8.Red))
                    {
                        someImage.CopyTo(frame.GetSubRect(area), mask);
                    }
                }
                else
                {
                    frame.Draw(m, Bgr8.Blue, 3, true, Bgr8.Red);
                }

                Console.WriteLine("Best template: " + m.Template.ClassLabel + " score: " + m.Score);
            }

            frame.Draw(String.Format("Matching {0} templates in: {1} ms", templPyrs.Count, matchTime), 
                       font, new PointF(5, 10), new Bgr(0, 255, 0));
            /************************************ drawing ****************************************/

            this.pictureBox.Image = frame.ToBitmap(); //it will be just casted (data is shared) 24bpp color

            //frame.Save(String.Format("C:/probaImages/imgMarked_{0}.jpg", i)); b.Save(String.Format("C:/probaImages/img_{0}.jpg", i)); i++;
            GC.Collect();
        }
        private static List<Match> matchTemplate(this LinearizedMaps linMaps, ITemplate template, Rectangle searchArea, int minMatchingPercentage, bool filterPartialObjects = true)
        {
            //just do matching for templates that can fit into query image
            if (template.Size.Width > linMaps.ImageValidSize.Width ||
                template.Size.Height > linMaps.ImageValidSize.Height)
                return new List<Match>();

            var similarityMap = calculateSimilarityMap(template, linMaps, searchArea);

            float rawScoreScale = 100f / (GlobalParameters.MAX_FEATURE_SIMILARITY * template.Features.Length);
            short minMatchingRawScore = (short)System.Math.Round(minMatchingPercentage * (1 / rawScoreScale));

            List<short> rawScores;
            var foundMatchPoints = searchSimilarityMap(similarityMap, minMatchingRawScore, out rawScores);

            var offset = new Point(searchArea.X, searchArea.Y);
            var foundCandidates = createMatches(template, linMaps.NeigborhoodSize, foundMatchPoints, offset, rawScores, rawScoreScale);

            filterPartialShownObjects(ref foundCandidates, linMaps.ImageSize);

            return foundCandidates;
        }
        private static void filterPartialShownObjects(ref List<Match> matches, Size originalImageSize)
        {
            List<Match> filteredMatches = new List<Match>();

            foreach (Match m in matches)
            {
                Rectangle mRect = new Rectangle(m.X, m.Y, m.Template.Size.Width, m.Template.Size.Height);
                if (!(mRect.Right > originalImageSize.Width))
                    filteredMatches.Add(m);
            }

            matches = filteredMatches;
        }
        private static Image<Gray, short> calculateSimilarityMap(ITemplate template, LinearizedMaps maps, Rectangle searchArea)
        {
            Debug.Assert(searchArea.Right <= maps.ImageSize.Width &&
                         searchArea.Bottom <= maps.ImageSize.Height);
            Debug.Assert(template.Size.Width + searchArea.X < maps.ImageSize.Width &&
                         template.Size.Height + searchArea.Y < maps.ImageSize.Height);

            int width = searchArea.Width / maps.NeigborhoodSize;
            int height = searchArea.Height / maps.NeigborhoodSize;

            Image<Gray, short> similarityMap = new Image<Gray, short>(width, height, LinearizedMaps.MAP_STRIDE_ALLIGNMENT); //performance penalty (alloc, dealloc)!!!

            using (var buffer = new Image<Gray, byte>(width, height, LinearizedMaps.MAP_STRIDE_ALLIGNMENT)) //performance penalty (alloc, dealloc)!!!
            {
                int nAddsInBuffer = 0;

                foreach (var feature in template.Features)
                {
                    var position = new Point(feature.X + searchArea.X, feature.Y + searchArea.Y); //shifted position

                    Point mapPoint;
                    var neighbourMap = maps.GetMapElement(position, feature.AngleIndex, out mapPoint);

                    neighbourMap.AddTo(buffer, mapPoint);
                    nAddsInBuffer++;

                    if (nAddsInBuffer / GlobalParameters.MAX_SUPPORTED_NUM_OF_FEATURES_ADDDED_AS_BYTE != 0)
                    {
                        buffer.AddTo(similarityMap);
                        buffer.Clear();

                        nAddsInBuffer = 0;
                    }
                }

                bool finalAdd = (template.Features.Length % GlobalParameters.MAX_SUPPORTED_NUM_OF_FEATURES_ADDDED_AS_BYTE != 0) ? true : false;
                if (finalAdd)
                {
                    buffer.AddTo(similarityMap);
                }
            }

            return similarityMap;
        }
        /// <summary>
        /// Matches the provided templates against the linear memory maps.
        /// </summary>
        /// <param name="linMaps">Linear maps.</param>
        /// <param name="templates">Collections of templates.</param>
        /// <param name="minMatchingPercentage">Minimum matching percentage [0..100].</param>
        /// <param name="inParallel">True to match each template in parallel, sequentially otherwise.</param>
        /// <returns>List of found matches.</returns>
        public static List<Match> MatchTemplates(this LinearizedMaps linMaps, IEnumerable<ITemplate> templates, int minMatchingPercentage = 85, bool inParallel = true)
        {
            var searchArea = new Rectangle(new Point(), linMaps.ImageSize);

            List<Match> matches = new List<Match>();

            if (inParallel)
            {
                object syncObj = new object();

                Parallel.ForEach(templates, (template) =>
                {
                    List<Match> templateMatches = matchTemplate(linMaps, template, searchArea, minMatchingPercentage);
                    lock (syncObj) matches.AddRange(templateMatches);
                });
            }
            else
            {
                foreach (var template in templates)
                {
                    List<Match> templateMatches = matchTemplate(linMaps, template, searchArea, minMatchingPercentage);
                    matches.AddRange(templateMatches);
                }
            }

            return matches;
        }
        /// <summary>
        ///	Intersect Shared Method
        /// </summary>
        ///
        /// <remarks>
        ///	Produces a new Rectangle by intersecting 2 existing 
        ///	Rectangles. Returns null if there is no	intersection.
        /// </remarks>
        public static Rectangle Intersect(Rectangle a, Rectangle b)
        {
            // MS.NET returns a non-empty rectangle if the two rectangles
            // touch each other
            if (!a.IntersectsWithInclusive(b))
                return Empty;

            return Rectangle.FromLTRB(
                Math.Max(a.Left, b.Left),
                Math.Max(a.Top, b.Top),
                Math.Min(a.Right, b.Right),
                Math.Min(a.Bottom, b.Bottom));
        }
        public override void OnMouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left || !this.IsSelected || isDrawn)
                return;

            var ptSecond = Element.ToImageCoordinate(e.Location.ToPt()).Round();

            roi = new Rectangle
            {
                X = System.Math.Min(ptFirst.X, ptSecond.X),
                Y = System.Math.Min(ptFirst.Y, ptSecond.Y),
                Width = System.Math.Abs(ptFirst.X - ptSecond.X),
                Height = System.Math.Abs(ptFirst.Y - ptSecond.Y)
            };

            roi.Width = Math.Max(MIN_RECT_SIZE, roi.Width);
            roi.Height = Math.Max(MIN_RECT_SIZE, roi.Height);

            var imageSize = Element.Image.Size.ToSize();
            this.Annotation.Polygon = roi.Vertices().Select(x => x.Clamp(imageSize)).ToArray();
        }
 /// <summary>
 ///	Union Shared Method
 /// </summary>
 ///
 /// <remarks>
 ///	Produces a new Rectangle from the union of 2 existing 
 ///	Rectangles.
 /// </remarks>
 public static Rectangle Union(Rectangle a, Rectangle b)
 {
     return FromLTRB(Math.Min(a.Left, b.Left),
              Math.Min(a.Top, b.Top),
              Math.Max(a.Right, b.Right),
              Math.Max(a.Bottom, b.Bottom));
 }
        private void trackOneStep(Image<Bgr, byte> frame, out Image<Gray, byte> probabilityMap, out Box2D foundBox)
        {
            const float SEARCH_AREA_INFLATE_FACTOR = 0.05f;

            /**************************** KALMAN predict **************************/
            kalman.Predict(); 
            searchArea = createRect(kalman.State.Position, searchArea.Size, frame.Size);
            /**************************** KALMAN predict **************************/

            trackCamshift(frame, searchArea, out probabilityMap, out foundBox);

            if (!foundBox.IsEmpty)
            {
                /**************************** KALMAN correct **************************/
                //kalman.Correct(new PointF(foundBox.Center.X, foundBox.Center.Y)); //correct predicted state by measurement
                /**************************** KALMAN correct **************************/

                var foundArea = Rectangle.Round(foundBox.GetMinArea());
                searchArea = foundArea.Inflate(SEARCH_AREA_INFLATE_FACTOR, SEARCH_AREA_INFLATE_FACTOR, frame.Size); //inflate found area for search (X factor)...
                nonVisibleCount = 0;
            }
            else
            {
                nonVisibleCount++;
                if (nonVisibleCount == 1) //for the first time 
                {
                    searchArea = searchArea.Inflate(-SEARCH_AREA_INFLATE_FACTOR * 1.5, -SEARCH_AREA_INFLATE_FACTOR * 1.5, frame.Size); //shrink (hysteresis)
                }

                searchArea = createRect(kalman.State.Position, searchArea.Size, frame.Size); 
            }

            if (nonVisibleCount > 80) //if not visible for a longer time => reset tracking
            {
                nonVisibleCount = 0;
                isROISelected = false;
            }
        }
 /// <summary>
 ///	Intersect Method
 /// </summary>
 ///
 /// <remarks>
 ///	Replaces the Rectangle with the intersection of itself
 ///	and another Rectangle.
 /// </remarks>
 public void Intersect(Rectangle rect)
 {
     this = Rectangle.Intersect(this, rect);
 }
        private void trackCamshift(Image<Bgr, byte> frame, Rectangle searchArea, out Image<Gray, byte> probabilityMap, out Box2D foundBox)
        {
            const int PROBABILITY_MIN_VAL = (int)(0.3f * Byte.MaxValue);

            //convert to HSV
            var hsvImg = frame.Convert<Hsv, byte>(); //<<parallel operation>>
            //back-project ratio hist => create probability map
            probabilityMap = ratioHist.BackProject(hsvImg.SplitChannels(0, 1)); //or new Image<Gray, byte>[]{ hsvImg[0], hsvImg[1]...} //<<parallel operation>>

            //user constraints...
            Image<Gray, byte> mask = hsvImg.InRange(new Hsv(0, 0, minV), new Hsv(0, 0, maxV), Byte.MaxValue, 2);
            probabilityMap.And(mask, inPlace: true);

            //run Camshift algorithm to find new object position, size and angle
            CentralMoments centralMoments;
            foundBox = Camshift.Process(probabilityMap, searchArea, Meanshift.DEFAULT_TERM, out centralMoments); //<<parallel operation>>

             //stopping conditions
            float avgIntensity = centralMoments.Mu00 / (foundBox.Size.Area() + Single.Epsilon);
            if (avgIntensity < PROBABILITY_MIN_VAL || foundBox.Size.IsEmpty || foundBox.GetMinArea().Area() < 5 * 5)
            {
                foundBox = Box2D.Empty; //invalid box
            }
        }
 private bool IntersectsWithInclusive(Rectangle r)
 {
     return !((Left > r.Right) || (Right < r.Left) ||
         (Top > r.Bottom) || (Bottom < r.Top));
 }
        /// <summary>
        /// Matches the provided template against the linear memory maps.
        /// </summary>
        /// <param name="linMaps">Linear maps.</param>
        /// <param name="template">Template.</param>
        /// <param name="searchArea">Search area in the image.</param>
        /// <param name="minMatchingPercentage">Minimum matching percentage [0..100].</param>
        /// <returns>List of found matches.</returns>
        public static List<Match> MatchTemplate(this LinearizedMaps linMaps, ITemplate template, Rectangle searchArea, int minMatchingPercentage = 85)
        {
            if (searchArea.IntersectionPercent(new Rectangle(new Point(), linMaps.ImageSize)) < 1)
            {
                throw new Exception("Search area must be within image size!");
            }

            return matchTemplate(linMaps, template, searchArea, minMatchingPercentage);
        }