public void ApplyTest() { var img1 = Properties.Resources.image2; var img2 = Properties.Resources.image2; MatrixH homography = new MatrixH(1, 0, 32, 0, 1, 0, 0, 0); Blend blend = new Blend(homography, img1); var actual = blend.Apply(img2); Assert.AreEqual(64, actual.Size.Width); Assert.AreEqual(32, actual.Size.Height); homography = new MatrixH(1, 0, 32, 0, 1, 32, 0, 0); blend = new Blend(homography, img1); actual = blend.Apply(img2); Assert.AreEqual(64, actual.Size.Width); Assert.AreEqual(64, actual.Size.Height); // ImageBox.Show(img3, PictureBoxSizeMode.Zoom); }
/// <summary> /// The blending filter is able to blend two images using a homography matrix. /// A linear alpha gradient is used to smooth out differences between the two /// images, effectively blending them in two images. The gradient is computed /// considering the distance between the centers of the two images. /// </summary> /// <param name="im">Image.</param> /// <param name="overlayIm">The overlay image (also called the anchor).</param> /// <param name="homography">Homography matrix used to map a image passed to /// the filter to the overlay image specified at filter creation.</param> /// <param name="fillColor">The filling color used to fill blank spaces. The filling color will only be visible after the image is converted /// to 24bpp. The alpha channel will be used internally by the filter.</param> /// <param name="gradient">A value indicating whether to blend using a linear /// gradient or just superimpose the two images with equal weights.</param> /// <param name="alphaOnly">A value indicating whether only the alpha channel /// should be blended. This can be used together with a transparency /// mask to selectively blend only portions of the image.</param> /// <returns>Blended image.</returns> public static Bgra<byte>[,] Blend(this Gray<byte>[,] im, Gray<byte>[,] overlayIm, MatrixH homography, Bgra<byte> fillColor, bool gradient = true, bool alphaOnly = false) { Bgra<byte>[,] resultImage = null; using (var uOverlayIm = overlayIm.Lock()) { Blend blend = new Blend(homography, uOverlayIm.AsBitmap()); blend.AlphaOnly = alphaOnly; blend.Gradient = gradient; blend.FillColor = fillColor.ToColor(); resultImage = im.ApplyBaseTransformationFilter<Gray<byte>, Bgra<byte>>(blend); } return resultImage; }
public void MultiplyTest() { MatrixH A = new MatrixH(); MatrixH B = new MatrixH(); MatrixH expected = new MatrixH(); MatrixH actual = A.Multiply(B); Assert.IsTrue(Accord.Math.Matrix.IsEqual( expected.Elements, actual.Elements)); double[,] a = { { 2, 3, 1 }, { 2, 1, 7 }, { 1, 2, 2 } }; double[,] b = { { 1, 3, 1 }, { -2, 1, -4 }, { 1, -1, 3 } }; A = new MatrixH(a); B = new MatrixH(b); actual = A.Multiply(B); expected = new MatrixH(Accord.Math.Matrix.Multiply(a, b)); Assert.IsTrue(Accord.Math.Matrix.IsEqual( (double[,])actual, (double[,])expected, 0.001)); }
/// <summary> /// Normalizes a set of homogeneous points so that the origin is located /// at the centroid and the mean distance to the origin is sqrt(2). /// </summary> public static PointF[] Normalize(this PointF[] points, out MatrixH transformation) { float[,] H; var result = Normalize(points, out H); transformation = new MatrixH(H); return result; }
/// <summary> /// Creates an homography matrix matching points /// from a set of points to another. /// </summary> /// public static MatrixH Homography(PointF[] points1, PointF[] points2) { // Initial argument checks if (points1.Length != points2.Length) throw new ArgumentException("The number of points should be equal."); if (points1.Length < 4) throw new ArgumentException("At least four points are required to fit an homography"); int N = points1.Length; MatrixH T1, T2; // Normalize input points points1 = Tools.Normalize(points1, out T1); points2 = Tools.Normalize(points2, out T2); // Create the matrix A var A = new float[3 * N, 9]; for (int i = 0; i < N; i++) { PointF X = points1[i]; float x = points2[i].X; float y = points2[i].Y; int r = 3 * i; A[r, 0] = 0; A[r, 1] = 0; A[r, 2] = 0; A[r, 3] = -X.X; A[r, 4] = -X.Y; A[r, 5] = -1; A[r, 6] = y * X.X; A[r, 7] = y * X.Y; A[r, 8] = y; r++; A[r, 0] = X.X; A[r, 1] = X.Y; A[r, 2] = 1; A[r, 3] = 0; A[r, 4] = 0; A[r, 5] = 0; A[r, 6] = -x * X.X; A[r, 7] = -x * X.Y; A[r, 8] = -x; r++; A[r, 0] = -y * X.X; A[r, 1] = -y * X.Y; A[r, 2] = -y; A[r, 3] = x * X.X; A[r, 4] = x * X.Y; A[r, 5] = x; A[r, 6] = 0; A[r, 7] = 0; A[r, 8] = 0; } // Create the singular value decomposition SingularValueDecompositionF svd = new SingularValueDecompositionF(A, computeLeftSingularVectors: false, computeRightSingularVectors: true, autoTranspose: false, inPlace: true); float[,] V = svd.RightSingularVectors; // Extract the homography matrix MatrixH H = new MatrixH(V[0, 8], V[1, 8], V[2, 8], V[3, 8], V[4, 8], V[5, 8], V[6, 8], V[7, 8], V[8, 8]); // Denormalize H = T2.Inverse().Multiply(H.Multiply(T1)); return H; }
public void ApplyTest2() { var img1 = Properties.Resources.image2; var img2 = Properties.Resources.image2; var img3 = Properties.Resources.image2; var img4 = Properties.Resources.image2; MatrixH homography; Blend blend; homography = new MatrixH(1, 0, 32, 0, 1, 0, 0, 0); blend = new Blend(homography, img1); var img12 = blend.Apply(img2); //ImageBox.Show("Blend of 1 and 2", img12, PictureBoxSizeMode.Zoom); Assert.AreEqual(img12.PixelFormat, PixelFormat.Format32bppArgb); blend = new Blend(homography, img3); var img34 = blend.Apply(img4); //ImageBox.Show("Blend of 3 and 4", img34, PictureBoxSizeMode.Zoom); Assert.AreEqual(img34.PixelFormat, PixelFormat.Format32bppArgb); homography = new MatrixH(1, 0, 64, 0, 1, 0, 0, 0); blend = new Blend(homography, img12); var img1234 = blend.Apply(img34); //ImageBox.Show("Blend of 1, 2, 3, 4", img1234, PictureBoxSizeMode.Zoom); Assert.AreEqual(img1234.PixelFormat, PixelFormat.Format32bppArgb); // Blend of 1 and 5 (8bpp and 32bpp) homography = new MatrixH(1, 0, 0, 0, 1, 32, 0, 0); //ImageBox.Show("Image 1", img1, PictureBoxSizeMode.Zoom); blend = new Blend(homography, img1234); var img15 = blend.Apply(img1); //ImageBox.Show("Blend of 1 and 5", img15, PictureBoxSizeMode.Zoom); Assert.AreEqual(img1234.PixelFormat, PixelFormat.Format32bppArgb); Assert.AreEqual(img1.PixelFormat, PixelFormat.Format8bppIndexed); Assert.AreEqual(img15.PixelFormat, PixelFormat.Format32bppArgb); Assert.AreEqual(128, img15.Width); Assert.AreEqual(64, img15.Height); }
/// <summary> /// Multiplies this matrix, returning a new matrix as result. /// </summary> /// public MatrixH Multiply(MatrixH matrix) { float na = elements[0] * matrix.elements[0] + elements[1] * matrix.elements[3] + elements[2] * matrix.elements[6]; float nb = elements[0] * matrix.elements[1] + elements[1] * matrix.elements[4] + elements[2] * matrix.elements[7]; float nc = elements[0] * matrix.elements[2] + elements[1] * matrix.elements[5] + elements[2]; float nd = elements[3] * matrix.elements[0] + elements[4] * matrix.elements[3] + elements[5] * matrix.elements[6]; float ne = elements[3] * matrix.elements[1] + elements[4] * matrix.elements[4] + elements[5] * matrix.elements[7]; float nf = elements[3] * matrix.elements[2] + elements[4] * matrix.elements[5] + elements[5]; float ng = elements[6] * matrix.elements[0] + elements[7] * matrix.elements[3] + matrix.elements[6]; float nh = elements[6] * matrix.elements[1] + elements[7] * matrix.elements[4] + matrix.elements[7]; float ni = elements[6] * matrix.elements[2] + elements[7] * matrix.elements[5] + 1f; return new MatrixH(na, nb, nc, nd, ne, nf, ng, nh, ni); }
/// <summary> /// Matches detected keypoints. /// </summary> private void MatchKeypoints() { // matching keypoints step needs at least two images if (input_images.Count < 2) return; // using RANSAC homography estimator RansacHomographyEstimator ransac = new RansacHomographyEstimator(0.001, 0.99); CorrelationMatching matcher = new CorrelationMatching(9); Bitmap mergedImage = new Bitmap(input_images.Count * input_images[0].Width, input_images[0].Height); //it is assumed the images are of same size! Graphics graphics = Graphics.FromImage(mergedImage); IntPoint[][] matches; int cumulativeWidth = 0; int keypoints_cntr = 0; // draw all images for (int i = 0; i < input_images.Count; i++) { graphics.DrawImage(input_images[i], cumulativeWidth, 0, input_images[i].Width, input_images[i].Height); cumulativeWidth += input_images[i].Width; } // iterate through all images for (int i = 0; i < input_images.Count; i++) { if (i != input_images.Count - 1) { // match detected keypoints with maximum cross-correlation algorithm matches = matcher.Match(new Bitmap(input_images[i]), new Bitmap(input_images[i + 1]), keypoints[keypoints_cntr].ToArray(), keypoints[keypoints_cntr + 1].ToArray()); IntPoint[] correlationPoints1 = matches[0]; IntPoint[] correlationPoints2 = matches[1]; // Plot RANSAC results against correlation results homography = ransac.Estimate(correlationPoints1, correlationPoints2); // take only inliers - good matches IntPoint[] inliers1 = correlationPoints1.Submatrix(ransac.Inliers); IntPoint[] inliers2 = correlationPoints2.Submatrix(ransac.Inliers); PairsMarker pairs = new PairsMarker(correlationPoints1, correlationPoints2.Apply(p => new IntPoint(p.X + input_images[i].Width, p.Y))); // draw all matching pairs for (int j = 0; j < pairs.Points1.Count(); j++) { if (i % 2 == 0) graphics.DrawLine(new Pen(Color.Red, 1.5f), new System.Drawing.Point(correlationPoints1[j].X + i * input_images[i].Width, correlationPoints1[j].Y), new System.Drawing.Point(correlationPoints2[j].X + (i + 1) * input_images[i].Width, correlationPoints2[j].Y)); } // draw inliers for (int j = 0; j < inliers1.Count(); j++) { if (i % 2 == 0) graphics.DrawLine(new Pen(Color.GreenYellow, 1.5f), new System.Drawing.Point(inliers1[j].X + i * input_images[i].Width, inliers1[j].Y), new System.Drawing.Point(inliers2[j].X + (i + 1) * input_images[i].Width, inliers2[j].Y)); else graphics.DrawLine(new Pen(Color.Blue, 1.5f), new System.Drawing.Point(inliers1[j].X + i * input_images[i].Width, inliers1[j].Y), new System.Drawing.Point(inliers2[j].X + (i + 1) * input_images[i].Width, inliers2[j].Y)); } keypoints_cntr += 2; } } ShowThumbnail(mergedImage, true, PanoramaPhase.MatchKeypoints); }
private void button2_Click(object sender, EventArgs e) { // Step 3: Create the homography matrix using a robust estimator RansacHomographyEstimator ransac = new RansacHomographyEstimator(0.001, 0.99); homography = ransac.Estimate(correlationPoints1, correlationPoints2); // Plot RANSAC results against correlation results IntPoint[] inliers1 = correlationPoints1.Submatrix(ransac.Inliers); IntPoint[] inliers2 = correlationPoints2.Submatrix(ransac.Inliers); // Concatenate the two images in a single image (just to show on screen) Concatenate concat = new Concatenate(img1); Bitmap img3 = concat.Apply(img2); // Show the marked correlations in the concatenated image PairsMarker pairs = new PairsMarker( inliers1, // Add image1's width to the X points to show the markings correctly inliers2.Apply(p => new IntPoint(p.X + img1.Width, p.Y))); pictureBox1.Image = pairs.Apply(img3); numA.Value = (decimal)homography.Elements[0]; numB.Value = (decimal)homography.Elements[1]; numC.Value = (decimal)homography.Elements[2]; numD.Value = (decimal)homography.Elements[3]; numE.Value = (decimal)homography.Elements[4]; numF.Value = (decimal)homography.Elements[5]; numG.Value = (decimal)homography.Elements[6]; numH.Value = (decimal)homography.Elements[7]; }
public void MultiplyTest() { MatrixH matrix = new MatrixH(Matrix.Identity(3)); PointH[] points = new PointH[] { new PointH(1, 2), new PointH(5, 2), new PointH(12, 2), new PointH(1, 2), new PointH(10, 2), }; PointH[] expected = new PointH[] { new PointH(1, 2), new PointH(5, 2), new PointH(12, 2), new PointH(1, 2), new PointH(10, 2), }; PointH[] actual = (PointH[])points.Clone(); matrix.TransformPoints(actual); Assert.AreEqual(expected[0], actual[0]); Assert.AreEqual(expected[1], actual[1]); Assert.AreEqual(expected[2], actual[2]); Assert.AreEqual(expected[3], actual[3]); Assert.AreEqual(expected[4], actual[4]); }
private bool GenerateKeypointMatches(Bitmap target, Bitmap frame, Rectangle prevTarget) { HarrisCornersDetector harrisDetector = new HarrisCornersDetector(HarrisCornerMeasure.Harris, 1000f, 1f, 2); targetKeyPoints=harrisDetector.ProcessImage(target).ToArray(); frameKeyPoints=harrisDetector.ProcessImage(frame).ToArray(); //Console.WriteLine("tr={0} fr={1}", targetKeyPoints.Length, frameKeyPoints.Length); if (targetKeyPoints.Length==0||frameKeyPoints.Length==0) { return false; } CorrelationMatching matcher=new CorrelationMatching(15); IntPoint[][] matches=matcher.Match(target, frame, targetKeyPoints, frameKeyPoints); targetMacthes=matches[0]; frameMatches=matches[1]; if (targetMacthes.Length<4||frameMatches.Length<4) { return false; } RansacHomographyEstimator ransac=new RansacHomographyEstimator(0.1, 0.50); MatrixH estiment = new MatrixH(); try { estiment = ransac.Estimate(targetMacthes, frameMatches); } catch { return false; } IntPoint[] targetGoodMatch=targetMacthes.Submatrix(ransac.Inliers); IntPoint[] frameGoodMatch=frameMatches.Submatrix(ransac.Inliers); CalculatePosChange(targetGoodMatch, frameGoodMatch, prevTarget); return true; }
/// <summary> /// Constructs a new Blend filter. /// </summary> /// /// <param name="homography">The homography matrix mapping a second image to the overlay image.</param> /// <param name="overlayImage">The overlay image (also called the anchor).</param> /// public Blend(MatrixH homography, Bitmap overlayImage) { this.homography = homography; this.overlayImage = overlayImage; formatTranslations[PixelFormat.Format8bppIndexed] = PixelFormat.Format32bppArgb; formatTranslations[PixelFormat.Format24bppRgb] = PixelFormat.Format32bppArgb; formatTranslations[PixelFormat.Format32bppArgb] = PixelFormat.Format32bppArgb; }
private void BtnRansac_OnClick(object sender, RoutedEventArgs e) { // Step 3: Create the homography matrix using a robust estimator RansacHomographyEstimator ransac = new RansacHomographyEstimator(0.001, 0.99); homography = ransac.Estimate(correlationPoints1, correlationPoints2); // Plot RANSAC results against correlation results IntPoint[] inliers1 = correlationPoints1.Submatrix(ransac.Inliers); IntPoint[] inliers2 = correlationPoints2.Submatrix(ransac.Inliers); // Concatenate the two images in a single image (just to show on screen) Concatenate concat = new Concatenate(img1); Bitmap img3 = concat.Apply(img2); // Show the marked correlations in the concatenated image PairsMarker pairs = new PairsMarker( inliers1, // Add image1's width to the X points to show the markings correctly inliers2.Apply(p => new IntPoint(p.X + img1.Width, p.Y))); PictureBox.Source = pairs.Apply(img3); }
public void ApplyTest() { Bitmap img1 = Properties.Resources.image2; MatrixH homography = new MatrixH(1, 0, 32, 0, 1, 0, 0, 0); ProjectiveTransform transform = new ProjectiveTransform(homography); transform.FillColor = Color.Red; Bitmap actual = transform.Apply(img1); ImageBox.Show(actual, PictureBoxSizeMode.Zoom); Assert.AreEqual(64, actual.Size.Width); Assert.AreEqual(32, actual.Size.Height); homography = new MatrixH(2, 0, 0, 0, 2, 0, 0, 0); transform = new ProjectiveTransform(homography); transform.FillColor = Color.Red; actual = transform.Apply(img1); ImageBox.Show(actual, PictureBoxSizeMode.Zoom); Assert.AreEqual(32, actual.Size.Width); Assert.AreEqual(32, actual.Size.Height); homography = new MatrixH(2, 0, 32, 0, 0.5f, 32, 0, 0); transform = new ProjectiveTransform(homography); transform.FillColor = Color.Red; actual = transform.Apply(img1); ImageBox.Show(actual, PictureBoxSizeMode.Zoom); Assert.AreEqual(32 / 2 + 32, actual.Size.Width); Assert.AreEqual(32 / 0.5 + 32, actual.Size.Height); homography = new MatrixH(1, 0, -32, 0, 1, 0, 0, 0); transform = new ProjectiveTransform(homography); transform.FillColor = Color.Red; actual = transform.Apply(img1); ImageBox.Show(actual, PictureBoxSizeMode.Zoom); Assert.AreEqual(64, actual.Size.Width); Assert.AreEqual(32, actual.Size.Height); }
/// <summary> /// Compute inliers using the Symmetric Transfer Error, /// </summary> /// private int[] distance(MatrixH H, double t) { // Compute the projections (both directions) PointF[] p1 = H.TransformPoints(pointSet1); PointF[] p2 = H.Inverse().TransformPoints(pointSet2); // Compute the distances for (int i = 0; i < pointSet1.Length; i++) { // Compute the distance as float ax = pointSet1[i].X - p2[i].X; float ay = pointSet1[i].Y - p2[i].Y; float bx = pointSet2[i].X - p1[i].X; float by = pointSet2[i].Y - p1[i].Y; d2[i] = (ax * ax) + (ay * ay) + (bx * bx) + (by * by); } // Find and return the inliers return Matrix.Find(d2, z => z < t); }
private void btnRansac_Click(object sender, EventArgs e) { if (correlationPoints1 == null) { MessageBox.Show("Please, click Nearest Neighbor button first! :-)"); return; } if (correlationPoints1.Length < 4 || correlationPoints2.Length < 4) { MessageBox.Show("Insufficient points to attempt a fit."); return; } // Step 3: Create the homography matrix using a robust estimator RansacHomographyEstimator ransac = new RansacHomographyEstimator(0.001, 0.99); homography = ransac.Estimate(correlationPoints1, correlationPoints2); // Plot RANSAC results against correlation results IntPoint[] inliers1 = correlationPoints1.Submatrix(ransac.Inliers); IntPoint[] inliers2 = correlationPoints2.Submatrix(ransac.Inliers); // Concatenate the two images in a single image (just to show on screen) Concatenate concat = new Concatenate(img1); Bitmap img3 = concat.Apply(img2); // Show the marked correlations in the concatenated image PairsMarker pairs = new PairsMarker( inliers1, // Add image1's width to the X points to show the markings correctly inliers2.Apply(p => new IntPoint(p.X + img1.Width, p.Y))); pictureBox.Image = pairs.Apply(img3); }
/// <summary> /// Creates an homography matrix matching points /// from a set of points to another. /// </summary> public static MatrixH Homography(PointH[] points1, PointH[] points2) { // Initial argument checkings if (points1.Length != points2.Length) { throw new ArgumentException("The number of points should be equal."); } if (points1.Length < 4) { throw new ArgumentException("At least four points are required to fit an homography"); } int N = points1.Length; MatrixH T1, T2; // Normalize input points points1 = Tools.Normalize(points1, out T1); points2 = Tools.Normalize(points2, out T2); // Create the matrix A double[,] A = new double[3 * N, 9]; for (int i = 0; i < N; i++) { PointH X = points1[i]; double x = points2[i].X; double y = points2[i].Y; double w = points2[i].W; int r = 3 * i; A[r, 0] = 0; A[r, 1] = 0; A[r, 2] = 0; A[r, 3] = -w * X.X; A[r, 4] = -w * X.Y; A[r, 5] = -w * X.W; A[r, 6] = y * X.X; A[r, 7] = y * X.Y; A[r, 8] = y * X.W; r++; A[r, 0] = w * X.X; A[r, 1] = w * X.Y; A[r, 2] = w * X.W; A[r, 3] = 0; A[r, 4] = 0; A[r, 5] = 0; A[r, 6] = -x * X.X; A[r, 7] = -x * X.Y; A[r, 8] = -x * X.W; r++; A[r, 0] = -y * X.X; A[r, 1] = -y * X.Y; A[r, 2] = -y * X.W; A[r, 3] = x * X.X; A[r, 4] = x * X.Y; A[r, 5] = x * X.W; A[r, 6] = 0; A[r, 7] = 0; A[r, 8] = 0; } // Create the singular value decomposition SingularValueDecomposition svd = new SingularValueDecomposition(A, false, true); double[,] V = svd.RightSingularVectors; // Extract the homography matrix MatrixH H = new MatrixH((float)V[0, 8], (float)V[1, 8], (float)V[2, 8], (float)V[3, 8], (float)V[4, 8], (float)V[5, 8], (float)V[6, 8], (float)V[7, 8], (float)V[8, 8]); // Denormalize H = T2.Inverse().Multiply(H.Multiply(T1)); return(H); }