// // C++: void cv::Subdiv2D::getTriangleList(vector_Vec6f& triangleList) // /** * Returns a list of all triangles. * * param triangleList Output vector. * * The function gives each triangle as a 6 numbers vector, where each two are one of the triangle * vertices. i.e. p1_x = v[0], p1_y = v[1], p2_x = v[2], p2_y = v[3], p3_x = v[4], p3_y = v[5]. */ public void getTriangleList(MatOfFloat6 triangleList) { ThrowIfDisposed(); if (triangleList != null) { triangleList.ThrowIfDisposed(); } Mat triangleList_mat = triangleList; imgproc_Subdiv2D_getTriangleList_10(nativeObj, triangleList_mat.nativeObj); }
// // C++: void cv::Subdiv2D::getTriangleList(vector_Vec6f& triangleList) // //javadoc: Subdiv2D::getTriangleList(triangleList) public void getTriangleList(MatOfFloat6 triangleList) { ThrowIfDisposed(); if (triangleList != null) { triangleList.ThrowIfDisposed(); } #if ((UNITY_ANDROID || UNITY_IOS || UNITY_WEBGL) && !UNITY_EDITOR) || UNITY_5 || UNITY_5_3_OR_NEWER Mat triangleList_mat = triangleList; imgproc_Subdiv2D_getTriangleList_10(nativeObj, triangleList_mat.nativeObj); return; #else return; #endif }
// Update is called once per frame void Update() { if (webCamTextureToMatHelper.IsPlaying() && webCamTextureToMatHelper.DidUpdateThisFrame() && !imageOptimizationHelper.IsCurrentFrameSkipped()) { Mat rgbaMat = webCamTextureToMatHelper.GetMat(); //get downScaleMat; Mat downScaleRgbaMat = imageOptimizationHelper.GetDownScaleMat((rgbaMat)); //grayscale Imgproc.cvtColor(downScaleRgbaMat, gray1Mat, Imgproc.COLOR_RGBA2GRAY); //blur Imgproc.blur(gray1Mat, gray2Mat, new Size(5, 5)); //edge filter Imgproc.filter2D(gray2Mat, gray1Mat, gray1Mat.depth(), kernel); //blur Imgproc.blur(gray1Mat, gray2Mat, new Size(3, 3)); //detect edge Imgproc.threshold(gray2Mat, gray2Mat, EDGE_DETECT_VALUE, 255, Imgproc.THRESH_BINARY); //copy Mat to byteArray Utils.copyFromMat <byte> (gray2Mat, byteArray); //set edge pointList List <Point> pointList = new List <Point> (); int w = gray1Mat.width(); int h = gray1Mat.height(); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { if (byteArray [x + w * y] == 255) { pointList.Add(new Point(x, y)); } } } int limit = Mathf.RoundToInt((float)(pointList.Count * POINT_RATE)); if (limit > POINT_MAX_NUM) { limit = POINT_MAX_NUM; } while (pointList.Count > limit) { pointList.RemoveAt(Random.Range(0, pointList.Count)); } // Debug.Log ("pointList.Count " + pointList.Count); //init subdiv subdiv.initDelaunay(new OpenCVForUnity.CoreModule.Rect(0, 0, downScaleRgbaMat.width(), downScaleRgbaMat.height())); for (int i = 0; i < pointList.Count; i++) { subdiv.insert(pointList [i]); } subdiv.insert(new Point(0, 0)); subdiv.insert(new Point(gray1Mat.width() / 2 - 1, 0)); subdiv.insert(new Point(gray1Mat.width() - 1, 0)); subdiv.insert(new Point(gray1Mat.width() - 1, gray1Mat.height() / 2 - 1)); subdiv.insert(new Point(gray1Mat.width() - 1, gray1Mat.height() - 1)); subdiv.insert(new Point(gray1Mat.width() / 2 - 1, gray1Mat.height() - 1)); subdiv.insert(new Point(0, gray1Mat.height() - 1)); subdiv.insert(new Point(0, gray1Mat.height() / 2 - 1)); using (MatOfFloat6 triangleList = new MatOfFloat6()) { subdiv.getTriangleList(triangleList); float[] pointArray = triangleList.toArray(); float downScaleRatio = imageOptimizationHelper.downscaleRatio; if (downScaleRatio < 1) { downScaleRatio = 1; } byte[] color = new byte[4]; for (int i = 0; i < pointArray.Length / 6; i++) { Point p0 = new Point(pointArray [i * 6 + 0] * downScaleRatio, pointArray [i * 6 + 1] * downScaleRatio); Point p1 = new Point(pointArray [i * 6 + 2] * downScaleRatio, pointArray [i * 6 + 3] * downScaleRatio); Point p2 = new Point(pointArray [i * 6 + 4] * downScaleRatio, pointArray [i * 6 + 5] * downScaleRatio); if (p0.x < 0 || p0.x > rgbaMat.width()) { continue; } if (p0.y < 0 || p0.y > rgbaMat.height()) { continue; } if (p1.x < 0 || p1.x > rgbaMat.width()) { continue; } if (p1.y < 0 || p1.y > rgbaMat.height()) { continue; } if (p2.x < 0 || p2.x > rgbaMat.width()) { continue; } if (p2.y < 0 || p2.y > rgbaMat.height()) { continue; } //get center of gravity int cx = (int)((p0.x + p1.x + p2.x) * 0.33333); int cy = (int)((p0.y + p1.y + p2.y) * 0.33333); // Debug.Log ("cx " + cx + " cy " + cy ); //get center of gravity color rgbaMat.get(cy, cx, color); // Debug.Log ("r " + color[0] + " g " + color[1] + " b " + color[2] + " a " + color[3]); //fill Polygon Imgproc.fillConvexPoly(rgbaMat, new MatOfPoint(p0, p1, p2), new Scalar(color [0], color [1], color [2], color [3]), Imgproc.LINE_AA, 0); // Imgproc.line (rgbaMat, p0, p1, new Scalar (64, 255, 128, 255)); // Imgproc.line (rgbaMat, p1, p2, new Scalar (64, 255, 128, 255)); // Imgproc.line (rgbaMat, p2, p0, new Scalar (64, 255, 128, 255)); } } // Imgproc.putText (rgbaMat, "W:" + rgbaMat.width () + " H:" + rgbaMat.height () + " DOWNSCALE W:" + downScaleRgbaMat.width () + " H:" + downScaleRgbaMat.height (), new Point (5, rgbaMat.rows () - 10), Imgproc.FONT_HERSHEY_SIMPLEX, 1.0, new Scalar (255, 255, 255, 255), 2, Imgproc.LINE_AA, false); Utils.fastMatToTexture2D(rgbaMat, texture); } }
void TriangleDivide() { //init subdiv Subdiv2D subdiv = new Subdiv2D(); OpenCVForUnity.Rect cv_rect = new OpenCVForUnity.Rect(0, 0, rgbaMat.width(), rgbaMat.height()); subdiv.initDelaunay(cv_rect); for (int i = 0; i < pointList.Count; i++) { subdiv.insert(pointList[i]); } subdiv.insert(new Point(0, 0)); subdiv.insert(new Point(rgbaMat.width() / 4 - 1, 0)); // subdiv.insert(new Point(rgbaMat.width() / 2 - 1, 0)); // subdiv.insert(new Point(rgbaMat.width() / 2 - 1, rgbaMat.height() / 2 - 1)); // subdiv.insert(new Point(rgbaMat.width() / 2 - 1, rgbaMat.height() - 1)); // subdiv.insert(new Point(rgbaMat.width() / 4 - 1, rgbaMat.height() - 1)); // subdiv.insert(new Point(0, rgbaMat.height() - 1)); subdiv.insert(new Point(0, rgbaMat.height() / 2 - 1)); //using (MatOfFloat6 triangleList = new MatOfFloat6()) MatOfFloat6 triangleList = new MatOfFloat6(); { subdiv.getTriangleList(triangleList); float[] pointArray = triangleList.toArray(); //Debug.Log(pointArray.Length); //11000+ float downScaleRatio = 1; byte[] color = new byte[4]; for (int i = 0; i < pointArray.Length / 6; i++) { Point p0 = new Point(pointArray[i * 6 + 0] * downScaleRatio, pointArray[i * 6 + 1] * downScaleRatio); Point p1 = new Point(pointArray[i * 6 + 2] * downScaleRatio, pointArray[i * 6 + 3] * downScaleRatio); Point p2 = new Point(pointArray[i * 6 + 4] * downScaleRatio, pointArray[i * 6 + 5] * downScaleRatio); if (p0.x < 0 || p0.x > rgbaMat.width()) { continue; } if (p0.y < 0 || p0.y > rgbaMat.height()) { continue; } if (p1.x < 0 || p1.x > rgbaMat.width()) { continue; } if (p1.y < 0 || p1.y > rgbaMat.height()) { continue; } if (p2.x < 0 || p2.x > rgbaMat.width()) { continue; } if (p2.y < 0 || p2.y > rgbaMat.height()) { continue; } //get center of gravity int cx = (int)((p0.x + p1.x + p2.x) * 0.33333); int cy = (int)((p0.y + p1.y + p2.y) * 0.33333); //Debug.Log ("cx " + cx + " cy " + cy ); //get center of gravity color rgbaMat.get(cy, cx, color); //Debug.Log ("r " + color[0] + " g " + color[1] + " b " + color[2] + " a " + color[3]); //fill Polygon //Imgproc.fillConvexPoly(rgbaMat, new MatOfPoint(p0, p1, p2), new Scalar(color[0], color[1], color[2], color[3]), Imgproc.LINE_AA, 0); Imgproc.line(rgbaMat, p0, p1, new Scalar(64, 255, 128, 255)); Imgproc.line(rgbaMat, p1, p2, new Scalar(64, 255, 128, 255)); Imgproc.line(rgbaMat, p2, p0, new Scalar(64, 255, 128, 255)); //--------------------------------------------------------------------// //Debug.Log(pointArray.Length / 6); //154 //(68dlib点+周围8点 => 154个三角形) //Point[] pt = new Point[3]; //pt[0] = new Point(t[0], t[1]); //pt[1] = new Point(t[2], t[3]); //pt[2] = new Point(t[4], t[5]); //Debug.Log("[0]" + pt[0] + "[1]" + pt[1] + "[2]" + pt[2]); Point[] pt = new Point[3] { p0, p1, p2 }; //Debug.Log("[0]" + p0 + "[1]" + p1 + "[2]" + p2); //Debug.Log(cv_rect); //800*400,rgba图的尺寸 if (cv_rect.contains(p0) && cv_rect.contains(p1) && cv_rect.contains(p2)) { int count = 0; int[] index = new int[3]; for (int j = 0; j < 3; j++) { for (int k = 0; k < pointList.Count; k++) { if (Mathf.Abs((float)pt[j].x - (float)pointList[k].x) < 1.0 && Mathf.Abs((float)pt[j].y - (float)pointList[k].y) < 1.0) //重合 { index[j] = k; count++; } } } if (count == 3) { //154中筛选109个,满足3个点重合 //delaunayTri.push_back(index); } } //--------------------------------------------------------------------// } //subdiv.getVoronoiFacetList(); } }
// Update is called once per frame void Update() { if (webCamTextureToMatHelper.IsPlaying () && webCamTextureToMatHelper.DidUpdateThisFrame ()) { Mat rgbaMat = webCamTextureToMatHelper.GetMat (); //get downScaleMat; Mat downScaleRgbaMat = webCamTextureToMatHelper.GetDownScaleMat (rgbaMat); //grayscale Imgproc.cvtColor (downScaleRgbaMat, gray1Mat, Imgproc.COLOR_RGBA2GRAY); //blur Imgproc.blur (gray1Mat, gray2Mat, new Size (5, 5)); //edge filter Imgproc.filter2D (gray2Mat, gray1Mat, gray1Mat.depth (), kernel); //blur Imgproc.blur (gray1Mat, gray2Mat, new Size (3, 3)); //detect edge Imgproc.threshold (gray2Mat, gray2Mat, EDGE_DETECT_VALUE, 255, Imgproc.THRESH_BINARY); //copy Mat to byteArray Utils.copyFromMat<byte> (gray2Mat, byteArray); //set edge pointList List<Point> pointList = new List<Point> (); int w = gray1Mat.width (); int h = gray1Mat.height (); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { if (byteArray [x + w * y] == 255) pointList.Add (new Point (x, y)); } } int limit = Mathf.RoundToInt ((float)(pointList.Count * POINT_RATE)); if (limit > POINT_MAX_NUM) limit = POINT_MAX_NUM; while (pointList.Count > limit) { pointList.RemoveAt (Random.Range (0, pointList.Count)); } // Debug.Log ("pointList.Count " + pointList.Count); //init subdiv subdiv.initDelaunay (new OpenCVForUnity.Rect (0, 0, downScaleRgbaMat.width (), downScaleRgbaMat.height ())); for (int i = 0; i < pointList.Count; i++) { subdiv.insert (pointList [i]); } subdiv.insert (new Point (0, 0)); subdiv.insert (new Point (gray1Mat.width () / 2 - 1, 0)); subdiv.insert (new Point (gray1Mat.width () - 1, 0)); subdiv.insert (new Point (gray1Mat.width () - 1, gray1Mat.height () / 2 - 1)); subdiv.insert (new Point (gray1Mat.width () - 1, gray1Mat.height () - 1)); subdiv.insert (new Point (gray1Mat.width () / 2 - 1, gray1Mat.height () - 1)); subdiv.insert (new Point (0, gray1Mat.height () - 1)); subdiv.insert (new Point (0, gray1Mat.height () / 2 - 1)); using (MatOfFloat6 triangleList = new MatOfFloat6()) { subdiv.getTriangleList (triangleList); float[] pointArray = triangleList.toArray (); int downScaleRatio = webCamTextureToMatHelper.DOWNSCALE_RATIO; if (downScaleRatio < 1) downScaleRatio = 1; byte[] color = new byte[4]; for (int i = 0; i < pointArray.Length/6; i++) { Point p0 = new Point (pointArray [i * 6 + 0] * downScaleRatio, pointArray [i * 6 + 1] * downScaleRatio); Point p1 = new Point (pointArray [i * 6 + 2] * downScaleRatio, pointArray [i * 6 + 3] * downScaleRatio); Point p2 = new Point (pointArray [i * 6 + 4] * downScaleRatio, pointArray [i * 6 + 5] * downScaleRatio); if (p0.x < 0 || p0.x > rgbaMat.width ()) continue; if (p0.y < 0 || p0.y > rgbaMat.height ()) continue; if (p1.x < 0 || p1.x > rgbaMat.width ()) continue; if (p1.y < 0 || p1.y > rgbaMat.height ()) continue; if (p2.x < 0 || p2.x > rgbaMat.width ()) continue; if (p2.y < 0 || p2.y > rgbaMat.height ()) continue; //get center of gravity int cx = (int)((p0.x + p1.x + p2.x) * 0.33333); int cy = (int)((p0.y + p1.y + p2.y) * 0.33333); // Debug.Log ("cx " + cx + " cy " + cy ); //get center of gravity color rgbaMat.get (cy, cx, color); // Debug.Log ("r " + color[0] + " g " + color[1] + " b " + color[2] + " a " + color[3]); //fill Polygon Imgproc.fillConvexPoly (rgbaMat, new MatOfPoint (p0, p1, p2), new Scalar (color [0], color [1], color [2], color [3]), Imgproc.LINE_AA, 0); // Imgproc.line (rgbaMat, p0, p1, new Scalar (64, 255, 128, 255)); // Imgproc.line (rgbaMat, p1, p2, new Scalar (64, 255, 128, 255)); // Imgproc.line (rgbaMat, p2, p0, new Scalar (64, 255, 128, 255)); } } Imgproc.putText (rgbaMat, "W:" + rgbaMat.width () + " H:" + rgbaMat.height () + " DOWNSCALE W:" + downScaleRgbaMat.width () + " H:" + downScaleRgbaMat.height (), new Point (5, rgbaMat.rows () - 10), Core.FONT_HERSHEY_SIMPLEX, 1.0, new Scalar (255, 255, 255, 255), 2, Imgproc.LINE_AA, false); Utils.matToTexture2D (rgbaMat, texture, webCamTextureToMatHelper.GetBufferColors ()); } }
private void WarpFaces() { // Create the image matrices Mat imgSrc = CreateSourceImageMat(); Mat imgDest = CreateDestImageMat(imgSrc); // Generate the face data (in this case, load the parameters) //var sourceFace = JsonConvert.DeserializeObject<RootObject>(sourceImageFace); //var warpToFace = JsonConvert.DeserializeObject<RootObject>(this.warpToFace); // Create the landmark point lists var pointList1 = new List <Point>(); var pointList2 = new List <Point>(); AddMatchingLandmarks(sourceFace.faceLandmarks, warpToFace.faceLandmarks, pointList1, pointList2); if (pointList1.Count != pointList2.Count) { Debug.LogErrorFormat("Counts are not equal. Lists ahve {0} and {1} elements.", pointList1.Count, pointList2.Count); } // Declare the int source width/height int sw = (int)imgSrc.size().width; int sh = (int)imgSrc.size().height; int dw = warpToImage.width; int dh = warpToImage.height; // Create a subdivision for the source image var sourceSubDiv = new Subdiv2D(new OpenCVForUnity.Rect(0, 0, sw, sh)); // Add border points to the subdivision // and add all the other points Add8PointBorder(sourceSubDiv, sw, sh); foreach (var p in pointList1) { sourceSubDiv.insert(p); } // Create a list of triangles // from the subdivision MatOfFloat6 sourceTriMat = new MatOfFloat6(); sourceSubDiv.getTriangleList(sourceTriMat); var sourceTriList = new List <float>(sourceTriMat.toArray()); // OpenCV for Unity subdiv has a bug and we need to ensure // every triangle is inside the bounds of the source CapToMax(sourceTriList, sw - 1, sh - 1); // Copy it var destTriList = new List <float>(); foreach (float f in sourceTriList) { destTriList.Add(f); } // Find the points from the source, and // move them to the destination this way // the triangles correlate to each other MovePointsInList(sourceFace.faceLandmarks.FaceLandmarkList(), warpToFace.faceLandmarks.FaceLandmarkList(), destTriList); MovePointsInList(Get8PointBorder(sw, sh), Get8PointBorder(dw, dh), destTriList); // Now we have source triangles and positions // and destination triangles and positions // warp the source triangles ot the destination WarpImages(imgSrc, imgDest, sourceTriList, destTriList); // Everything is warped, so now create the texture from // the matrix Texture2D texture = MatToTexture2D(imgDest); // Assign the texture target.GetComponent <Renderer>().material.mainTexture = texture; }