/// <summary> /// Process a new video frame. /// </summary> public void ProcessFrame(UnmanagedImage frame) { filterImage = filter.Apply(frame); Blob blob = extractBlob(); if (blob == null) { trackingObject.Reset(); return; } trackingObject.Rectangle = blob.Rectangle; trackingObject.Center = (IntPoint)blob.CenterOfGravity; if (rotation) { // Locate moments CentralMoments moments = new CentralMoments(); moments.Compute(filterImage, blob.Rectangle); trackingObject.Angle = moments.GetOrientation(); } if (extract) { blobCounter.ExtractBlobsImage(filterImage, blob, false); trackingObject.Image = blob.Image; } }
public void ComputeTest() { Bitmap image = Accord.Imaging.Image.Clone(Resources.hu); CentralMoments target = new CentralMoments(image, order: 3); Assert.AreEqual(86424.0 / target.Mu00, 1, 1e-4); Assert.AreEqual(0, target.Mu01); Assert.AreEqual(0, target.Mu10); Assert.AreEqual(5.868206472635379E8 / target.Mu02, 1, 1e-2); Assert.AreEqual(6348920.945848465 / target.Mu11, 1, 1e-2); Assert.AreEqual(9.084235762166061E8 / target.Mu20, 1, 1e-3); Assert.AreEqual(-2.155191E9 / target.Mu12, 1, 1e-4); Assert.AreEqual(7.125893E8 / target.Mu21, 1, 1e-3); Assert.AreEqual(-1.26244547E10 / target.Mu30, 1, 1e-4); Assert.AreEqual(1.71818829E9 / target.Mu03, 1, 1e-4); SizeF size = target.GetSize(); float angle = target.GetOrientation(); Assert.AreEqual(410.207916f, size.Height); Assert.AreEqual(329.534637f, size.Width); Assert.AreEqual(0.0196384024f, angle, 1e-4); }
/// <summary> /// Computes the Hu moments from the specified central moments. /// </summary> /// /// <param name="moments">The central moments to use as base of calculations.</param> /// public void Compute(CentralMoments moments) { double inv = 1.0 / moments.Mu00; double inv2 = 1.0 / (moments.Mu00 * moments.Mu00); double inv5d2 = System.Math.Sqrt(inv2 * inv2 * inv); float n20 = (float)(moments.Mu20 * inv2); float n02 = (float)(moments.Mu02 * inv2); float n11 = (float)(moments.Mu11 * inv2); float n21 = (float)(moments.Mu21 * inv5d2); float n12 = (float)(moments.Mu12 * inv5d2); float n30 = (float)(moments.Mu30 * inv5d2); float n03 = (float)(moments.Mu03 * inv5d2); // (η20 + η02) I1 = (n20 + n02); // (η20 − η02)² + 4 η11² I2 = (n20 - n02) * (n20 - n02) + 4 * (n11 * n11); // (η30 − 3 η12)² I3 = (n30 - 3 * n12) * (n30 - 3 * n12) // + (3 η21 − η03)² + (3 * n21 - n03) * (3 * n21 - n03); // (η30 + η12)² + (η21 + η03)² I4 = (n30 + n12) * (n30 + n12) + (n21 + n03) * (n21 + n03); // (η30 − 3 η12) (η30 + η12) [(η30 + η12)² −3 (η21 + η03)² ] I5 = (n30 - 3 * n12) * (n30 + n12) * ((n30 + n12) * (n30 + n12) - 3 * (n21 + n03) * (n21 + n03)) // (3 η21 − η03) (η21 + η03) [3 (η30 + η12)² − (η21 + η03)² ] + (3 * n21 - n03) * (n21 + n03) * (3 * (n30 + n12) * (n30 + n12) - (n21 + n03) * (n21 + n03)); // (η20 − η02) [(η30 + η12)² − (η21 + η03)² ] I6 = (n20 - n02) * ((n30 + n12) * (n30 + n12) - (n21 + n03) * (n21 + n03)) // + 4 η11 (η30 + η12) (η21 + η03) + 4 * n11 * (n30 + n12) * (n21 + n03); // (3 η21 − η03) (η30 + η12) [(η30 + η12)² − 3 (η21 + η03)² ] I7 = (3 * n21 - n03) * (n30 + n12) * (n30 + n12) * ((n30 + n12) * (n30 + n12) - 3 * (n21 + n03) * (n21 + n03)) // - (η30 − 3 η12) (η21 + η03) [3 (η30 + η12)² − (η21 + η03)² ] - (n30 - 3 * n12) * (n21 + n03) * (3 * (n30 + n12) * (n30 + n12) - (n21 + n03) * (n21 + n03)); }
internal override void Compute(IImage image) { RawMoments raw = new RawMoments(Order); raw.Compute(image); CentralMoments center = new CentralMoments(raw); this.Compute(center); }
/// <summary> /// Computes moments for the provided image. /// </summary> /// <param name="image">Image.</param> /// <param name="area">Area</param> public void Compute(Gray <float>[,] image, Rectangle area) { RawMoments raw = new RawMoments(Order); raw.Compute(image, area); CentralMoments center = new CentralMoments(raw); this.Compute(center); }
public void ComputeTest2() { // 0 and 1 are only translated var cm0 = new CentralMoments(Accord.Imaging.Image.Clone(Resources.hu0), 3); var cm1 = new CentralMoments(Accord.Imaging.Image.Clone(Resources.hu1), 3); Assert.AreEqual(cm0.Mu00, cm1.Mu00); Assert.AreEqual(cm0.Mu01, cm1.Mu01); Assert.AreEqual(cm0.Mu10, cm1.Mu10); Assert.AreNotEqual(cm0.Mu11, cm1.Mu11); }
public void ComputeTest2() { // 0 and 1 are only translated var cm0 = new CentralMoments(Resources.hu0, 3); var cm1 = new CentralMoments(Resources.hu1, 3); Assert.AreEqual(cm0.Mu00, cm1.Mu00); Assert.AreEqual(cm0.Mu01, cm1.Mu01); Assert.AreEqual(cm0.Mu10, cm1.Mu10); Assert.AreNotEqual(cm0.Mu11, cm1.Mu11); }
private static Rectangle process(Gray <byte>[,] probabilityMap, Rectangle roi, TermCriteria termCriteria, out CentralMoments centralMoments) { Rectangle imageArea = new Rectangle(0, 0, probabilityMap.Width(), probabilityMap.Height()); Rectangle searchWindow = roi; RawMoments moments = new RawMoments(order: 1); // Mean shift with fixed number of iterations int i = 0; double shift = Byte.MaxValue; while (termCriteria.ShouldTerminate(i, shift) == false && !searchWindow.IsEmptyArea()) { // Locate first order moments moments.Compute(probabilityMap, searchWindow); int shiftX = (int)(moments.CenterX - searchWindow.Width / 2f); int shiftY = (int)(moments.CenterY - searchWindow.Height / 2f); // Shift the mean (centroid) searchWindow.X += shiftX; searchWindow.Y += shiftY; // Keep the search window inside the image searchWindow.Intersect(imageArea); shift = System.Math.Abs((double)shiftX) + System.Math.Abs((double)shiftY); //for term criteria only i++; } if (searchWindow.IsEmptyArea() == false) { // Locate second order moments and perform final shift moments.Order = 2; moments.Compute(probabilityMap, searchWindow); searchWindow.X += (int)(moments.CenterX - searchWindow.Width / 2f); searchWindow.Y += (int)(moments.CenterY - searchWindow.Height / 2f); // Keep the search window inside the image searchWindow.Intersect(imageArea); } centralMoments = new CentralMoments(moments); // moments to be used by camshift return(searchWindow); }
/// <summary> /// Camshift algorithm /// </summary> /// <param name="probabilityMap">Probability map [0-255].</param> /// <param name="roi">Initial Search area</param> /// <param name="termCriteria">Mean shift termination criteria (PLEASE DO NOT REMOVE (but you can move it) THIS CLASS; PLEASE!!!)</param> /// <param name="centralMoments">Calculated central moments (up to order 2).</param> /// <returns>Object position, size and angle packed into a structure.</returns> public static Box2D Process(Gray <byte>[,] probabilityMap, Rectangle roi, TermCriteria termCriteria, out CentralMoments centralMoments) { // Compute mean shift Rectangle objArea = Meanshift.Process(probabilityMap, roi, termCriteria, out centralMoments); //fit ellipse Ellipse ellipse = centralMoments.GetEllipse(); ellipse.Center = objArea.Center(); //return empty structure is the object is lost var sz = ellipse.Size; if (Single.IsNaN(sz.Width) || Single.IsNaN(sz.Height) || sz.Width < 1 || sz.Height < 1) { return(Box2D.Empty); } return((Box2D)ellipse); }
/// <summary> /// Camshift algorithm /// </summary> /// private void camshift(UnmanagedImage frame) { int width = frame.Width; int height = frame.Height; Rectangle area = new Rectangle(0, 0, width, height); // Compute tracking object center float objX = Math.Max(0, Math.Min(searchWindow.X + searchWindow.Width * 0.5f, width)); float objY = Math.Max(0, Math.Min(searchWindow.Y + searchWindow.Height * 0.5f, height)); float objAngle; // Compute mean shift CentralMoments moments = meanShift(frame); SizeF objSize = moments.GetSizeAndOrientation(out objAngle); if (Single.IsNaN(objSize.Width) || Single.IsNaN(objSize.Height) || Single.IsNaN(objAngle) || objSize.Width < 1 || objSize.Height < 1) { Reset(); return; } // Truncate to integer coordinates IntPoint center = new IntPoint((int)objX, (int)objY); Rectangle rec = new Rectangle((int)(objX - objSize.Width * 0.5f), (int)(objY - objSize.Height * 0.5f), (int)objSize.Width, (int)objSize.Height); angleHistory.Push(objAngle); // Create tracking object IsSteady = checkSteadiness(); trackingObject.Rectangle = rec; trackingObject.Center = center; trackingObject.Angle = smooth ? (float)angleHistory.Mean : objAngle; if (extract) { Rectangle inner = rec; xHistory.Push(rec.X); yHistory.Push(rec.Y); widthHistory.Push(rec.Width); heightHistory.Push(rec.Height); inner.X = (int)xHistory.Mean; inner.Y = (int)yHistory.Mean; inner.Width = (int)widthHistory.Mean; inner.Height = (int)heightHistory.Mean; inner.Intersect(area); Crop crop = new Crop(inner); // TODO: Perform rotation of the extracted object //RotateNearestNeighbor rotate = new RotateNearestNeighbor((objAngle - Math.PI / 2) * 180f / Math.PI, true); //trackingObject.Image = rotate.Apply(crop.Apply(frame)); trackingObject.Image = crop.Apply(frame); } // Compute a new search window size searchWindow.Width = (int)(1.1f * objSize.Width); searchWindow.Height = (int)((aspectRatio != 0) ? (aspectRatio * objSize.Width) : (1.1f * objSize.Height)); }
/// <summary> /// Meanshift algorithm /// </summary> /// <param name="probabilityMap">Probability map [0-255].</param> /// <param name="roi">Initial search area</param> /// <param name="termCriteria">Mean shift termination criteria</param> /// <param name="centralMoments">Calculated central moments (up to order 2).</param> /// <returns>Object area.</returns> public static Rectangle Process(Gray <byte>[,] probabilityMap, Rectangle roi, TermCriteria termCriteria, out CentralMoments centralMoments) { return(process(probabilityMap, roi, termCriteria, out centralMoments)); }