65.9K
CodeProject 正在变化。 阅读更多。
Home

Emgu CV 中基于眼部位置进行人脸对齐

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (3投票s)

2016年9月17日

CPOL

1分钟阅读

viewsIcon

17234

人脸对齐旋转以提高人脸识别率

引言

人脸识别是图像处理中的一项重要任务。但由于人脸姿势各异,例如向左或向右旋转,人脸识别的准确率会降低。因此,旋转人脸并使其正面朝向以获得更好的人脸识别效果至关重要。

背景

我搜索了大量网站以进行人脸识别和人脸旋转。我找到了一些代码和提示,但它们对我来说根本不起作用。因此,在实施了一些我的想法后,我编写了这段代码,根据眼部位置进行人脸对齐。它对我来说准确率超过 97%。

Using the Code

首先,使用haar级联检测器检测左右眼。

HaarCascade haar_righteye = new HaarCascade(path + "haarcascade_mcs_righteye.xml");
HaarCascade haar_lefteye = new HaarCascade(path + "haarcascade_mcs_lefteye.xml");      

//following variables are used to detect right eye and 
//left eye for fixing position and hence used for face alignment
MCvAvgComp[][] Right_Eye = upper_face.DetectHaarCascade(haar_righteye, 
1.4, 4, Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_CANNY_PRUNING, new Size(4, 4));
MCvAvgComp[][] Left_Eye = upper_face.DetectHaarCascade(haar_lefteye, 
1.4, 4, Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_CANNY_PRUNING, new Size(4, 4));

这里,upper_face 是人脸从鼻子中部开始的上半部分。简单来说,我将检测到的人脸图像取一个子矩形,高度设置为原始图像的一半。

int height = Face.Height / 2;
Rectangle rect = new Rectangle(0, 0, Face.Width, height);
Image<Gray, byte> upper_face = Face.GetSubRect(rect);

我将根据眼部位置(X 值)在图像中找到左眼和右眼。所述haar级联检测器并不总是直接给出左眼和右眼。因此,检查它们非常重要。

为了实际旋转人脸,我将根据眼部位置找到角度。然后,使用此角度与 180 度的计算,找到旋转人脸图像的最终角度。

var deltaY = (L_eye.rect.Y + L_eye.rect.Height / 2) - (R_eye.rect.Y + R_eye.rect.Height / 2);
             //using horizontal position and width attribute find out the variable deltaX
             var deltaX = (L_eye.rect.X + L_eye.rect.Width / 2) - (R_eye.rect.X + R_eye.rect.Width / 2);
             double degrees = (Math.Atan2(deltaY, deltaX) * 180) / Math.PI;//find out the angle 
                                                                           //as per position of eyes
             degrees = 180 - degrees;
             Face = Face.Rotate(degrees, new Gray(220),true);

请在下面找到完整的代码

public Image<Gray, byte> AlignFace(Image<Gray, byte> Face)
    {
        try
        {
            int height = Face.Height / 2;
            Rectangle rect = new Rectangle(0, 0, Face.Width, height);
            Image<Gray, byte> upper_face = Face.GetSubRect(rect);

            //following variables are used to detect right eye and 
            //left eye for fixing position and hence used for face alignment
            MCvAvgComp[][] Right_Eye = upper_face.DetectHaarCascade
            (haar_righteye, 1.4, 4, Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_CANNY_PRUNING, new Size(4, 4));
            MCvAvgComp[][] Left_Eye = upper_face.DetectHaarCascade
            (haar_lefteye, 1.4, 4, Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_CANNY_PRUNING, new Size(4, 4));

            bool FLAG = false;
            foreach (MCvAvgComp R_eye in Right_Eye[0])
            {                          
                foreach (MCvAvgComp L_eye in Left_Eye[0])
                {
                    if (R_eye.rect.X > (L_eye.rect.X+L_eye.rect.Width))
                    {
                        //upper_face.Draw(R_eye.rect, new Gray(200), 2);
                        //upper_face.Draw(L_eye.rect, new Gray(200), 2);
                        var deltaY = (L_eye.rect.Y + L_eye.rect.Height / 2) - 
                                     (R_eye.rect.Y + R_eye.rect.Height / 2);
                        //using horizontal position and width attribute find out the variable deltaX
                        var deltaX = (L_eye.rect.X + L_eye.rect.Width / 2) - 
                                     (R_eye.rect.X + R_eye.rect.Width / 2);
                        double degrees = (Math.Atan2(deltaY, deltaX) * 180) / Math.PI;//find out 
                                                                   //the angle as per position of eyes
                        degrees = 180 - degrees;
                        Face = Face.Rotate(degrees, new Gray(220),true);
                        FLAG = true;
                        break;
                    }                    
                }
                if(FLAG==true)
                {
                    break;
                }
            }          
        }
        catch (Exception d) {
            op += " Align Error: " + d.Message;
        }
        res = op;
        return Face;
    }

关注点

计算的度数的计算包含 180 度的角度,因此代码行...

degrees = 180 - degrees;

...是这段代码中一个有趣的方面。因为通过添加这一行代码,准确率得到了提高。

我为什么要添加这个呢?

请找出....

© . All rights reserved.