// Draws the Delaunay triangulation into an image using the triangle indexes private void DrawDelaunay(ref Mat img, ref VectorOfPointF points, VectorOfVectorOfInt triangleIndexes, MCvScalar delaunayColor) { Size size = img.Size; Rectangle rect = new Rectangle(0, 0, size.Width, size.Height); for (int i = 0; i < triangleIndexes.Size; i++) { VectorOfPoint tri = new VectorOfPoint(); PointF pp0 = points[triangleIndexes[i][0]]; PointF pp1 = points[triangleIndexes[i][1]]; PointF pp2 = points[triangleIndexes[i][2]]; Point[] p0 = { new Point((int)pp0.X, (int)pp0.Y) }; Point[] p1 = { new Point((int)pp1.X, (int)pp1.Y) }; Point[] p2 = { new Point((int)pp2.X, (int)pp2.Y) }; tri.Push(p0); tri.Push(p1); tri.Push(p2); if (rect.Contains(tri[0]) && rect.Contains(tri[1]) && rect.Contains(tri[2])) { CvInvoke.Line(img, tri[0], tri[1], delaunayColor, 2, Emgu.CV.CvEnum.LineType.AntiAlias, 0); CvInvoke.Line(img, tri[1], tri[2], delaunayColor, 2, Emgu.CV.CvEnum.LineType.AntiAlias, 0); CvInvoke.Line(img, tri[2], tri[0], delaunayColor, 2, Emgu.CV.CvEnum.LineType.AntiAlias, 0); } } }
//public MorphImage(Mat img1, Mat img2, VectorOfPointF points1, VectorOfPointF points2, float alpha) public MorphImage(ImageDetails imgdet1, ImageDetails imgdet2, VectorOfPointF points1, VectorOfPointF points2, float alpha) { this.img1 = imgdet1.ResizedImage.Mat; this.img2 = imgdet2.ResizedImage.Mat; this.alpha = alpha; img1.ConvertTo(img1, Emgu.CV.CvEnum.DepthType.Cv32F); img2.ConvertTo(img2, Emgu.CV.CvEnum.DepthType.Cv32F); this.points1 = points1; this.points2 = points2; if (points1.Size == 68) { AddCornerPoints(points1, img1); } if (points2.Size == 68) { AddCornerPoints(points2, img2); } // Add Points for whole image //points1 = AddCornerPoints(points1, img1); // todo: corner points get added twice //points2 = AddCornerPoints(points2, img2); // Create an instance of Subdiv2D Rectangle rect = new Rectangle(0, 0, img1.Size.Width, img1.Size.Height); Subdiv2D subdiv = new Subdiv2D(rect); // Create and Draw the Delaunay triangulation triangleIndexes = new VectorOfVectorOfInt(); CreateDelaunay(ref img1, ref subdiv, ref points1, false, ref triangleIndexes); //// Draw the Delaunay triangulation of face 1 //Mat img1D = img1.Clone(); //DrawDelaunay(ref img1D, ref subdiv, new MCvScalar(255, 255, 255)); //// Draw the Delaunay triangulation of face 2 //Mat img2D = img2.Clone(); //DrawDelaunay(ref img2D, ref points2, triangleIndexes, new MCvScalar(255, 255, 255)); //img2D.ConvertTo(img2D, Emgu.CV.CvEnum.DepthType.Cv8U); //compute weighted average point coordinates pointsM = new VectorOfPointF(); for (int i = 0; i < points1.Size; i++) { float x = (1 - alpha) * points1[i].X + alpha * points2[i].X; float y = (1 - alpha) * points1[i].Y + alpha * points2[i].Y; PointF[] pf = { new PointF(x, y) }; pointsM.Push(pf); } //empty image for morphed face int rowsM, colsM; if (img1.Cols >= img2.Cols) { colsM = img1.Cols; } else { colsM = img2.Cols; } if (img1.Rows >= img2.Rows) { rowsM = img1.Rows; } else { rowsM = img2.Rows; } imgM = Mat.Zeros(rowsM, colsM, Emgu.CV.CvEnum.DepthType.Cv32F, 3); for (int i = 0; i < triangleIndexes.Size; i++) { VectorOfPointF t1 = new VectorOfPointF(); VectorOfPointF t2 = new VectorOfPointF(); VectorOfPointF tM = new VectorOfPointF(); PointF ppft10 = points1[triangleIndexes[i][0]]; PointF ppft11 = points1[triangleIndexes[i][1]]; PointF ppft12 = points1[triangleIndexes[i][2]]; PointF ppft20 = points2[triangleIndexes[i][0]]; PointF ppft21 = points2[triangleIndexes[i][1]]; PointF ppft22 = points2[triangleIndexes[i][2]]; PointF ppftM0 = pointsM[triangleIndexes[i][0]]; PointF ppftM1 = pointsM[triangleIndexes[i][1]]; PointF ppftM2 = pointsM[triangleIndexes[i][2]]; PointF[] pft10 = { new PointF(ppft10.X, ppft10.Y) }; PointF[] pft11 = { new PointF(ppft11.X, ppft11.Y) }; PointF[] pft12 = { new PointF(ppft12.X, ppft12.Y) }; PointF[] pft20 = { new PointF(ppft20.X, ppft20.Y) }; PointF[] pft21 = { new PointF(ppft21.X, ppft21.Y) }; PointF[] pft22 = { new PointF(ppft22.X, ppft22.Y) }; PointF[] pftM0 = { new PointF(ppftM0.X, ppftM0.Y) }; PointF[] pftM1 = { new PointF(ppftM1.X, ppftM1.Y) }; PointF[] pftM2 = { new PointF(ppftM2.X, ppftM2.Y) }; t1.Push(pft10); t1.Push(pft11); t1.Push(pft12); t2.Push(pft20); t2.Push(pft21); t2.Push(pft22); tM.Push(pftM0); tM.Push(pftM1); tM.Push(pftM2); MorphTriangle(ref img1, ref img2, ref imgM, ref t1, ref t2, ref tM, alpha); } imgM.ConvertTo(imgM, Emgu.CV.CvEnum.DepthType.Cv8U); //CvInvoke.Imshow("Morphed Face", imgM); }
private void CreateDelaunay(ref Mat img, ref Subdiv2D subdiv, ref VectorOfPointF points, bool drawAnimated, ref VectorOfVectorOfInt triangleIndexes) { PointF[] pointsArr = points.ToArray(); foreach (PointF p in pointsArr) { subdiv.Insert(p); if (drawAnimated) { Mat imgCopy = img.Clone(); DrawDelaunay(ref imgCopy, ref subdiv, new MCvScalar(255, 255, 255)); CvInvoke.Imshow("Delaunay Triangulation", imgCopy); } } // Unfortunately we don't get the triangles by there original point indexes. // We only get them with their vertex coordinates. // So we have to map them again to get the triangles with their point indexes. Size size = img.Size; Rectangle rect = new Rectangle(0, 0, size.Width, size.Height); VectorOfInt ind = new VectorOfInt(); int[] indArr = new int[3]; Triangle2DF[] triangleList = subdiv.GetDelaunayTriangles(); for (int i = 0; i < triangleList.Length; i++) { Triangle2DF t = triangleList[i]; PointF ptzero = new PointF { X = t.V0.X, Y = t.V0.Y }; PointF[] PZero = new PointF[] { ptzero }; PointF ptone = new PointF { X = t.V1.X, Y = t.V1.Y }; PointF[] POne = new PointF[] { ptone }; PointF pttwo = new PointF { X = t.V2.X, Y = t.V2.Y }; PointF[] PTwo = new PointF[] { pttwo }; VectorOfPointF pt = new VectorOfPointF(); pt.Push(PZero); pt.Push(POne); pt.Push(PTwo); if (rect.Contains(new Point((int)pt[0].X, (int)pt[0].Y)) && rect.Contains(new Point((int)pt[1].X, (int)pt[1].Y)) && rect.Contains(new Point((int)pt[2].X, (int)pt[2].Y))) { for (int j = 0; j < 3; j++) { for (int k = 0; k < points.Size; k++) { if (Math.Abs(pt[j].X - points[k].X) < 1.0 && Math.Abs(pt[j].Y - points[k].Y) < 1) { indArr[j] = k; } } } } ind = new VectorOfInt(indArr); triangleIndexes.Push(ind); } }
public void TestVectorOfVector() { int[][] v0 = new int[][] { new int[] {1, 2, 3}, new int[] {4, 5}, new int[] {6} }; using (VectorOfVectorOfInt v = new VectorOfVectorOfInt(v0)) { int[][] v1 = v.ToArrayOfArray(); for (int i = 0; i < v0.Length; i++) { int[] a = v0[i]; int[] b = v1[i]; for (int j = 0; j < a.Length; j++) { EmguAssert.IsTrue(a[j] == b[j]); } } } }