Exemple #1
0
        public void Recognize(ref string path, bool needCrop)
        {
            FaceRectRelative = RectangleF.Empty;
            LeftEyeCenter    = RightEyeCenter = MouthCenter = Vector2.Zero;

            var executablePath = Path.GetDirectoryName(Application.ExecutablePath);
            var faceFileName   = Path.Combine(executablePath, "Haar cascades", "haarcascade_frontalface_default.xml");
            var eyeFileName    = Path.Combine(executablePath, "Haar cascades", "haarcascade_eye.xml");
            var mouthFileName  = Path.Combine(executablePath, "Haar cascades", "haarcascade_mcs_mouth.xml");

            var image         = new Image <Bgr, byte>(path);
            var faceRectangle = Rectangle.Empty;

            var mouthRectangle = Rectangle.Empty;

            var gray = image.Convert <Gray, Byte>(); //Convert it to Grayscale

            //normalizes brightness and increases contrast of the image
            gray._EqualizeHist();

            using (var face = new HaarCascade(faceFileName))
                using (var eye = new HaarCascade(eyeFileName))
                    using (var mouth = new HaarCascade(mouthFileName))
                    {
                        //Detect the faces  from the gray scale image and store the locations as rectangle
                        //The first dimensional is the channel
                        //The second dimension is the index of the rectangle in the specific channel
                        var facesDetected = gray.DetectHaarCascade(face, 1.1, 10, Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.FIND_BIGGEST_OBJECT, new Size(20, 20));
                        if (facesDetected.Length == 0 || facesDetected[0].Length == 0)
                        {
                            faceRectangle = new Rectangle(0, 0, image.Width, image.Height);
                        }
                        else
                        {
                            faceRectangle = facesDetected[0][0].rect;

                            if (needCrop) // если это создание проекта - то нужно обрезать фотку и оставить только голову
                            {
                                var newHeight    = (int)(faceRectangle.Height * 0.5);
                                var newWidth     = newHeight + faceRectangle.Height >= image.Height ? (int)(faceRectangle.Width * 0.2) : (int)(faceRectangle.Width * 0.3); // если по условию - значит лицо крупно, и по ширине незачем широко оставлять
                                var newImageRect = faceRectangle;
                                newImageRect.Inflate(newWidth, newHeight);
                                if (newImageRect.Width < image.Width || newImageRect.Height < image.Height) // если действительно лицо маленькое - делаем обрезание
                                {
                                    newImageRect.X = newImageRect.X < 0 ? 0 : newImageRect.X;
                                    newImageRect.Y = newImageRect.Y < 0 ? 0 : newImageRect.Y;
                                    if (newImageRect.Width + newImageRect.X > image.Width)
                                    {
                                        var delta = (int)Math.Ceiling(((newImageRect.Width + newImageRect.X) - image.Width) * 0.5f);
                                        if (newImageRect.X - delta < 0)
                                        {
                                            newImageRect.Width -= delta * 2;
                                        }
                                        else
                                        {
                                            newImageRect.Width -= delta;
                                            newImageRect.X     -= delta;
                                        }
                                    }
                                    if (newImageRect.Height + newImageRect.Y > image.Height)
                                    {
                                        var delta = (int)Math.Ceiling(((newImageRect.Height + newImageRect.Y) - image.Height) * 0.5f);
                                        if (newImageRect.Y - delta < 0)
                                        {
                                            newImageRect.Height -= delta * 2;
                                        }
                                        else
                                        {
                                            newImageRect.Height -= delta;
                                            newImageRect.Y      -= delta;
                                        }
                                    }

                                    using (var croppedImage = ImageEx.Crop(path, newImageRect))
                                    {
                                        path = UserConfig.AppDataDir;
                                        FolderEx.CreateDirectory(path);
                                        path = Path.Combine(path, "tempHaarImage.jpg");
                                        croppedImage.Save(path, ImageFormat.Jpeg);
                                    }
                                    Recognize(ref path, false);
                                    return;
                                }
                            }
                        }

                        #region  от

                        //Set the region of interest on the faces
                        gray.ROI = faceRectangle;
                        var mouthDetected = gray.DetectHaarCascade(mouth, 1.1, 10, Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_ROUGH_SEARCH, new Size(20, 20));
                        gray.ROI = Rectangle.Empty;

                        if (mouthDetected.Length > 0 && mouthDetected[0].Length > 0)
                        {
                            var sortedMouths   = mouthDetected[0].OrderByDescending(x => x.rect.Y).ToList();
                            var hasBetterMouth = false;
                            if (sortedMouths.Count > 1) // обрабатываем случай, когда два рта расположены близко, но нижний - неправильный.
                            {
                                var mouthRect1 = sortedMouths[0].rect;
                                var mouthRect2 = sortedMouths[1].rect;

                                if (Math.Abs(mouthRect1.Y - mouthRect2.Y) < 20)
                                {
                                    var rectS1 = mouthRect1.Width * mouthRect1.Height;
                                    var rectS2 = mouthRect2.Width * mouthRect2.Height;

                                    if (rectS2 > rectS1)
                                    {
                                        hasBetterMouth = true;
                                        mouthRectangle = mouthRect2;
                                        mouthRectangle.Offset(faceRectangle.X, faceRectangle.Y);

                                        var heightCoef = mouthRectangle.Height > 60 ? 0.28f : 0.4f;
                                        //   var heightCoef = 1;
                                        MouthCenter = new Vector2(mouthRectangle.X + mouthRectangle.Width * 0.5f, mouthRectangle.Y + mouthRectangle.Height * heightCoef);
                                    }
                                }
                            }

                            if (!hasBetterMouth)
                            {
                                mouthRectangle = sortedMouths[0].rect;
                                mouthRectangle.Offset(faceRectangle.X, faceRectangle.Y);

                                var heightCoef = mouthRectangle.Height > 60 ? 0.28f : 0.4f; // более пиздец точное распознавание -_-
                                //var heightCoef = 1;
                                MouthCenter = new Vector2(mouthRectangle.X + mouthRectangle.Width * 0.5f, mouthRectangle.Y + mouthRectangle.Height * heightCoef);
                            }

                            image.Draw(mouthRectangle, new Bgr(Color.Green), 2);
                        }

                        if (MouthCenter == Vector2.Zero) // если не определилось - втыкаем по дефолту
                        {
                            MouthCenter = new Vector2(faceRectangle.Width * 0.5f, faceRectangle.Height / 1.5f);
                        }

                        #endregion

                        #region Глазки

                        //Set the region of interest on the faces
                        gray.ROI = faceRectangle;
                        var eyesDetected = gray.DetectHaarCascade(eye, 1.1, 10, Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_CANNY_PRUNING, new Size(20, 20));
                        gray.ROI = Rectangle.Empty;

                        if (eyesDetected.Length > 0 && eyesDetected[0].Length > 0)
                        {
                            if (eyesDetected[0].Length == 1) // определился один глаз
                            {
                                var eyeRect = eyesDetected[0][0].rect;
                                eyeRect.Offset(faceRectangle.X, faceRectangle.Y);
                                var center = new Vector2(eyeRect.X + eyeRect.Width * 0.5f, eyeRect.Y + eyeRect.Height * 0.5f);

                                if (center.X < MouthCenter.X)   // определяем глаз по положению рта
                                {
                                    LeftEyeCenter = center;
                                }
                                else
                                {
                                    RightEyeCenter = center;
                                }
                            }
                            else    // определилось несколько глаз. выбираем нужные. развлекаемся
                            {
                                var sortedEyes = eyesDetected[0].OrderBy(x => x.rect.X).ToList();
                                var j1         = 0;
                                for (var j = 0; j < sortedEyes.Count - 1; j++)
                                {
                                    var rf = sortedEyes[j].rect;
                                    rf.Offset(faceRectangle.X, faceRectangle.Y);
                                    var center = new Vector2(rf.X + rf.Width * 0.5f, rf.Y + rf.Height * 0.5f);
                                    if (Math.Abs(center.Y - MouthCenter.Y) > 20)
                                    {
                                        LeftEyeCenter = center;
                                        j1            = j;
                                        break;
                                    }
                                }

                                for (var i = sortedEyes.Count - 1; i > j1; i--)
                                {
                                    var rf = sortedEyes[i].rect;
                                    rf.Offset(faceRectangle.X, faceRectangle.Y);
                                    var center = new Vector2(rf.X + rf.Width * 0.5f, rf.Y + rf.Height * 0.5f);

                                    if (Math.Abs(center.Y - LeftEyeCenter.Y) < 65 && Math.Abs(center.X - LeftEyeCenter.X) > 20) // абсолютно от балды числа .что бы уж сильно явные выпады убрать
                                    {
                                        RightEyeCenter = center;
                                        break;
                                    }
                                }
                            }
                        }

                        #region Глазки не определились. Через три пизды колено определяем

                        if (LeftEyeCenter == Vector2.Zero)
                        {
                            if (RightEyeCenter != Vector2.Zero) // определяем через правый глаз и рот
                            {
                                var delta = Math.Abs(RightEyeCenter.X - MouthCenter.X);
                                LeftEyeCenter = new Vector2(MouthCenter.X - delta, RightEyeCenter.Y);
                            }
                            else        // примерно определяем через прямоугольник лица
                            {
                                LeftEyeCenter = new Vector2(faceRectangle.X + faceRectangle.Width / 3.5f, faceRectangle.Y + faceRectangle.Height / 3f);
                            }
                        }

                        if (RightEyeCenter == Vector2.Zero)
                        {
                            if (LeftEyeCenter != Vector2.Zero) // определяем через левый глаз и рот
                            {
                                var delta = MouthCenter.X - LeftEyeCenter.X;
                                RightEyeCenter = new Vector2(MouthCenter.X + delta, LeftEyeCenter.Y);
                            }
                            else        // примерно определяем через прямоугольник лица
                            {
                                RightEyeCenter = new Vector2(faceRectangle.X + faceRectangle.Width / 3.5f, faceRectangle.Y + faceRectangle.Height / 3f);
                            }
                        }

                        #endregion

                        #region Поворот фотки по глазам!

                        var v = new Vector2(LeftEyeCenter.X - RightEyeCenter.X, LeftEyeCenter.Y - RightEyeCenter.Y);
                        v.Normalize(); // ПД !
                        var xVector = new Vector2(1, 0);

                        float xDiff = xVector.X - v.X;
                        float yDiff = xVector.Y - v.Y;
                        var   angle = Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI;

                        if (Math.Abs(angle) > 1 && angleCount <= 5)        // поворачиваем наклоненные головы
                        {
                            ++angleCount;

                            using (var ms = new MemoryStream(File.ReadAllBytes(path))) // Don't use using!!
                            {
                                var originalImg = (Bitmap)Bitmap.FromStream(ms);

                                path = UserConfig.AppDataDir;
                                FolderEx.CreateDirectory(path);
                                path = Path.Combine(path, "tempHaarImage.jpg");

                                using (var ii = ImageEx.RotateImage(new Bitmap(originalImg), (float)-angle))
                                    ii.Save(path, ImageFormat.Jpeg);
                            }

                            Recognize(ref path, false);
                            return;
                        }

                        #endregion

                        #endregion
                    }

            #region Переводим в относительные координаты

            MouthCenter    = new Vector2(MouthCenter.X / (image.Width * 1f), MouthCenter.Y / (image.Height * 1f));
            LeftEyeCenter  = new Vector2(LeftEyeCenter.X / (image.Width * 1f), LeftEyeCenter.Y / (image.Height * 1f));
            RightEyeCenter = new Vector2(RightEyeCenter.X / (image.Width * 1f), RightEyeCenter.Y / (image.Height * 1f));

            var leftTop     = new Vector2(LeftEyeCenter.X, Math.Max(LeftEyeCenter.Y, RightEyeCenter.Y));
            var rightBottom = new Vector2(RightEyeCenter.X, MouthCenter.Y);

            FaceRectRelative = new RectangleF(leftTop.X, leftTop.Y, rightBottom.X - leftTop.X, rightBottom.Y - leftTop.Y);

            #endregion
        }
Exemple #2
0
        private static void CropImage(Image sourceImage, string imageName, bool needCrop = true, int angleCount = 0)
        {
            FSDK.TPoint[] pointFeature;

            var image = new FSDK.CImage(new Bitmap(sourceImage));



            var faceRectangle = Rectangle.Empty;

            var facePosition = image.DetectFace();

            if (0 == facePosition.w)
            {
                SaveToFTP(sourceImage, imageName);
                return;
            }

            pointFeature = image.DetectFacialFeaturesInRegion(ref facePosition);

            var left = facePosition.xc - (int)(facePosition.w * 0.6f);

            left = left < 0 ? 0 : left;
            //   int top = facePosition.yc - (int)(facePosition.w * 0.5f);             // верхушку определяет неправильлно. поэтому просто не будем обрезать :)
            var BottomFace = new Vector2(pointFeature[11].x, pointFeature[11].y);

            var distance = pointFeature[2].y - pointFeature[11].y;
            var top      = pointFeature[16].y + distance - 15; // определение высоты по алгоритму старикана

            top = top < 0 ? 0 : top;

            var newWidth = (int)(facePosition.w * 1.2);

            newWidth = newWidth > image.Width || newWidth == 0 ? image.Width : newWidth;

            faceRectangle = new Rectangle(left, top, newWidth,
                                          BottomFace.Y + 15 < image.Height ? (int)(BottomFace.Y + 15) - top : image.Height - top - 1);

            if (needCrop)
            {
                sourceImage = ImageEx.Crop(new Bitmap(sourceImage), faceRectangle);
            }


            // по новой картинке еще раз распознаемм все
            image        = new FSDK.CImage(new Bitmap(sourceImage));
            facePosition = image.DetectFace();
            if (0 == facePosition.w)
            {
                SaveToFTP(sourceImage, imageName);
                return;
            }

            pointFeature = image.DetectFacialFeaturesInRegion(ref facePosition);


            var LeftEyeCenter  = new Vector2(pointFeature[0].x, pointFeature[0].y);
            var RightEyeCenter = new Vector2(pointFeature[1].x, pointFeature[1].y);

            #region Поворот фотки по глазам!



            var v = new Vector2(LeftEyeCenter.X - RightEyeCenter.X, LeftEyeCenter.Y - RightEyeCenter.Y);
            v.Normalize(); // ПД !
            var xVector = new Vector2(1, 0);

            var xDiff = xVector.X - v.X;
            var yDiff = xVector.Y - v.Y;
            var angle = Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI;

            if (Math.Abs(angle) > 1 && angleCount <= 5) // поворачиваем наклоненные головы
            {
                ++angleCount;
                sourceImage = ImageEx.RotateImage(new Bitmap(sourceImage), (float)-angle);
                CropImage(sourceImage, imageName, false, angleCount);
                return;
            }

            #endregion

            #region Корректируем размер фотки

            const int selectedSize = 1024;              // вызывается уже при создании проекта
            var       max          = (float)Math.Max(sourceImage.Width, sourceImage.Height);
            if (max != selectedSize)
            {
                var k = selectedSize / max;
                sourceImage = ImageEx.ResizeImage(sourceImage, new Size((int)Math.Round(sourceImage.Width * k), (int)Math.Round((sourceImage.Height * k))));
            }

            #endregion

            SaveToFTP(sourceImage, imageName);
        }
        public bool Recognize(ref string path, bool needCrop, bool needRotation = true)
        {
            FaceRectRelative = RectangleF.Empty;
            LeftEyeCenter    = RightEyeCenter = LeftMouth = LeftNose = RightNose = RightMouth = Vector2.Zero;

            var executablePath = Path.GetDirectoryName(Application.ExecutablePath);

            FSDK.TPoint[] pointFeature;
            var           image = new FSDK.CImage(path);

            var faceRectangle  = Rectangle.Empty;
            var mouthRectangle = Rectangle.Empty;

            FSDK.SetFaceDetectionThreshold(5);
            FSDK.SetFaceDetectionParameters(true, true, 512);
            var facePosition = image.DetectFace();

            if (0 == facePosition.w)
            {
                MessageBox.Show("No faces detected", "Face Detection");
                return(false);
            }

            if (needCrop)
            {
                RotatedAngle = facePosition.angle;      // угол, на который повернута голова.
            }
            pointFeature = image.DetectFacialFeaturesInRegion(ref facePosition);

            String AttributeValues;         // определение пола

            FSDK.DetectFacialAttributeUsingFeatures(image.ImageHandle, ref pointFeature, "Gender", out AttributeValues, 1024);
            var ConfidenceMale   = 0.0f;
            var ConfidenceFemale = 0.0f;
            var Age = 0.0f;             // в этой версии распознавалки не работает.

            FSDK.GetValueConfidence(AttributeValues, "Male", ref ConfidenceMale);
            FSDK.GetValueConfidence(AttributeValues, "Female", ref ConfidenceFemale);
            IsMale = ConfidenceMale > ConfidenceFemale;

            FSDK.DetectFacialAttributeUsingFeatures(image.ImageHandle, ref pointFeature, "Age", out AttributeValues, 1024);

            var left = facePosition.xc - (int)(facePosition.w * 0.6f);

            left = left < 0 ? 0 : left;
            //   int top = facePosition.yc - (int)(facePosition.w * 0.5f);             // верхушку определяет неправильлно. поэтому просто не будем обрезать :)
            BottomFace = new Vector2(pointFeature[11].x, pointFeature[11].y);

            var distance = pointFeature[2].y - pointFeature[11].y;
            var top      = pointFeature[16].y + distance - 15;     // определение высоты по алгоритму старикана

            top = top < 0 ? 0 : top;

            var newWidth = (int)(facePosition.w * 1.2);

            newWidth = newWidth > image.Width || newWidth == 0 ? image.Width : newWidth;

            faceRectangle = new Rectangle(left, top, newWidth, BottomFace.Y + 15 < image.Height ? (int)(BottomFace.Y + 15) - top : image.Height - top - 1);
            if (needCrop)       // если это создание проекта - то нужно обрезать фотку и оставить только голову
            {
                var bmpImage = new Bitmap(path);
                FaceColor = GetFaceColor(bmpImage, pointFeature);

                var croppedImage = ImageEx.Crop(bmpImage, faceRectangle);
                path = UserConfig.AppDataDir;
                FolderEx.CreateDirectory(path);
                path = Path.Combine(path, "tempHaarImage.jpg");
                croppedImage.Save(path, ImageFormat.Jpeg);
                croppedImage.Dispose();

                return(Recognize(ref path, false));
            }

            LeftEyeCenter  = new Vector2(pointFeature[0].x, pointFeature[0].y);
            RightEyeCenter = new Vector2(pointFeature[1].x, pointFeature[1].y);

            LeftMouth  = new Vector2(pointFeature[3].x, pointFeature[3].y);
            RightMouth = new Vector2(pointFeature[4].x, pointFeature[4].y);

            LeftNose  = new Vector2(pointFeature[45].x, pointFeature[45].y);
            RightNose = new Vector2(pointFeature[46].x, pointFeature[46].y);

            TopFace     = new Vector2(pointFeature[66].x, pointFeature[66].y);
            MiddleFace1 = new Vector2(pointFeature[66].x, pointFeature[66].y);
            MiddleFace2 = new Vector2(pointFeature[5].x, pointFeature[5].y);


            RightMiddleFace1 = new Vector2(pointFeature[67].x, pointFeature[67].y);
            RightMiddleFace2 = new Vector2(pointFeature[6].x, pointFeature[6].y);

            #region Поворот фотки по глазам!

            if (needRotation)
            {
                var v = new Vector2(LeftEyeCenter.X - RightEyeCenter.X, LeftEyeCenter.Y - RightEyeCenter.Y);
                v.Normalize();      // ПД !
                var xVector = new Vector2(1, 0);

                var xDiff = xVector.X - v.X;
                var yDiff = xVector.Y - v.Y;
                var angle = Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI;

                if (Math.Abs(angle) > 1 && angleCount <= 5)                // поворачиваем наклоненные головы
                {
                    ++angleCount;

                    using (var ms = new MemoryStream(File.ReadAllBytes(path))) // Don't use using!!
                    {
                        var originalImg = (Bitmap)Image.FromStream(ms);

                        path = UserConfig.AppDataDir;
                        FolderEx.CreateDirectory(path);
                        path = Path.Combine(path, "tempHaarImage.jpg");

                        using (var ii = ImageEx.RotateImage(new Bitmap(originalImg), (float)-angle))
                            ii.Save(path, ImageFormat.Jpeg);
                    }

                    return(Recognize(ref path, false));
                }
            }

            #endregion

            var upperUpperLip = pointFeature[54];       // вехняя точка верхней губы
            var lowerUpperLip = pointFeature[61];       // нижняя точка верхней губы
            var lowerLip      = pointFeature[64];       // верхняя точка нижней губы

            var diff2 = Math.Abs(lowerUpperLip.y - upperUpperLip.y);
            var diffX = Math.Abs(lowerLip.y - lowerUpperLip.y);

            IsOpenSmile = diffX > diff2;

            #region Переводим в относительные координаты

            LeftMouth  = new Vector2(LeftMouth.X / (image.Width * 1f), LeftMouth.Y / (image.Height * 1f));
            RightMouth = new Vector2(RightMouth.X / (image.Width * 1f), RightMouth.Y / (image.Height * 1f));

            LeftEyeCenter  = new Vector2(LeftEyeCenter.X / (image.Width * 1f), LeftEyeCenter.Y / (image.Height * 1f));
            RightEyeCenter = new Vector2(RightEyeCenter.X / (image.Width * 1f), RightEyeCenter.Y / (image.Height * 1f));

            LeftNose  = new Vector2(LeftNose.X / (image.Width * 1f), LeftNose.Y / (image.Height * 1f));
            RightNose = new Vector2(RightNose.X / (image.Width * 1f), RightNose.Y / (image.Height * 1f));

            TopFace     = new Vector2(TopFace.X / (image.Width * 1f), TopFace.Y / (image.Height * 1f));
            MiddleFace1 = new Vector2(MiddleFace1.X / (image.Width * 1f), MiddleFace1.Y / (image.Height * 1f));
            MiddleFace2 = new Vector2(MiddleFace2.X / (image.Width * 1f), MiddleFace2.Y / (image.Height * 1f));
            BottomFace  = new Vector2(BottomFace.X / (image.Width * 1f), BottomFace.Y / (image.Height * 1f));

            RightMiddleFace1 = new Vector2(RightMiddleFace1.X / (image.Width * 1f), RightMiddleFace1.Y / (image.Height * 1f));
            RightMiddleFace2 = new Vector2(RightMiddleFace2.X / (image.Width * 1f), RightMiddleFace2.Y / (image.Height * 1f));

            FacialFeatures = new List <Vector3>();
            RealPoints     = new List <Vector2>();
            int index       = 0;
            var pointDepths = GetPointDepths();
            foreach (var point in pointFeature)
            {
                FacialFeatures.Add(new Vector3(point.x / (image.Width * 1f), point.y / (image.Height * 1f), pointDepths[index++]));
                RealPoints.Add(new Vector2(point.x, point.y));
            }

            #endregion

            return(true);
        }