public FaceViewModel(FaceLocation faceLocation, string imagePath)
        {
            _imagePath = imagePath;

            Title = imagePath;
            Application.Current.Dispatcher.Invoke(() =>
            {
                BitmapImage src = new BitmapImage();
                src.BeginInit();
                src.UriSource   = new Uri(imagePath, UriKind.Absolute);
                src.CacheOption = BitmapCacheOption.OnLoad;
                src.EndInit();

                DrawingVisual dv = new DrawingVisual();
                using (DrawingContext dc = dv.RenderOpen())
                {
                    dc.DrawImage(src, new Rect(0, 0, src.PixelWidth, src.PixelHeight));
                    dc.DrawRectangle(System.Windows.Media.Brushes.Green, null,
                                     new Rect(faceLocation.Left,
                                              faceLocation.Top, faceLocation.Right - faceLocation.Left,
                                              faceLocation.Bottom - faceLocation.Top));
                }

                RenderTargetBitmap rtb = new RenderTargetBitmap(src.PixelWidth, src.PixelHeight, 96, 96,
                                                                PixelFormats.Pbgra32);
                rtb.Render(dv);

                Image = rtb;
            });
        }
Example #2
0
        int GetRectanglesIntersectionSquare(FaceLocation a, FaceLocation b)
        {
            int xIntersection = GetSegmentsIntersectionLength(a.Left, a.Right, b.Left, b.Right);
            int yIntersection = GetSegmentsIntersectionLength(a.Top, a.Bottom, b.Top, b.Bottom);

            return(xIntersection * yIntersection);
        }
Example #3
0
        FaceLocation CalculateNormalFaceLocation(Rectangle faceRect, int origWidth, int origHeight, double scaleFactor, double faceClippingRatio)
        {
            FaceLocation faceLocation = new FaceLocation();
            double       halhOfWidth  = Math.Round((faceRect.Right - faceRect.Left) * scaleFactor * faceClippingRatio / 2);
            double       halfOfHeight = Math.Round((faceRect.Bottom - faceRect.Top) * scaleFactor * faceClippingRatio / 2);
            double       delta        = 0; if (halhOfWidth > halfOfHeight)

            {
                delta = halhOfWidth;
            }
            else
            {
                delta = halfOfHeight;
            }

            faceLocation.Angle = 0;
            faceLocation.Left  = (int)Math.Round(faceRect.Center.X * scaleFactor - delta); if (faceLocation.Left < 0)
            {
                faceLocation.Left = 0;
            }
            faceLocation.Right = (int)Math.Round(faceRect.Center.X * scaleFactor + delta); if (faceLocation.Right >= origWidth)
            {
                faceLocation.Right = origWidth - 1;
            }
            faceLocation.Top = (int)Math.Round(faceRect.Center.Y * scaleFactor - delta); if (faceLocation.Top < 0)
            {
                faceLocation.Top = 0;
            }
            faceLocation.Bottom = (int)Math.Round(faceRect.Center.Y * scaleFactor + delta); if (faceLocation.Bottom >= origHeight)
            {
                faceLocation.Bottom = origHeight - 1;
            }
            return(faceLocation);
        }
Example #4
0
        FaceLocation CalculateRotatedFaceLocation(double baseX, double baseY, Rectangle faceRect, double angle, int origWidth, int origHeight, double scaleFactor, double faceClippingRatio)
        {
            FaceLocation faceLocation      = new FaceLocation();
            double       resultX           = (faceRect.Center.X - baseX) * Math.Cos(angle * Math.PI / 180) - (faceRect.Center.Y - baseY) * Math.Sin(angle * Math.PI / 180) + baseX;
            double       resultY           = (faceRect.Center.X - baseX) * Math.Sin(angle * Math.PI / 180) + (faceRect.Center.Y - baseY) * Math.Cos(angle * Math.PI / 180) + baseY;
            double       distanceToCenterX = (baseX - resultX) * scaleFactor;
            double       distanceToCenterY = (baseY - resultY) * scaleFactor;
            double       halhOfWidth       = Math.Round((faceRect.Right - faceRect.Left) * scaleFactor * faceClippingRatio / 2);
            double       halfOfHeight      = Math.Round((faceRect.Bottom - faceRect.Top) * scaleFactor * faceClippingRatio / 2);
            double       delta             = 0; if (halhOfWidth > halfOfHeight)

            {
                delta = halhOfWidth;
            }
            else
            {
                delta = halfOfHeight;
            }

            faceLocation.Angle = angle;
            faceLocation.Left  = (int)Math.Round((double)origWidth / 2 - distanceToCenterX - delta); if (faceLocation.Left < 0)
            {
                faceLocation.Left = 0;
            }
            faceLocation.Right = (int)Math.Round((double)origWidth / 2 - distanceToCenterX + delta); if (faceLocation.Right >= origWidth)
            {
                faceLocation.Right = origWidth - 1;
            }
            faceLocation.Top = (int)Math.Round((double)origHeight / 2 - distanceToCenterY - delta); if (faceLocation.Top < 0)
            {
                faceLocation.Top = 0;
            }
            faceLocation.Bottom = (int)Math.Round((double)origHeight / 2 - distanceToCenterY + delta); if (faceLocation.Bottom >= origHeight)
            {
                faceLocation.Bottom = origHeight - 1;
            }
            return(faceLocation);
        }
Example #5
0
        List <FaceLocation> GetCorrelatedFaceList(List <FaceLocation> faceLocationList, int additionalFacesCounter)
        {
            if (faceLocationList == null || faceLocationList.Count == 0)
            {
                return(null);
            }

            if (additionalFacesCounter > 0) // дополнительные лица, найденные в процессе дополнительного вращения. Есть смысл коррелировать
            {
                if (faceLocationList.Count == 1)
                {
                    return(faceLocationList);                             // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! надо обязательно повернуть на нужный угол !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                }
                else
                {
                    List <List <FaceLocation> > preCorrelatedList = new List <List <FaceLocation> >();
                    List <FaceLocation>         correlatedList    = new List <FaceLocation>();

                    for (int i = 0; i < faceLocationList.Count; i++)
                    {
                        if (preCorrelatedList.Count == 0)
                        {
                            List <FaceLocation> list = new List <FaceLocation>();
                            list.Add(faceLocationList[i]);
                            preCorrelatedList.Add(list);
                        }
                        else
                        {
                            bool isCorrelated = false;
                            for (int listId = 0; listId < preCorrelatedList.Count; listId++)
                            {
                                int square = GetRectanglesIntersectionSquare(preCorrelatedList[listId][0], faceLocationList[i]);
                                if (square > 0) // пересекаются
                                {
                                    if (square > ((preCorrelatedList[listId][0].Right - preCorrelatedList[listId][0].Left) * (preCorrelatedList[listId][0].Bottom - preCorrelatedList[listId][0].Top)) * 0.4)
                                    {
                                        preCorrelatedList[listId].Add(faceLocationList[i]);
                                        isCorrelated = true;
                                        break;
                                    }
                                }
                            }
                            if (!isCorrelated)
                            {
                                List <FaceLocation> list = new List <FaceLocation>();
                                list.Add(faceLocationList[i]);
                                preCorrelatedList.Add(list);
                            }
                        }
                    }

                    if (preCorrelatedList.Count > 0)
                    {
                        for (int preList = 0; preList < preCorrelatedList.Count; preList++)
                        {
                            if (preCorrelatedList[preList] != null && preCorrelatedList[preList].Count > 0)
                            {
                                if (preCorrelatedList[preList].Count == 1)
                                {
                                    correlatedList.Add(preCorrelatedList[preList][0]);
                                }
                                else
                                {
                                    double angelValue = 0;
                                    int    left       = 0;
                                    int    right      = 0;
                                    int    top        = 0;
                                    int    bottom     = 0;

                                    for (int t = 0; t < preCorrelatedList[preList].Count; t++)
                                    {
                                        angelValue = angelValue + preCorrelatedList[preList][t].Angle;
                                        left       = left + preCorrelatedList[preList][t].Left;
                                        right      = right + preCorrelatedList[preList][t].Right;
                                        top        = top + preCorrelatedList[preList][t].Top;
                                        bottom     = bottom + preCorrelatedList[preList][t].Bottom;
                                    }
                                    FaceLocation avg = new FaceLocation()
                                    {
                                        Angle  = angelValue / preCorrelatedList[preList].Count,
                                        Left   = (int)((double)left / preCorrelatedList[preList].Count),
                                        Right  = (int)((double)right / preCorrelatedList[preList].Count),
                                        Top    = (int)((double)top / preCorrelatedList[preList].Count),
                                        Bottom = (int)((double)bottom / preCorrelatedList[preList].Count)
                                    };
                                    correlatedList.Add(avg);
                                }
                            }
                        }
                    }
                    return(correlatedList);
                }
            }
            else // нет смысла коррелировать лица - бесполезно. Все лица из фотографии без вращения
            {
                return(faceLocationList);
            }
        }
Example #6
0
        public SearchFaces(byte[] photoArray, int[] additionalRotateAngles = null, int photoJpegQuality = 95, double faceClippingRatio = 1.2)
        {
            if (photoArray != null)
            {
                try
                {
                    using (Stream input = new MemoryStream(photoArray))
                    {
                        photoArray = null;
                        using (var inputStream = new SKManagedStream(input))
                            using (var codec = SKCodec.Create(inputStream))
                                using (var original = SKBitmap.Decode(codec))
                                {
                                    // ЧИТАЕМ EXIF-ИНФОРМАЦИЮ
                                    input.Position = 0;
                                    try
                                    {
                                        using (ExifReader reader = new ExifReader(input))
                                        {
                                            reader.GetTagValue(ExifTags.DateTime, out photoDateTime);
                                            reader.GetTagValue(ExifTags.BodySerialNumber, out cameraSerialNumber);
                                        }
                                    }
                                    catch (Exception exc) { }

                                    // НОРМАЛИЗУЕМ ИЗОБРАЖЕНИE ПО ВРАЩЕНИЮ
                                    SKBitmap normalized  = AdjustOrientation(original, codec.EncodedOrigin);
                                    double   scaleFactor = 2;

                                    // ПОЛУЧАЕМ ДЕТЕКТИРУЕМОЕ НА ЛИЦА ИЗОБРАЖЕНИЕ
                                    using (var scanned = normalized.Resize(new SKImageInfo((int)Math.Round((double)normalized.Width / scaleFactor), (int)Math.Round((double)normalized.Height / scaleFactor)), SKFilterQuality.High))
                                    {
                                        if (scanned == null)
                                        {
                                            return;
                                        }

                                        int additionalFacesCounter = 0;

                                        List <FaceLocation> faceLocationList = new List <FaceLocation>();

                                        using (var fd = Dlib.GetFrontalFaceDetector())
                                        {
                                            DlibDotNet.Rectangle[] faces = null;
                                            using (var array2D = Dlib.LoadImageData <RgbPixel>(ImagePixelFormat.Rgba, scanned.Bytes, (uint)scanned.Height, (uint)scanned.Width, (uint)(scanned.Bytes.Length / scanned.Height)))
                                                faces = fd.Operator(array2D);

                                            if (faces != null && faces.Length > 0)
                                            {
                                                for (int f = 0; f < faces.Length; f++)
                                                {
                                                    #region обрезаем лицо до квадрата
                                                    Point center = faces[f].Center;
                                                    int   radius = 0;
                                                    if (faces[f].Width < faces[f].Height)
                                                    {
                                                        radius = (int)faces[f].Width / 2;
                                                    }
                                                    else
                                                    {
                                                        radius = (int)faces[f].Height / 2;
                                                    }
                                                    faces[f].Left   = center.X - radius;
                                                    faces[f].Right  = center.X + radius;
                                                    faces[f].Top    = center.Y - radius;
                                                    faces[f].Bottom = center.Y + radius;
                                                    #endregion обрезаем лицо до квадрата
                                                    FaceLocation faceLocation = CalculateNormalFaceLocation(faces[f], normalized.Width, normalized.Height, scaleFactor, faceClippingRatio);
                                                    faceLocationList.Add(faceLocation);
                                                }
                                            }

                                            if (additionalRotateAngles != null && additionalRotateAngles.Length > 0)
                                            {
                                                for (int r = 0; r < additionalRotateAngles.Length; r++)
                                                {
                                                    if (additionalRotateAngles[r] != 0)
                                                    {
                                                        DlibDotNet.Rectangle[] addFaces = null;
                                                        SKBitmap rotatedScanned         = Rotate(scanned, additionalRotateAngles[r]);
                                                        using (var array2D = Dlib.LoadImageData <RgbPixel>(ImagePixelFormat.Rgba, rotatedScanned.Bytes, (uint)rotatedScanned.Height, (uint)rotatedScanned.Width, (uint)(rotatedScanned.Bytes.Length / rotatedScanned.Height)))
                                                            addFaces = fd.Operator(array2D);

                                                        if (addFaces != null && addFaces.Length > 0)
                                                        {
                                                            for (int i = 0; i < addFaces.Length; i++)
                                                            {
                                                                #region обрезаем лицо до квадрата
                                                                Point center = addFaces[i].Center;
                                                                int   radius = 0;
                                                                if (addFaces[i].Width < addFaces[i].Height)
                                                                {
                                                                    radius = (int)addFaces[i].Width / 2;
                                                                }
                                                                else
                                                                {
                                                                    radius = (int)addFaces[i].Height / 2;
                                                                }
                                                                addFaces[i].Left   = center.X - radius;
                                                                addFaces[i].Right  = center.X + radius;
                                                                addFaces[i].Top    = center.Y - radius;
                                                                addFaces[i].Bottom = center.Y + radius;
                                                                #endregion обрезаем лицо до квадрата
                                                                FaceLocation faceLocation = CalculateRotatedFaceLocation((double)rotatedScanned.Width / 2, (double)rotatedScanned.Height / 2, addFaces[i], -additionalRotateAngles[r], normalized.Width, normalized.Height, scaleFactor, faceClippingRatio);
                                                                additionalFacesCounter++;
                                                                faceLocationList.Add(faceLocation);
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }

                                        if (faceLocationList.Count > 0)
                                        {
                                            List <FaceLocation> correlatedFaceList = GetCorrelatedFaceList(faceLocationList, additionalFacesCounter); // пропускаем через коррелятор лиц для избавления от дублей и уменьшения бокового наклона

                                            if (correlatedFaceList != null && correlatedFaceList.Count > 0)
                                            {
                                                for (int i = 0; i < correlatedFaceList.Count; i++)
                                                {
                                                    //var cropRect = new SKRectI { Left = correlatedFaceList[i].Left, Top = correlatedFaceList[i].Top, Right = correlatedFaceList[i].Right, Bottom = correlatedFaceList[i].Bottom };
                                                    var cropRect = new SKRectI();
                                                    int w        = correlatedFaceList[i].Right - correlatedFaceList[i].Left;
                                                    int h        = correlatedFaceList[i].Bottom - correlatedFaceList[i].Top;
                                                    int centerX  = correlatedFaceList[i].Left + w / 2;
                                                    int centerY  = correlatedFaceList[i].Top + h / 2;

                                                    if (w > h)
                                                    {
                                                        cropRect.Left   = centerX - h / 2;
                                                        cropRect.Right  = centerX + h / 2;
                                                        cropRect.Top    = centerY - h / 2;
                                                        cropRect.Bottom = centerY + h / 2;
                                                    }
                                                    else if (w < h)
                                                    {
                                                        cropRect.Left   = centerX - w / 2;
                                                        cropRect.Right  = centerX + w / 2;
                                                        cropRect.Top    = centerY - w / 2;
                                                        cropRect.Bottom = centerY + w / 2;
                                                    }
                                                    else
                                                    {
                                                        cropRect.Left   = correlatedFaceList[i].Left;
                                                        cropRect.Top    = correlatedFaceList[i].Top;
                                                        cropRect.Right  = correlatedFaceList[i].Right;
                                                        cropRect.Bottom = correlatedFaceList[i].Bottom;
                                                    }

                                                    var faceBitmap = new SKBitmap(cropRect.Width, cropRect.Height);
                                                    normalized.ExtractSubset(faceBitmap, cropRect);

                                                    //// ТЕПЕРЬ БУДЕМ ПОВОРАЧИВАТЬ
                                                    SKBitmap rotated = Rotate(faceBitmap, -correlatedFaceList[i].Angle);

                                                    // ТЕПЕРЬ НАКЛАДЫВАЕМ МАСКУ НА ЛИЦО В ВИДЕ КРУГА
                                                    double radius = 0;
                                                    if (cropRect.Width < cropRect.Height)
                                                    {
                                                        radius = (double)cropRect.Width / 2 * (1 + 0.5 / 2);
                                                    }
                                                    else
                                                    {
                                                        radius = (double)cropRect.Height / 2 * (1 + 0.5 / 2);
                                                    }

                                                    using (SKCanvas canvas = new SKCanvas(rotated))
                                                    {
                                                        canvas.DrawBitmap(rotated, 0, 0);
                                                        SKPaint paint = new SKPaint();
                                                        paint.Color       = maskColor;
                                                        paint.Style       = SKPaintStyle.Stroke;
                                                        paint.StrokeWidth = (float)(radius * 0.4);

                                                        canvas.DrawCircle((float)rotated.Width / 2, (float)rotated.Height / 2, (float)radius, paint);
                                                        canvas.Flush();
                                                    }

                                                    // ВЫРЕЗАЕМ ИТОГ
                                                    double x             = (double)rotated.Width / 2;
                                                    double y             = (double)rotated.Height / 2;
                                                    var    finalCropRect = new SKRectI {
                                                        Left = (int)(x - (double)faceBitmap.Width / 2), Top = (int)(y - (double)faceBitmap.Height / 2), Right = (int)(x + (double)faceBitmap.Width / 2), Bottom = (int)(y + (double)faceBitmap.Height / 2)
                                                    };
                                                    faceBitmap.Dispose();
                                                    using (SKBitmap face = new SKBitmap(finalCropRect.Width, finalCropRect.Height))
                                                    {
                                                        rotated.ExtractSubset(face, finalCropRect);
                                                        try
                                                        {
                                                            if (face.Width > 600 * scaleFactor)
                                                            {
                                                                using (var scaled = face.Resize(new SKImageInfo((int)Math.Round(400 * scaleFactor), (int)Math.Round(400 * scaleFactor)), SKFilterQuality.High))
                                                                {
                                                                    if (scaled != null)
                                                                    {
                                                                        using (var image = SKImage.FromBitmap(scaled))
                                                                            using (var data = image.Encode(SKEncodedImageFormat.Jpeg, 90))
                                                                            {
                                                                                if (facesByteArrays == null)
                                                                                {
                                                                                    facesByteArrays = new List <byte[]>();
                                                                                }
                                                                                facesByteArrays.Add(data.ToArray());
                                                                            }
                                                                    }
                                                                }
                                                            }
                                                            else
                                                            {
                                                                using (var image = SKImage.FromBitmap(face))
                                                                    using (var data = image.Encode(SKEncodedImageFormat.Jpeg, 90))
                                                                    {
                                                                        if (facesByteArrays == null)
                                                                        {
                                                                            facesByteArrays = new List <byte[]>();
                                                                        }
                                                                        facesByteArrays.Add(data.ToArray());
                                                                    }
                                                            }
                                                        }
                                                        catch (Exception exc) { };
                                                    }
                                                }
                                                normalized.Dispose();
                                                correlatedFaceList = null;
                                            }
                                            faceLocationList = null;
                                        }
                                    }
                                }
                        isSuccess = true;
                    }
                }
                catch (Exception exc)
                {
                    try
                    {
                        isSuccess = false;
                        if (exc.StackTrace != null && exc.StackTrace != "")
                        {
                            log.Debug(String.Format("SearchFaces. Exception: {0}", exc.StackTrace));
                        }
                        else if (exc.Message != null && exc.Message != "")
                        {
                            log.Debug(String.Format("SearchFaces. Exception: {0}", exc.Message));
                        }
                    }
                    catch (Exception ex) { }
                }
            }
            else
            {
                log.Debug("SearchFaces. Null request.");
            }
        }