NEWS

[C#] Hướng dẫn Detect Face and Crop Image sử dụng EmguCV trong lập trình Winform

[C#] Hướng dẫn Detect Face and Crop Image sử dụng EmguCV trong lập trình Winform
Đăng bởi: Thảo Meo - Lượt xem: 17048 17:41:48, 13/09/2019C#   In bài viết

Xin chào các bạn, bài viết hôm nay mình sẽ hướng dẫn các bạn cách Detect Face and Crop Image sử dụng thư viện EmguCV và OpenCV trong lập trình Winform C#.

[C#] Detect face and crop image using Emgucv and opencv

Trong một số ứng dụng các bạn sẽ thấy ví dụ như: ứng dụng Facebook chẳng hạn, khi các bạn upload hình avatar lên thì hình ảnh các bạn sẽ được Facebook nhận dạng đâu là mặt người.

Và sau đó sẽ crop hình vào đúng chuẩn khung hình của ứng dụng.

Trong lúc đang làm việc ở công ty, mình có viết một ứng dụng dùng để quản trị nhân sự.

Khi chúng ta thêm mới một nhân viên vào, và có chọn hình ảnh thì chúng ta phải cắt hình và đưa hình ảnh về dạng chuẩn cho ứng dụng.

VD: như hình thẻ 3x4 hay là hình 4x6.

Vậy thì thay vì chúng ta phải import hình ảnh vào và viết tools crop and resize image.

Thì các bạn có thể tham khảo bài viết này, để ứng dụng tự động nhận dạng mặt người ở đâu, sau đó chúng ta sẽ tính trung tâm của hình ảnh và crop image về kích thước mà chúng ta mong đợi.

Trong bài viết này, mình sử dụng thư viện EmguCV để detect Image, và sau đó mình sẽ cắt hình.

Các bạn có thể tham khảo thêm về bài viết sử dụng và import thư viện EmguCV ở đây.

Giao diện demo ứng dụng Detect Face and Crop Image C#:

detect_face_and_crop_demo

Video demo ứng dụng của mình:

Full source code C# detect face and crop image:

using Emgu.CV;
using Emgu.CV.Structure;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DetectFaceAndCrop
{
    public partial class Form1 : Form
    {
        Image<Bgr, Byte> ImageFrame; 
        private CascadeClassifier _cascadeClassifier;
        Image InputImg;
        public Form1()
        {
            InitializeComponent();
        }

        private void btn_browser_Click(object sender, EventArgs e)
        {
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                InputImg = AutoResizeImage(openFileDialog.FileName);
                ImageFrame = new Image<Bgr, byte>(new Bitmap(InputImg));
                CamImageBox.Image = ImageFrame;
                DetectFaces();
            }
        }

        public Image AutoResizeImage(string url)
        {
            var InputImg = Image.FromFile(url);
            var ImageFrame = new Image<Bgr, byte>(new Bitmap(InputImg));
            Image<Gray, byte> grayframe = ImageFrame.Convert<Gray, byte>();
            var faces = _cascadeClassifier.DetectMultiScale(grayframe, 1.1, 10, Size.Empty);

            if (faces.Length > 0)
            {
                Bitmap BmpInput = grayframe.ToBitmap();
                Bitmap ExtractedFace;  
                Graphics FaceCanvas;
             
                foreach (var face in faces)
                {
                    ImageFrame.Draw(face, new Bgr(Color.Blue), 4);
                    ExtractedFace = new Bitmap(face.Width, face.Height);              
                    FaceCanvas = Graphics.FromImage(ExtractedFace);

                    FaceCanvas.DrawImage(BmpInput, 0, 0, face, GraphicsUnit.Pixel);
                    int w = face.Width;
                    int h = face.Height;
                    int x = face.X;
                    int y = face.Y;

                    int r = Math.Max(250, 250) / 2;
                    int centerx = x + w / 2;
                    int centery = y + h / 2;
                    int nx = (int)(centerx - r);
                    int ny = (int)(centery - r);
                    int nr = (int)(r * 5);


                    double zoomFactor = (double)197 / (double)face.Width;
                    Size newSize = new Size((int)(InputImg.Width * zoomFactor), (int)(InputImg.Height * zoomFactor));
                    Bitmap bmp = new Bitmap(InputImg, newSize);             
                    return (Image)bmp;
                }


            }
            return InputImg;
        }

        private void DetectFaces()
        {
            Image<Gray, byte> grayframe = ImageFrame.Convert<Gray, byte>();
            var faces = _cascadeClassifier.DetectMultiScale(grayframe, 1.1, 10, Size.Empty); 
            if (faces.Length > 0)
            {               
                Bitmap BmpInput = grayframe.ToBitmap();
                Bitmap ExtractedFace; 
                Graphics FaceCanvas;
               
                foreach (var face in faces)
                {
                    ImageFrame.Draw(face, new Bgr(Color.Blue), 4);                   
                    ExtractedFace = new Bitmap(face.Width, face.Height);                 
                    FaceCanvas = Graphics.FromImage(ExtractedFace);
                    FaceCanvas.DrawImage(BmpInput, 0, 0, face, GraphicsUnit.Pixel);
                    if (face.Width < 100) { return; }
                    int w = face.Width;
                    int h = face.Height;
                    int x = face.X;
                    int y = face.Y;

                    int r = Math.Max(250, 250) / 2;
                    int centerx = x + w / 2;
                    int centery = y + h / 2;
                    int nx = (int)(centerx - r);
                    int ny = (int)(centery - r);
                    int nr = (int)(r * 5);


                    double zoomFactor = (double)197 / (double)face.Width;
                    Size newSize = new Size((int)(InputImg.Width * zoomFactor), (int)(InputImg.Height * zoomFactor));
                    Bitmap bmp = new Bitmap(InputImg, newSize);
                    pic_result.Image = (Image)bmp;
                    var imgextract = CropImage(pic_result.Image, nx + 4, ny - 25, 248, 340);
                    pic_result.Image = imgextract;                    
                }

                CamImageBox.Image = ImageFrame;

            }
        }
        public static Bitmap CropImage(Image source, int x, int y, int width, int height)
        {
            Rectangle crop = new Rectangle(x, y, width, height);

            var bmp = new Bitmap(crop.Width, crop.Height);
            using (var gr = Graphics.FromImage(bmp))
            {
                gr.DrawImage(source, new Rectangle(0, 0, bmp.Width, bmp.Height), crop, GraphicsUnit.Pixel);
            }
            return bmp;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            _cascadeClassifier = new CascadeClassifier("haarcascade_frontalface_default.xml");
        }
    }
}

Bonus thêm đoạn code ResizeImageKeepAspectRatio dùng để thay đổi kích thước hình ảnh nhưng vẫn giữ tỷ lệ.

public Image ResizeImageKeepAspectRatio(Image source, int width, int height)
{
    Image result = null;

    try
    {
        if (source.Width != width || source.Height != height)
        {
            // Resize image
            float sourceRatio = (float)source.Width / source.Height;

            using (var target = new Bitmap(width, height))
            {
                using (var g = System.Drawing.Graphics.FromImage(target))
                {
                    g.CompositingQuality = CompositingQuality.HighQuality;
                    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    g.SmoothingMode = SmoothingMode.HighQuality;

                    // Scaling
                    float scaling;
                    float scalingY = (float)source.Height / height;
                    float scalingX = (float)source.Width / width;
                    if (scalingX < scalingY) scaling = scalingX; else scaling = scalingY;

                    int newWidth = (int)(source.Width / scaling);
                    int newHeight = (int)(source.Height / scaling);

                    // Correct float to int rounding
                    if (newWidth < width) newWidth = width;
                    if (newHeight < height) newHeight = height;

                    // See if image needs to be cropped
                    int shiftX = 0;
                    int shiftY = 0;

                    if (newWidth > width)
                    {
                        shiftX = (newWidth - width) / 2;
                    }

                    if (newHeight > height)
                    {
                        shiftY = (newHeight - height) / 2;
                    }

                    // Draw image
                    g.DrawImage(source, -shiftX, -shiftY, newWidth, newHeight);
                }

                result = (Image)target.Clone();
            }
        }
        else
        {
            // Image size matched the given size
            result = (Image)source.Clone();
        }
    }
    catch (Exception)
    {
        result = null;
    }

    return result;
}

public Bitmap Resize_Picture(Bitmap bmp, string Des, int FinalWidth, int FinalHeight, int ImageQuality)
{
    System.Drawing.Bitmap NewBMP;
    System.Drawing.Graphics graphicTemp;
   
    int iHeight;
    int iWidth;
    if ((FinalHeight == 0) && (FinalWidth != 0))
    {
        iWidth = FinalWidth;
        iHeight = (bmp.Size.Height * iWidth / bmp.Size.Width);
    }
    else if ((FinalHeight != 0) && (FinalWidth == 0))
    {
        iHeight = FinalHeight;
        iWidth = (bmp.Size.Width * iHeight / bmp.Size.Height);
    }
    else
    {
        iWidth = FinalWidth;
        iHeight = FinalHeight;
    }

    NewBMP = new System.Drawing.Bitmap(iWidth, iHeight);
    graphicTemp = System.Drawing.Graphics.FromImage(NewBMP);
    graphicTemp.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
    graphicTemp.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
    graphicTemp.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
    graphicTemp.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
    graphicTemp.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
    graphicTemp.DrawImage(bmp, 0, 0, iWidth, iHeight);
    graphicTemp.Dispose();
    System.Drawing.Imaging.EncoderParameters encoderParams = new System.Drawing.Imaging.EncoderParameters();
    System.Drawing.Imaging.EncoderParameter encoderParam = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, ImageQuality);
    encoderParams.Param[0] = encoderParam;
    System.Drawing.Imaging.ImageCodecInfo[] arrayICI = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders();
    for (int fwd = 0; fwd <= arrayICI.Length - 1; fwd++)
    {
        if (arrayICI[fwd].FormatDescription.Equals("JPEG"))
        {
            NewBMP.Save(Des, arrayICI[fwd], encoderParams);
        }
    }

    return NewBMP;
    NewBMP.Dispose();
    bmp.Dispose();
}

Hy vọng bài viết sẽ giúp ích được cho bạn nào đang viết về ứng dụng quản trị nhân sự.

Thanks for watching!

 

DOWNLOAD SOURCE

THÔNG TIN TÁC GIẢ

BÀI VIẾT LIÊN QUAN

[C#] Hướng dẫn Detect Face and Crop Image sử dụng EmguCV trong lập trình Winform
Đăng bởi: Thảo Meo - Lượt xem: 17048 17:41:48, 13/09/2019C#   In bài viết

CÁC BÀI CÙNG CHỦ ĐỀ

Đọc tiếp
.