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; }
private unsafe static void goodFeaturesToTrack(Gray <float>[,] integralDxx, Gray <float>[,] integralDxy, Gray <float>[,] integralDyy, int winSize, float minEigValue, Gray <float>[,] strengthImg) { minEigValue = System.Math.Max(1E-3f, minEigValue); int normFactor = winSize * winSize * 255; int maxCol = integralDxx.Width() - winSize; int maxRow = integralDxx.Height() - winSize; for (int row = 0; row < maxRow; row++) { for (int col = 0; col < maxCol; col++) { var Dxx = integralDxx.GetSum(col, row, winSize, winSize); var Dxy = integralDxy.GetSum(col, row, winSize, winSize); var Dyy = integralDyy.GetSum(col, row, winSize, winSize); var eigenVal = calcMinEigenVal(Dxx, Dxy, Dyy); eigenVal /= normFactor; if (eigenVal > minEigValue) { strengthImg[winSize / 2 + row, winSize / 2 + col] = eigenVal; } } } }
private unsafe static void goodFeaturesToTrack(Gray<float>[,] integralDxx, Gray<float>[,] integralDxy, Gray<float>[,] integralDyy, int winSize, float minEigValue, Gray<float>[,] strengthImg) { minEigValue = System.Math.Max(1E-3f, minEigValue); int normFactor = winSize * winSize * 255; int maxCol = integralDxx.Width() - winSize; int maxRow = integralDxx.Height() - winSize; for (int row = 0; row < maxRow; row++) { for (int col = 0; col < maxCol; col++) { var Dxx = integralDxx.GetSum(col, row, winSize, winSize); var Dxy = integralDxy.GetSum(col, row, winSize, winSize); var Dyy = integralDyy.GetSum(col, row, winSize, winSize); var eigenVal = calcMinEigenVal(Dxx, Dxy, Dyy); eigenVal /= normFactor; if (eigenVal > minEigValue) { strengthImg[winSize / 2 + row, winSize / 2 + col] = eigenVal; } } } }
private static ComplexF[,] prepareImage(Gray <float>[,] image, int biggestKernelWidth, int biggestKernelHeight, ConvolutionBorder options, out int fillX, out int fillY) { int FFTNumOfCols = (int)System.Math.Pow(2.0, System.Math.Ceiling(System.Math.Log(biggestKernelWidth + image.Width(), 2.0))); int FFTNumOfRows = (int)System.Math.Pow(2.0, System.Math.Ceiling(System.Math.Log(biggestKernelHeight + image.Height(), 2.0))); fillX = System.Math.Min(image.Width(), biggestKernelWidth / 2); fillY = System.Math.Min(image.Height(), biggestKernelHeight / 2); var paddedImage = new Gray <float> [FFTNumOfRows, FFTNumOfCols]; //center image.CopyTo(paddedImage, new Point(fillX, fillY)); if (options == ConvolutionBorder.BorderMirror) { mirrorBorders(image, paddedImage, fillX, fillY); } var paddedImageCmplx = paddedImage.ToComplex(); paddedImageCmplx.FFT(FourierTransform.Direction.Forward, true); return(paddedImageCmplx); }
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> /// Computes gradient orientations from the color image. Orientation from the channel which has the maximum gradient magnitude is taken as the orientation for a location. /// </summary> /// <param name="frame">Image.</param> /// <param name="magnitudeSqrImage">Squared magnitude image.</param> /// <param name="minValidMagnitude">Minimal valid magnitude.</param> /// <returns>Orientation image (angles are in degrees).</returns> public static unsafe Gray<int>[,] Compute(Gray<byte>[,] frame, out Gray<int>[,] magnitudeSqrImage, int minValidMagnitude) { var minSqrMagnitude = minValidMagnitude * minValidMagnitude; var orientationImage = new Gray<int>[frame.Height(), frame.Width()]; var _magnitudeSqrImage = orientationImage.CopyBlank(); using (var uFrame = frame.Lock()) { ParallelLauncher.Launch(thread => { computeGray(thread, (byte*)uFrame.ImageData, uFrame.Stride, orientationImage, _magnitudeSqrImage, minSqrMagnitude); }, frame.Width() - 2 * kernelRadius, frame.Height() - 2 * kernelRadius); } magnitudeSqrImage = _magnitudeSqrImage; return orientationImage; }
private static IList<PointF> findContour(Gray<byte>[,] templateImg) { var contour = templateImg.FindContour(minGradientStrength: 150).Select(x => (PointF)x).ToList(); /*********** cut bottom border and shift contour beginning to the first non-border point ***************/ int firstIdx = -1; int lastIdx = -1; for (int i = 0; i < contour.Count; i++) { if (contour[i].Y == (templateImg.Height() - 1)) { if (firstIdx == -1) firstIdx = i; lastIdx = i; } } //return contour; return new CircularList<PointF>(contour).GetRange(lastIdx, contour.Count - (lastIdx - firstIdx + 1)); }
private static Gray<byte>[,] QuantizeOrientations(Gray<int>[,] orientDegImg) { var quantizedUnfilteredOrient = new Gray<byte>[orientDegImg.Height(), orientDegImg.Width()]; using (var uOrientDegImg = orientDegImg.Lock()) using (var uQuantizedUnfilteredOrient = quantizedUnfilteredOrient.Lock()) { int* orientDegImgPtr = (int*)uOrientDegImg.ImageData; byte* qOrinetUnfilteredPtr = (byte*)uQuantizedUnfilteredOrient.ImageData; int qOrinetUnfilteredStride = uQuantizedUnfilteredOrient.Stride; int imgWidth = uOrientDegImg.Width; int imgHeight = uOrientDegImg.Height; for (int j = 0; j < imgHeight; j++) { for (int i = 0; i < imgWidth; i++) { int angle = orientDegImgPtr[i]; qOrinetUnfilteredPtr[i] = AngleQuantizationTable[angle]; //[0-360] -> [...] -> [0-7] (for mapping see "CalculateAngleQuantizationTable()") } orientDegImgPtr += imgWidth; //<Gray<int>> is always alligned qOrinetUnfilteredPtr += qOrinetUnfilteredStride; } } //quantizedUnfilteredOrient.Mul(36).Save("quantizedUnfilteredImg.bmp"); return quantizedUnfilteredOrient; }
/// <summary> /// Creates linear response maps. /// </summary> /// <param name="orientationDegImg">Orientation image (in degrees).</param> /// <param name="neigborhood">Spread neighborhood size.</param> public LinearizedMaps(Gray<int>[,] orientationDegImg, int neigborhood) { this.NeigborhoodSize = neigborhood; this.ImageSize = orientationDegImg.Size(); this.LinearMapSize = new Size(orientationDegImg.Width() / neigborhood, orientationDegImg.Height() / neigborhood); this.ImageValidSize = new Size(this.LinearMapSize.Width * neigborhood, this.LinearMapSize.Height * neigborhood); this.LinearMaps = calculate(orientationDegImg); }