Esempio n. 1
0
        private void DrawDebugInfo(Graphics canvas, AbstractTrackPoint point, RectangleF search)
        {
            TrackPointBlock tpb = point as TrackPointBlock;

            if (tpb == null)
            {
                return;
            }

            Font   f    = new Font("Consolas", 8, FontStyle.Bold);
            string text = string.Format("simi:{0:0.000}, age:{1}, pos:{2:0.000}×{3:0.000}", tpb.Similarity, tpb.TemplateAge, tpb.Point.X, tpb.Point.Y);
            Brush  b    = tpb.Similarity > parameters.TemplateUpdateThreshold ? Brushes.Green : Brushes.Red;

            canvas.DrawString(text, f, b, search.Location.Translate(0, -25));

            f.Dispose();
        }
Esempio n. 2
0
        public override bool Track(List <AbstractTrackPoint> _previousPoints, Bitmap _CurrentImage, long _t, out AbstractTrackPoint _currentPoint)
        {
            //---------------------------------------------------------------------
            // The input informations we have at hand are:
            // - The current bitmap we have to find the point into.
            // - The coordinates of all the previous points tracked.
            // - Previous tracking infos, stored in the TrackPoints tracked so far.
            //---------------------------------------------------------------------

            TrackPointBlock lastTrackPoint = (TrackPointBlock)_previousPoints[_previousPoints.Count - 1];
            Point           lastPoint      = lastTrackPoint.ToPoint();

            bool bMatched = false;

            _currentPoint = null;

            if (lastTrackPoint.Template != null && _CurrentImage != null)
            {
                // Center search zone around last point.
                Point     searchCenter = lastPoint;
                Rectangle searchZone   = new Rectangle(searchCenter.X - (m_SearchWindowSize.Width / 2),
                                                       searchCenter.Y - (m_SearchWindowSize.Height / 2),
                                                       m_SearchWindowSize.Width,
                                                       m_SearchWindowSize.Height);

                searchZone.Intersect(new Rectangle(0, 0, _CurrentImage.Width, _CurrentImage.Height));

                double fBestScore    = 0;
                Point  bestCandidate = new Point(-1, -1);

                //Image<Bgr, Byte> cvTemplate = new Image<Bgr, Byte>(lastTrackPoint.Template);
                //Image<Bgr, Byte> cvImage = new Image<Bgr, Byte>(_CurrentImage);

                Bitmap img = _CurrentImage;
                Bitmap tpl = lastTrackPoint.Template;

                BitmapData imageData    = img.LockBits(new Rectangle(0, 0, img.Width, img.Height), ImageLockMode.ReadOnly, img.PixelFormat);
                BitmapData templateData = tpl.LockBits(new Rectangle(0, 0, tpl.Width, tpl.Height), ImageLockMode.ReadOnly, tpl.PixelFormat);

                Image <Bgr, Byte> cvImage    = new Image <Bgr, Byte>(imageData.Width, imageData.Height, imageData.Stride, imageData.Scan0);
                Image <Bgr, Byte> cvTemplate = new Image <Bgr, Byte>(templateData.Width, templateData.Height, templateData.Stride, templateData.Scan0);

                cvImage.ROI = searchZone;

                int resWidth  = searchZone.Width - lastTrackPoint.Template.Width + 1;
                int resHeight = searchZone.Height - lastTrackPoint.Template.Height + 1;

                Image <Gray, Single> similarityMap = new Image <Gray, Single>(resWidth, resHeight);

                //CvInvoke.cvMatchTemplate(cvImage.Ptr, cvTemplate.Ptr, similarityMap.Ptr, TM_TYPE.CV_TM_SQDIFF_NORMED);
                //CvInvoke.cvMatchTemplate(cvImage.Ptr, cvTemplate.Ptr, similarityMap.Ptr, TM_TYPE.CV_TM_CCORR_NORMED);
                CvInvoke.cvMatchTemplate(cvImage.Ptr, cvTemplate.Ptr, similarityMap.Ptr, TM_TYPE.CV_TM_CCOEFF_NORMED);

                img.UnlockBits(imageData);
                tpl.UnlockBits(templateData);

                // Find max
                Point  p1   = new Point(0, 0);
                Point  p2   = new Point(0, 0);
                double fMin = 0;
                double fMax = 0;

                CvInvoke.cvMinMaxLoc(similarityMap.Ptr, ref fMin, ref fMax, ref p1, ref p2, IntPtr.Zero);

                if (fMax > m_fSimilarityTreshold)
                {
                    bestCandidate = new Point(searchZone.Left + p2.X + tpl.Width / 2, searchZone.Top + p2.Y + tpl.Height / 2);
                    fBestScore    = fMax;
                }

                #region Monitoring
                if (m_bMonitoring)
                {
                    // Save the similarity map to file.
                    Image <Gray, Byte> mapNormalized = new Image <Gray, Byte>(similarityMap.Width, similarityMap.Height);
                    CvInvoke.cvNormalize(similarityMap.Ptr, mapNormalized.Ptr, 0, 255, NORM_TYPE.CV_MINMAX, IntPtr.Zero);

                    Bitmap bmpMap = mapNormalized.ToBitmap();

                    string tplDirectory = @"C:\Documents and Settings\Administrateur\Mes documents\Dev  Prog\Videa\Video Testing\Tracking\Template Update";
                    bmpMap.Save(tplDirectory + String.Format(@"\simiMap-{0:000}-{1:0.00}.bmp", _previousPoints.Count, fBestScore));
                }
                #endregion

                // Result of the matching.
                if (bestCandidate.X != -1 && bestCandidate.Y != -1)
                {
                    // Save template in the point.
                    _currentPoint = CreateTrackPoint(false, bestCandidate.X, bestCandidate.Y, fBestScore, _t, img, _previousPoints);
                    ((TrackPointBlock)_currentPoint).Similarity = fBestScore;

                    bMatched = true;
                }
                else
                {
                    // No match. Create the point at the center of the search window (whatever that might be).
                    _currentPoint = CreateTrackPoint(false, searchCenter.X, searchCenter.Y, 0.0f, _t, img, _previousPoints);
                    log.Debug("Track failed. No block over the similarity treshold in the search window.");
                }
            }
            else
            {
                // No image. (error case ?)
                // Create the point at the last point location.
                _currentPoint = CreateTrackPoint(false, lastTrackPoint.X, lastTrackPoint.Y, 0.0f, _t, _CurrentImage, _previousPoints);
                log.Debug("Track failed. No input image, or last point doesn't have any cached block image.");
            }

            return(bMatched);
        }
Esempio n. 3
0
        public override AbstractTrackPoint CreateTrackPoint(bool _bManual, int _x, int _y, double _fSimilarity, long _t, Bitmap _CurrentImage, List <AbstractTrackPoint> _previousPoints)
        {
            // Creates a TrackPoint from the input image at the given coordinates.
            // Stores algorithm internal data in the point, to help next match.
            // _t is in relative timestamps from the first point.

            // Copy the template from the image into its own Bitmap.

            Bitmap tpl = new Bitmap(m_BlockSize.Width, m_BlockSize.Height, PixelFormat.Format24bppRgb);

            bool bUpdateWithCurrentImage = true;

            if (!_bManual && _previousPoints.Count > 0 && _fSimilarity > m_fTemplateUpdateSimilarityThreshold)
            {
                // Do not update the template if it's not that different.
                TrackPointBlock prevBlock = _previousPoints[_previousPoints.Count - 1] as TrackPointBlock;
                if (prevBlock != null && prevBlock.Template != null)
                {
                    tpl = AForge.Imaging.Image.Clone(prevBlock.Template);
                    bUpdateWithCurrentImage = false;
                }
            }


            if (bUpdateWithCurrentImage)
            {
                BitmapData imageData    = _CurrentImage.LockBits(new Rectangle(0, 0, _CurrentImage.Width, _CurrentImage.Height), ImageLockMode.ReadOnly, _CurrentImage.PixelFormat);
                BitmapData templateData = tpl.LockBits(new Rectangle(0, 0, tpl.Width, tpl.Height), ImageLockMode.ReadWrite, tpl.PixelFormat);

                int pixelSize = 3;

                int tplStride            = templateData.Stride;
                int templateWidthInBytes = m_BlockSize.Width * pixelSize;
                int tplOffset            = tplStride - templateWidthInBytes;

                int imgStride         = imageData.Stride;
                int imageWidthInBytes = _CurrentImage.Width * pixelSize;
                int imgOffset         = imgStride - (_CurrentImage.Width * pixelSize) + imageWidthInBytes - templateWidthInBytes;

                int startY = _y - (m_BlockSize.Height / 2);
                int startX = _x - (m_BlockSize.Width / 2);

                if (startX < 0)
                {
                    startX = 0;
                }

                if (startY < 0)
                {
                    startY = 0;
                }

                unsafe
                {
                    byte *pTpl = (byte *)templateData.Scan0.ToPointer();
                    byte *pImg = (byte *)imageData.Scan0.ToPointer() + (imgStride * startY) + (pixelSize * startX);

                    for (int row = 0; row < m_BlockSize.Height; row++)
                    {
                        if (startY + row > imageData.Height - 1)
                        {
                            break;
                        }

                        for (int col = 0; col < templateWidthInBytes; col++, pTpl++, pImg++)
                        {
                            if (startX * pixelSize + col < imageWidthInBytes)
                            {
                                *pTpl = *pImg;
                            }
                        }

                        pTpl += tplOffset;
                        pImg += imgOffset;
                    }
                }

                _CurrentImage.UnlockBits(imageData);
                tpl.UnlockBits(templateData);
            }

            #region Monitoring
            if (m_bMonitoring && bUpdateWithCurrentImage)
            {
                // Save current template to file, to visually monitor the drift.
                string tplDirectory = @"C:\Documents and Settings\Administrateur\Mes documents\Dev  Prog\Videa\Video Testing\Tracking\Template Update";
                if (_previousPoints.Count <= 1)
                {
                    // Clean up folder.
                    string[] tplFiles = Directory.GetFiles(tplDirectory, "*.bmp");
                    foreach (string f in tplFiles)
                    {
                        File.Delete(f);
                    }
                }
                String iFileName = String.Format("{0}\\tpl-{1:000}.bmp", tplDirectory, _previousPoints.Count);
                tpl.Save(iFileName);
            }
            #endregion

            TrackPointBlock tpb = new TrackPointBlock(_x, _y, _t, tpl);
            tpb.IsReferenceBlock = _bManual;
            tpb.Similarity       = _bManual ? 1.0f : _fSimilarity;

            return(tpb);
        }
Esempio n. 4
0
        public override bool Track(List <AbstractTrackPoint> previousPoints, Bitmap currentImage, long position, out AbstractTrackPoint currentPoint)
        {
            //---------------------------------------------------------------------
            // The input informations we have at hand are:
            // - The current bitmap we have to find the point into.
            // - The coordinates of all the previous points tracked.
            // - Previous tracking scores, stored in the TrackPoints tracked so far.
            //---------------------------------------------------------------------
            TrackPointBlock lastTrackPoint = (TrackPointBlock)previousPoints[previousPoints.Count - 1];
            PointF          lastPoint      = lastTrackPoint.Point;
            PointF          subpixel       = new PointF(lastPoint.X - (int)lastPoint.X, lastPoint.Y - (int)lastPoint.Y);

            bool matched = false;

            currentPoint = null;

            if (lastTrackPoint.Template != null && currentImage != null)
            {
                // Center search zone around last point.
                PointF    searchCenter = lastPoint;
                Rectangle searchZone   = new Rectangle((int)(searchCenter.X - (searchWindow.Width / 2)),
                                                       (int)(searchCenter.Y - (searchWindow.Height / 2)),
                                                       searchWindow.Width,
                                                       searchWindow.Height);

                searchZone.Intersect(new Rectangle(0, 0, currentImage.Width, currentImage.Height));

                //Image<Bgr, Byte> cvTemplate = new Image<Bgr, Byte>(lastTrackPoint.Template);
                //Image<Bgr, Byte> cvImage = new Image<Bgr, Byte>(_CurrentImage);

                Bitmap img = currentImage;
                Bitmap tpl = lastTrackPoint.Template;

                BitmapData imageData    = img.LockBits(new Rectangle(0, 0, img.Width, img.Height), ImageLockMode.ReadOnly, img.PixelFormat);
                BitmapData templateData = tpl.LockBits(new Rectangle(0, 0, tpl.Width, tpl.Height), ImageLockMode.ReadOnly, tpl.PixelFormat);

                Image <Bgra, Byte> cvImage    = new Image <Bgra, Byte>(imageData.Width, imageData.Height, imageData.Stride, imageData.Scan0);
                Image <Bgra, Byte> cvTemplate = new Image <Bgra, Byte>(templateData.Width, templateData.Height, templateData.Stride, templateData.Scan0);

                cvImage.ROI = searchZone;

                int resWidth  = searchZone.Width - lastTrackPoint.Template.Width + 1;
                int resHeight = searchZone.Height - lastTrackPoint.Template.Height + 1;

                Image <Gray, Single> similarityMap = new Image <Gray, Single>(resWidth, resHeight);

                //CvInvoke.cvMatchTemplate(cvImage.Ptr, cvTemplate.Ptr, similarityMap.Ptr, TM_TYPE.CV_TM_SQDIFF_NORMED);
                //CvInvoke.cvMatchTemplate(cvImage.Ptr, cvTemplate.Ptr, similarityMap.Ptr, TM_TYPE.CV_TM_CCORR_NORMED);
                CvInvoke.cvMatchTemplate(cvImage.Ptr, cvTemplate.Ptr, similarityMap.Ptr, TM_TYPE.CV_TM_CCOEFF_NORMED);

                img.UnlockBits(imageData);
                tpl.UnlockBits(templateData);

                // Find max
                double bestScore     = 0;
                PointF bestCandidate = new PointF(-1, -1);
                Point  minLoc        = Point.Empty;
                Point  maxLoc        = Point.Empty;
                double min           = 0;
                double max           = 0;
                CvInvoke.cvMinMaxLoc(similarityMap.Ptr, ref min, ref max, ref minLoc, ref maxLoc, IntPtr.Zero);

                if (max > similarityTreshold)
                {
                    PointF loc = RefineLocation(similarityMap.Data, maxLoc, parameters.RefinementNeighborhood);

                    // The template matching was done on a template aligned with the integer part of the actual position.
                    // We reinject the floating point part of the orginal positon into the result.
                    loc = loc.Translate(subpixel.X, subpixel.Y);

                    bestCandidate = new PointF(searchZone.Left + loc.X + tpl.Width / 2, searchZone.Top + loc.Y + tpl.Height / 2);
                    bestScore     = max;
                }

                #region Monitoring
                if (monitoring)
                {
                    // Save the similarity map to file.
                    Image <Gray, Byte> mapNormalized = new Image <Gray, Byte>(similarityMap.Width, similarityMap.Height);
                    CvInvoke.cvNormalize(similarityMap.Ptr, mapNormalized.Ptr, 0, 255, NORM_TYPE.CV_MINMAX, IntPtr.Zero);

                    Bitmap bmpMap = mapNormalized.ToBitmap();

                    string tplDirectory = @"C:\Users\Joan\Videos\Kinovea\Video Testing\Tracking\simimap";
                    bmpMap.Save(tplDirectory + String.Format(@"\simiMap-{0:000}-{1:0.00}.bmp", previousPoints.Count, bestScore));
                }
                #endregion

                // Result of the matching.
                if (bestCandidate.X != -1 && bestCandidate.Y != -1)
                {
                    currentPoint = CreateTrackPoint(false, bestCandidate, bestScore, position, img, previousPoints);
                    ((TrackPointBlock)currentPoint).Similarity = bestScore;
                }
                else
                {
                    // No match. Create the point at the center of the search window (whatever that might be).
                    currentPoint = CreateTrackPoint(false, lastPoint, 0.0f, position, img, previousPoints);
                    log.Debug("Track failed. No block over the similarity treshold in the search window.");
                }

                matched = true;
            }
            else
            {
                // No image. (error case ?)
                // Create the point at the last point location.
                currentPoint = CreateTrackPoint(false, lastPoint, 0.0f, position, currentImage, previousPoints);
                log.Debug("Track failed. No input image, or last point doesn't have any cached block image.");
            }

            return(matched);
        }
Esempio n. 5
0
        public override AbstractTrackPoint CreateTrackPoint(bool manual, PointF p, double similarity, long t, Bitmap currentImage, List <AbstractTrackPoint> previousPoints)
        {
            // Creates a TrackPoint from the input image at the given coordinates.
            // Stores algorithm internal data in the point, to help next match.
            // _t is in relative timestamps from the first point.

            // Copy the template from the image into its own Bitmap.

            Bitmap tpl = new Bitmap(blockWindow.Width, blockWindow.Height, PixelFormat.Format32bppPArgb);
            int    age = 0;

            bool updateWithCurrentImage = true;

            if (!manual && previousPoints.Count > 0 && similarity > templateUpdateThreshold || similarity < similarityTreshold)
            {
                // Do not update the template if it's not that different.
                TrackPointBlock prevBlock = previousPoints[previousPoints.Count - 1] as TrackPointBlock;
                if (prevBlock != null && prevBlock.Template != null)
                {
                    tpl = AForge.Imaging.Image.Clone(prevBlock.Template);
                    updateWithCurrentImage = false;
                    age = prevBlock.TemplateAge + 1;
                }
            }


            if (updateWithCurrentImage)
            {
                BitmapData imageData    = currentImage.LockBits(new Rectangle(0, 0, currentImage.Width, currentImage.Height), ImageLockMode.ReadOnly, currentImage.PixelFormat);
                BitmapData templateData = tpl.LockBits(new Rectangle(0, 0, tpl.Width, tpl.Height), ImageLockMode.ReadWrite, tpl.PixelFormat);

                int pixelSize = 4;

                int tplStride            = templateData.Stride;
                int templateWidthInBytes = blockWindow.Width * pixelSize;
                int tplOffset            = tplStride - templateWidthInBytes;

                int imgStride         = imageData.Stride;
                int imageWidthInBytes = currentImage.Width * pixelSize;
                int imgOffset         = imgStride - (currentImage.Width * pixelSize) + imageWidthInBytes - templateWidthInBytes;

                int startY = (int)(p.Y - (blockWindow.Height / 2.0));
                int startX = (int)(p.X - (blockWindow.Width / 2.0));

                if (startX < 0)
                {
                    startX = 0;
                }

                if (startY < 0)
                {
                    startY = 0;
                }

                unsafe
                {
                    byte *pTpl = (byte *)templateData.Scan0.ToPointer();
                    byte *pImg = (byte *)imageData.Scan0.ToPointer() + (imgStride * startY) + (pixelSize * startX);

                    for (int row = 0; row < blockWindow.Height; row++)
                    {
                        if (startY + row > imageData.Height - 1)
                        {
                            break;
                        }

                        for (int col = 0; col < templateWidthInBytes; col++, pTpl++, pImg++)
                        {
                            if (startX * pixelSize + col < imageWidthInBytes)
                            {
                                *pTpl = *pImg;
                            }
                        }

                        pTpl += tplOffset;
                        pImg += imgOffset;
                    }
                }

                currentImage.UnlockBits(imageData);
                tpl.UnlockBits(templateData);
            }

            #region Monitoring
            if (monitoring && updateWithCurrentImage)
            {
                // Save current template to file, to visually monitor the drift.
                string tplDirectory = @"C:\Users\Joan\Videos\Kinovea\Video Testing\Tracking\simimap";
                if (previousPoints.Count <= 1)
                {
                    // Clean up folder.
                    string[] tplFiles = Directory.GetFiles(tplDirectory, "*.bmp");
                    foreach (string f in tplFiles)
                    {
                        File.Delete(f);
                    }
                }
                String iFileName = String.Format("{0}\\tpl-{1:000}.bmp", tplDirectory, previousPoints.Count);
                tpl.Save(iFileName);
            }
            #endregion

            TrackPointBlock tpb = new TrackPointBlock(p.X, p.Y, t, tpl);
            tpb.TemplateAge      = age;
            tpb.IsReferenceBlock = manual;
            tpb.Similarity       = manual ? 1.0f : similarity;

            return(tpb);
        }
Esempio n. 6
0
        public override AbstractTrackPoint CreateTrackPoint(bool _bManual, int _x, int _y, double _fSimilarity, long _t, Bitmap _CurrentImage, List <AbstractTrackPoint> _previousPoints)
        {
            // Creates a TrackPoint from the input image at the given coordinates.
            // Stores algorithm internal data in the point, to help next match.
            // _t is in relative timestamps from the first point.

            Bitmap   tpl = new Bitmap(m_BlockSize.Width, m_BlockSize.Height, PixelFormat.Format24bppRgb);
            Graphics g   = Graphics.FromImage(tpl);

            UpdateStrategy strategy = m_UpdateStrategy;

            if (_bManual)
            {
                // No points yet, or the user manually changed the point.
                // Use the block from the current image.
                strategy = UpdateStrategy.Current;
            }

            switch (strategy)
            {
            case UpdateStrategy.Original:
                // No update, we keep the original block.
                g.DrawImage(((TrackPointBlock)_previousPoints[0]).Template, 0, 0);
                break;

            case UpdateStrategy.Mixed:
            {
                // Update the template with a mix of the current block around match and the original block selected.

                // Paste the new block.
                Rectangle rDst = new Rectangle(0, 0, m_BlockSize.Width, m_BlockSize.Height);
                Rectangle rSrc = new Rectangle(_x - (m_BlockSize.Width / 2), _y - (m_BlockSize.Height / 2), m_BlockSize.Width, m_BlockSize.Height);
                g.DrawImage(_CurrentImage, rDst, rSrc, GraphicsUnit.Pixel);

                // Paste the original block at 50%.
                ColorMatrix mergeMatrix = new ColorMatrix();
                mergeMatrix.Matrix00 = 1.0f;
                mergeMatrix.Matrix11 = 1.0f;
                mergeMatrix.Matrix22 = 1.0f;
                mergeMatrix.Matrix33 = 0.5f;
                mergeMatrix.Matrix44 = 1.0f;

                ImageAttributes mergeImgAttr = new ImageAttributes();
                mergeImgAttr.SetColorMatrix(mergeMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

                //g.DrawImage(m_SyncMergeImage, rSyncDst, 0, 0, m_SyncMergeImage.Width, m_SyncMergeImage.Height, GraphicsUnit.Pixel, m_SyncMergeImgAttr);
                Bitmap originalTpl = ((TrackPointBlock)_previousPoints[0]).Template;
                g.DrawImage(originalTpl, rDst, 0, 0, m_BlockSize.Width, m_BlockSize.Height, GraphicsUnit.Pixel, mergeImgAttr);

                break;
            }

            case UpdateStrategy.Current:
            case UpdateStrategy.Both:
            default:
            {
                // Update the template with the block around the new position.
                Rectangle rDst = new Rectangle(0, 0, m_BlockSize.Width, m_BlockSize.Height);
                Rectangle rSrc = new Rectangle(_x - (m_BlockSize.Width / 2), _y - (m_BlockSize.Height / 2), m_BlockSize.Width, m_BlockSize.Height);
                g.DrawImage(_CurrentImage, rDst, rSrc, GraphicsUnit.Pixel);
                break;
            }
            }

            TrackPointBlock tpb = new TrackPointBlock(_x, _y, _t, tpl);

            tpb.IsReferenceBlock = _bManual;
            tpb.Similarity       = _bManual ? 1.0f : 0;

            return(tpb);
        }
Esempio n. 7
0
        public override bool Track(List <AbstractTrackPoint> _previousPoints, Bitmap _CurrentImage, long _t, out AbstractTrackPoint _currentPoint)
        {
            //---------------------------------------------------------------------
            // The input informations we have at hand are:
            // - The current bitmap we have to find the point into.
            // - The coordinates of all the previous points tracked.
            // - Previous tracking infos, stored in the TrackPoints tracked so far.
            //---------------------------------------------------------------------

            TrackPointBlock lastTrackPoint = (TrackPointBlock)_previousPoints[_previousPoints.Count - 1];
            Point           lastPoint      = lastTrackPoint.ToPoint();

            // Compute the projected point.
            // (coordinate of the point that would keep following the same motion as in last step).
            Point forecast;

            if (_previousPoints.Count > 1)
            {
                Point penultimate = _previousPoints[_previousPoints.Count - 2].ToPoint();

                int dx = lastPoint.X - penultimate.X;
                int dy = lastPoint.Y - penultimate.Y;

                forecast = new Point(lastPoint.X + dx, lastPoint.Y + dy);
            }
            else
            {
                forecast = _previousPoints[0].ToPoint();
            }

            bool bMatched = false;

            _currentPoint = null;

            if (lastTrackPoint.Template != null && _CurrentImage != null)
            {
                // Center search zone around last point.
                Point     searchCenter = lastPoint;
                Rectangle searchZone   = new Rectangle(searchCenter.X - (m_SearchWindowSize.Width / 2),
                                                       searchCenter.Y - (m_SearchWindowSize.Height / 2),
                                                       m_SearchWindowSize.Width,
                                                       m_SearchWindowSize.Height);

                // Convert to grayscale prior to match, if necessary.
                Bitmap workingImage = m_bWorkOnGrayscale ? Grayscale.CommonAlgorithms.BT709.Apply(_CurrentImage) : _CurrentImage;

                double fBestScore    = 0;
                Point  bestCandidate = new Point(-1, -1);

                if (m_UpdateStrategy == UpdateStrategy.Both)
                {
                    // Try to match the initial reference block in the image first.
                    // If it gets a score over a given threshold, we give it the priority over the I-1 block.
                    // This is an attempt at correcting the drift issue.

                    // Find the last reference block. (last block manually choosen by user.)
                    int iLastReferenceBlock = 0;
                    for (int b = _previousPoints.Count - 1; b >= 0; b--)
                    {
                        if (((TrackPointBlock)_previousPoints[b]).IsReferenceBlock)
                        {
                            iLastReferenceBlock = b;
                            break;
                        }
                    }

                    Bitmap originalTemplate        = ((TrackPointBlock)_previousPoints[iLastReferenceBlock]).Template;
                    Bitmap workingOriginalTemplate = m_bWorkOnGrayscale ? Grayscale.CommonAlgorithms.BT709.Apply(originalTemplate) : originalTemplate;

                    ITemplateMatching originalMatcher;
                    if (m_bCorrelationMatching)
                    {
                        originalMatcher = new CorrelationTemplateMatching(m_fOriginalSimilarityThreshold);
                    }
                    else
                    {
                        originalMatcher = new ExhaustiveTemplateMatching(m_fOriginalSimilarityThreshold);
                    }

                    TemplateMatch[] matchingsOriginal = originalMatcher.ProcessImage(workingImage, workingOriginalTemplate, searchZone);

                    if (matchingsOriginal.Length > 0)
                    {
                        // We found a block with a very good similarity to the original block selected by the user.
                        // It will take precedence over the I-1 block.
                        TemplateMatch tm = matchingsOriginal[0];
                        bestCandidate = new Point(tm.Rectangle.Left + (tm.Rectangle.Width / 2), tm.Rectangle.Top + (tm.Rectangle.Height / 2));
                        fBestScore    = tm.Similarity;

                        if (m_bMonitoring)
                        {
                            log.Debug(String.Format("Original template found with good similarity ({0:0.000}), {1} candidates.", tm.Similarity, matchingsOriginal.Length));
                        }
                    }
                    else
                    {
                        log.Debug(String.Format("Original template not found"));
                    }
                }

                if (bestCandidate.X == -1 || bestCandidate.Y == 1)
                {
                    Bitmap workingTemplate = m_bWorkOnGrayscale ? Grayscale.CommonAlgorithms.BT709.Apply(lastTrackPoint.Template) : lastTrackPoint.Template;

                    ITemplateMatching templateMatcher;
                    if (m_bCorrelationMatching)
                    {
                        templateMatcher = new CorrelationTemplateMatching(m_fSimilarityTreshold);
                    }
                    else
                    {
                        templateMatcher = new ExhaustiveTemplateMatching(m_fSimilarityTreshold);
                    }

                    TemplateMatch[] matchings = templateMatcher.ProcessImage(workingImage, workingTemplate, searchZone);

                    if (matchings.Length > 0)
                    {
                        // Find the best candidate.
                        // Score is weighted average of : similarity and closeness to forecast.
                        int    iBestCandidate  = -1;
                        double fWinnerDistance = 0;
                        for (int i = 0; i < matchings.Length; i++)
                        {
                            TemplateMatch tm = matchings[i];
                            //if(_previousPoints.Count > 1)
                            {
                                Point  candidatePoint      = new Point(tm.Rectangle.Left + (tm.Rectangle.Width / 2), tm.Rectangle.Top + (tm.Rectangle.Height / 2));
                                double fDistanceToForecast = CalibrationHelper.PixelDistance(candidatePoint, forecast);
                                double fScore = GetScore(tm.Similarity, fDistanceToForecast, m_fMaxDistance);

                                if (fScore > fBestScore)
                                {
                                    fBestScore      = fScore;
                                    fWinnerDistance = fDistanceToForecast;
                                    iBestCandidate  = i;
                                    bestCandidate   = candidatePoint;
                                }
                            }
                        }
                        if (m_bMonitoring)
                        {
                            log.Debug(String.Format("Last template found with : Score:{0:0.000}, Similarity:{1:0.000} (index:{2:00}/{3:00}), Distance to forecast (px):{4:0.00}",
                                                    fBestScore,
                                                    matchings[iBestCandidate].Similarity,
                                                    iBestCandidate,
                                                    matchings.Length,
                                                    fWinnerDistance));
                        }
                    }
                    else
                    {
                        log.Debug(String.Format("Last template not found, or score too low."));
                    }
                }

                // Result of the matching.
                if (bestCandidate.X != -1 && bestCandidate.Y != -1)
                {
                    // Save template in the point.
                    _currentPoint = CreateTrackPoint(false, bestCandidate.X, bestCandidate.Y, fBestScore, _t, _CurrentImage, _previousPoints);
                    ((TrackPointBlock)_currentPoint).Similarity = fBestScore;

                    // Finally, it is only considered a match if the score is over the threshold.
                    if (fBestScore >= m_fScoreTreshold || _previousPoints.Count == 1)
                    {
                        bMatched = true;
                    }
                }
                else
                {
                    // No match. Create the point at the center of the search window (whatever that might be).
                    _currentPoint = CreateTrackPoint(false, searchCenter.X, searchCenter.Y, fBestScore, _t, _CurrentImage, _previousPoints);
                    log.Debug("Track failed. No block over the similarity treshold in the search window.");
                }

                #region Monitoring
                if (m_bMonitoring)
                {
                    // Save current template to file, to visually monitor the drift.
                    string tplDirectory = @"C:\Documents and Settings\Administrateur\Mes documents\Dev  Prog\Videa\Video Testing\Tracking\Template Update";
                    if (_previousPoints.Count == 1)
                    {
                        // Clean up folder.
                        string[] tplFiles = Directory.GetFiles(tplDirectory, "*.bmp");
                        foreach (string f in tplFiles)
                        {
                            File.Delete(f);
                        }
                    }
                    String iFileName = String.Format("{0}\\tpl-{1:000}.bmp", tplDirectory, _previousPoints.Count);
                    ((TrackPointBlock)_currentPoint).Template.Save(iFileName);
                }
                #endregion
            }
            else
            {
                // No image. (error case ?)
                // Create the point at the last point location.
                _currentPoint = CreateTrackPoint(false, lastTrackPoint.X, lastTrackPoint.Y, 0.0f, _t, _CurrentImage, _previousPoints);
                log.Debug("Track failed. No input image, or last point doesn't have any cached block image.");
            }

            return(bMatched);
        }