Advertisement

使用opencv和dlib进行人脸三角刨分

阅读量:

使用opencv和dlib进行人脸三角刨分

  • 什么是Delaunay三角剖分?
  • 什么是Voronoi图?
  • python 代码
  • C++ 代码

什么是Delaunay三角剖分?

在这里插入图片描述

图:Delaunay三角剖分偏爱小角度

在一个平面上的一组离散点集合中进行三角剖分意味着将该平面划分为若干个互不重叠且覆盖整个平面的三角形区域,并且这些区域的所有顶点都必须是原始数据中的离散点集合中的某一点。

在这种情况下图2展示了四个关键节点A、B、C和D及其对应的德劳尼分割结果。

Delaunay triangulation exhibits a notable characteristic by avoiding the use of triangles with significant angular disparity.

图2描绘了当移动点时三角剖分如何演变以捕获"胖"三角形。位于顶端图像中的点B与D具有相同的x坐标值为1.5,在底端图像中,则它们的x坐标值被调整为1.75。顶端视角下形成的角ABC与ABD相对较大;相比之下,在顶端视角下形成的角ABC与ABD相对较大(注:此处可能有表述重复,请根据具体上下文进行调整)。然而,在底端视角下形成的角BCD过大,则采用边AC将其分割成更小的部分

多种算法可用于生成一组点集的Delaunay triangulation. 其中最为经典但并非最优的方法是:从任意一个初始分割出发,并依次验证每个triangle的circumcircle是否包含其他顶点. 如果满足条件,则交换edge(如图所示),直至所有生成的triangle都不再被其circumcircle所包含.

在这里插入图片描述

什么是Voronoi图?

给定平面中的一组点,在Voronoi图中将空间划分为若干区域,并使各区域边界的线条与相邻点等距分布。图3展示了基于黑色显示的点计算所得Voronoi图的具体实例。观察到的是,在每条边界线上都会穿过两个相邻点之间的中位线位置。如果将相邻Voronoi区域内的所有点进行连接,则能够构造出对应的Delaunay三角剖分!

Delaunay三角剖分和Voronoi图之间的联系多种多样,并非单一关系。
乔治·沃罗诺伊(Georgy Voronoy)是鲍里斯·德劳内(Boris Delaunay)的博士生导师。

给定一组点,您可以使用Subdiv2D类计算Delaunay三角剖分或Voronoi图。

在这里插入图片描述

人脸动态三角刨分

python 代码

复制代码
    #!/usr/bin/python
    
    import cv2
    
    import numpy as np
    import dlib
    import random
    
    # Check if a point is inside a rectangle
    
    def rect_contains(rect, point) :
    
    if point[0] < rect[0] :
    
        return False
    
    elif point[1] < rect[1] :
    
        return False
    
    elif point[0] > rect[2] :
    
        return False
    
    elif point[1] > rect[3] :
    
        return False
    
    return True
    
    # Draw a point
    
    def draw_point(img, p, color ) :
    
    cv2.circle( img, p, 2, color, -1, 1, 0 )
    
    # Draw delaunay triangles
    
    def draw_delaunay(img, subdiv, delaunay_color ) :
    
    triangleList = subdiv.getTriangleList();
    
    size = img.shape
    
    r = (0, 0, size[1], size[0])
    
    for t in triangleList :
    
        pt1 = (t[0], t[1])
    
        pt2 = (t[2], t[3])
    
        pt3 = (t[4], t[5])
    
        if rect_contains(r, pt1) and rect_contains(r, pt2) and rect_contains(r, pt3) :
    
            cv2.line(img, pt1, pt2, delaunay_color, 1,1, 0)
    
            cv2.line(img, pt2, pt3, delaunay_color, 1, 1, 0)
    
            cv2.line(img, pt3, pt1, delaunay_color, 1, 1, 0)
        cv2.imshow(win_delaunay,img)
        cv2.waitKey(100)
    
    # Draw voronoi diagram
    
    def draw_voronoi(img, subdiv) :
    
    ( facets, centers) = subdiv.getVoronoiFacetList([])
    
    for i in range(0,len(facets)) :
    
        ifacet_arr = []
    
        for f in facets[i] :
    
            ifacet_arr.append(f)
    
            ifacet = np.array(ifacet_arr, np.int)
    
            color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
    
            cv2.fillConvexPoly(img, ifacet, color,1, 0);
    
            ifacets = np.array([ifacet])
    
            cv2.polylines(img, ifacets, True, (0, 0, 0), 1, 1, 0)
    
            cv2.circle(img, (centers[i][0], centers[i][1]), 3, (0, 0, 0), -1, 1, 0)
    
    
    
    if __name__ == '__main__':
    
    # Define window names
    
    win_delaunay = "Delaunay Triangulation"
    
    win_voronoi = "Voronoi Diagram"
    
    # Turn on animation while drawing triangles
    
    animate = True
    
    # Define colors for drawing.
    
    delaunay_color = (255,255,255)
    
    points_color = (0, 0, 255)
    
    # Read in the image.
    
    img = cv2.imread("1.jpg");
    
    # Keep a copy around
    
    img_orig = img.copy();
    
    # Rectangle to be used with Subdiv2D
    
    size = img.shape
    
    rect = (0, 0, size[1], size[0])
    
    # Create an instance of Subdiv2D
    
    subdiv = cv2.Subdiv2D(rect);
    
    # Create an array of points.
    
    points = [];
    
    # Read in the points from a text file
    
    
    
    detector = dlib.get_frontal_face_detector()         # 使用特征提取器frontal_face_detector
    predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")    # dlib的68点模型
    
    
    dets = detector(img, 1)                                    # 特征提取器的实例化
    print("Number of faces detected: {}".format(len(dets)))
    for k, d in enumerate(dets):
        print("Detection {}: Left: {} Top: {} Right: {} Bottom: {}".format(
            k, d.left(), d.top(), d.right(), d.bottom()))
        # Get the landmarks/parts for the face in box d.
        shape = predictor(img, d)                                 # 利用预测器预测
        for i in range(68):
            points.append((int(shape.part(i).x), int(shape.part(i).y)))
    
    # Insert points into subdiv
    
    for p in points :
    
        subdiv.insert(p)
    
    # Show animation
    
    if animate :
    
        img_copy = img_orig.copy()
    
        # Draw delaunay triangles
    
        draw_delaunay( img_copy, subdiv, (255, 255, 255) );
    
        cv2.imshow(win_delaunay, img_copy)
    
        cv2.waitKey(100)
    
        # Draw delaunay triangles
    
        draw_delaunay( img, subdiv, (255, 255, 255) );
    
    # Draw points
    
    for p in points :
    
        draw_point(img, p, (0,0,255))
    
        # Allocate space for Voronoi Diagram
    
        img_voronoi = np.zeros(img.shape, dtype = img.dtype)
    
        # Draw Voronoi diagram
    
        draw_voronoi(img_voronoi,subdiv)
    
        # Show results
        cv2.imshow(win_voronoi,img_voronoi)
    
    cv2.waitKey(0)

C++ 代码

复制代码
    #include <opencv2/imgproc/imgproc.hpp>
    
    #include <opencv2/highgui/highgui.hpp>
    #include <dlib/opencv.h>  
    #include <dlib/image_processing/frontal_face_detector.h>  
    #include <dlib/image_processing/render_face_detections.h>  
    #include <dlib/image_processing.h>  
    #include <dlib/gui_widgets.h>  
    #include <iostream>
    
    #include <fstream>
    
    using namespace cv;
    using namespace dlib;
    using namespace std;
    
    #define RATIO 4  
    #define SKIP_FRAMES 2  
    // Draw a single point
    
    static void draw_point(Mat& img, Point2f fp, Scalar color)
    
    {
    
    	circle(img, fp, 2, color, CV_FILLED, CV_AA, 0);
    
    }
    
    // Draw delaunay triangles
    
    static void draw_delaunay(Mat& img, Subdiv2D& subdiv, Scalar delaunay_color)
    
    {
    
    	std::vector<Vec6f> triangleList;
    
    	subdiv.getTriangleList(triangleList);
    
    	std::vector<Point> pt(3);
    
    	Size size = img.size();
    
    	Rect rect(0, 0, size.width, size.height);
    
    	for (size_t i = 0; i < triangleList.size(); i++)
    
    	{
    
    		Vec6f t = triangleList[i];
    
    		pt[0] = Point(cvRound(t[0]), cvRound(t[1]));
    
    		pt[1] = Point(cvRound(t[2]), cvRound(t[3]));
    
    		pt[2] = Point(cvRound(t[4]), cvRound(t[5]));
    
    		// Draw rectangles completely inside the image.
    
    		if (rect.contains(pt[0]) && rect.contains(pt[1]) && rect.contains(pt[2]))
    
    		{
    
    			cv::line(img, pt[0], pt[1], delaunay_color, 1, CV_AA, 0);
    
    			cv::line(img, pt[1], pt[2], delaunay_color, 1, CV_AA, 0);
    
    			cv::line(img, pt[2], pt[0], delaunay_color, 1, CV_AA, 0);
    
    		}
    
    	}
    
    }
    
    //Draw voronoi diagram
    
    static void draw_voronoi(Mat& img, Subdiv2D& subdiv)
    
    {
    
    	std::vector<std::vector<Point2f> > facets;
    
    	std::vector<Point2f> centers;
    
    	subdiv.getVoronoiFacetList(std::vector<int>(), facets, centers);
    
    	std::vector<Point> ifacet;
    
    	std::vector<std::vector<Point> > ifacets(1);
    
    	for (size_t i = 0; i < facets.size(); i++)
    
    	{
    
    		ifacet.resize(facets[i].size());
    
    		for (size_t j = 0; j < facets[i].size(); j++)
    
    			ifacet[j] = facets[i][j];
    
    		Scalar color;
    
    		color[0] = std::rand() & 255;
    
    		color[1] = std::rand() & 255;
    
    		color[2] = std::rand() & 255;
    
    		fillConvexPoly(img, ifacet, color, 8, 0);
    
    		ifacets[0] = ifacet;
    
    		polylines(img, ifacets, true, Scalar(), 1, CV_AA, 0);
    
    		circle(img, centers[i], 3, Scalar(), CV_FILLED, CV_AA, 0);
    
    	}
    
    }
    
    int main(int argc, char** argv)
    
    {
    
    	// Define window names
    
    	string win_delaunay = "Delaunay Triangulation";
    
    	string win_voronoi = "Voronoi Diagram";
    
    	// Turn on animation while drawing triangles
    
    	bool animate = true;
    
    	// Define colors for drawing.
    
    	Scalar delaunay_color(255, 255, 255), points_color(0, 0, 255);
    
    	// Read in the image.
    
    	Mat img = imread("2.jpg");
    
    	// Keep a copy around
    
    	Mat img_orig = img.clone();
    
    	// Rectangle to be used with Subdiv2D
    
    	Size size = img.size();
    
    	Rect rect(0, 0, size.width, size.height);
    
    	// Create an instance of Subdiv2D
    
    	Subdiv2D subdiv(rect);
    
    	// Create a vector of points.
    
    	std::vector<Point2f> points;
    
    	// Read in the points from a text file
    
    
    	int count = 0;
    	frontal_face_detector detector = get_frontal_face_detector();
    
    	shape_predictor pose_model;
    	deserialize("shape_predictor_68_face_landmarks.dat") >> pose_model;
    	std::vector<dlib::rectangle> faces;
    	Mat  img_small;
    	resize(img, img_small, Size(), 1.0 / RATIO, 1.0 / RATIO);
    	cv_image<bgr_pixel> cimg(img);
    	cv_image<bgr_pixel> cimg_small(img_small);
    	// Detect faces   
    	if (count++ % SKIP_FRAMES == 0) {
    		faces = detector(cimg_small);
    	}
    	// Find the pose of each face.  
    	std::vector<full_object_detection> shapes;
    	for (unsigned long i = 0; i < faces.size(); ++i) {
    		dlib::rectangle r(
    			(long)(faces[i].left() * RATIO),
    			(long)(faces[i].top() * RATIO),
    			(long)(faces[i].right() * RATIO),
    			(long)(faces[i].bottom() * RATIO)
    		);
    		// Landmark detection on full sized image
    		full_object_detection shape = pose_model(cimg, r);
    		shapes.push_back(shape);
    
    		for (i=0;i<68;i++)
    
    		{
    
    			points.push_back(Point2f(shape.part(i).x(), shape.part(i).y()));
    
    		}
    
    	}
    	// Insert points into subdiv
    
    	for (std::vector<Point2f>::iterator it = points.begin(); it != points.end(); it++)
    
    	{
    
    		subdiv.insert(*it);
    
    		// Show animation
    
    		if (animate)
    
    		{
    
    			Mat img_copy = img_orig.clone();
    
    			// Draw delaunay triangles
    
    			draw_delaunay(img_copy, subdiv, delaunay_color);
    
    			imshow(win_delaunay, img_copy);
    
    			waitKey(100);
    
    		}
    
    	}
    
    	// Draw delaunay triangles
    
    	draw_delaunay(img, subdiv, delaunay_color);
    
    	// Draw points
    
    	for (std::vector<Point2f>::iterator it = points.begin(); it != points.end(); it++)
    
    	{
    
    		draw_point(img, *it, points_color);
    
    	}
    
    	// Allocate space for Voronoi Diagram
    
    	Mat img_voronoi = Mat::zeros(img.rows, img.cols, CV_8UC3);
    
    	// Draw Voronoi diagram
    
    	draw_voronoi(img_voronoi, subdiv);
    
    	// Show results.
    
    	imshow(win_delaunay, img);
    
    	imshow(win_voronoi, img_voronoi);
    
    	waitKey(0);
    
    	return 0;
    
    }

全部评论 (0)

还没有任何评论哟~