SKProgramLab

Let's Enjoy Programming! ~画像処理/IoT/機械学習など~

C#/VB.NETで画像処理⑮<顔検出>

こんにちは、SKです。
f:id:SKProgramLab:20200310203357p:plain:w100

C#/VB.NETで画像処理シリーズの第15弾。
今回は、OpenCVSharpを使って顔検出を行う方法を紹介します。

画像の中に存在する「人の顔」を検出する手法であり、誰の顔かを判断する顔認識ではありません。
OpenCVには"Haar-cascade"と呼ばれる分類器によって顔検出を行う機能があります。

Harr-cascadeの仕組みを理解しなくても、簡単なプログラムで顔検出を実装できます。
やはり超絶便利なライブラリ。動かしてみると楽しい機能なので、皆さんも是非試してみてください。

例によって、カメラ画像に顔画像を映し、検出位置に矩形を描画するプログラムを作ります。

参考リンク

qiita.com

OpenCVSharpとは?

skprogramlab.hatenablog.com

(前回)背景差分

skprogramlab.hatenablog.com

動画手順

youtu.be

①特徴分類器ファイルを用意する

まず、OpenCVライブラリ本体を落とします(OpenCVSharpではなく本家のサイトから)。
github.com

2020/5/26現在の最新バージョンは4.3.0です。
opencv-4.3.0-vc14_vc15.exeをクリックし、ダウンロード。 f:id:SKProgramLab:20200526000618p:plain

任意の場所に解凍し、sources\data\haarcascadesフォルダの中から"haarcascade_frontalface_default.xml"を探し、自分のプロジェクトの実行フォルダ(\bin\Debug)にコピーします。
f:id:SKProgramLab:20200526001823p:plain

f:id:SKProgramLab:20200526001131p:plain

②顔検出データを生成する

CascadeClassifier型の変数を定義し、先ほどコピーしたxmlファイルを基に初期化します。

//顔検出データ
private CascadeClassifier faceCascade;

private void Process(Mat img)        
{
    //顔検出データ生成
    if (faceCascade == null)
    {
        faceCascade = new CascadeClassifier(Path.Combine(Application.StartupPath, "haarcascade_frontalface_default.xml"));
    }

}


③顔検出を行い矩形描画

カメラ画像をグレースケール化し、先ほど定義したfaceCascadeの"DetectMultiScale"関数の引数に指定します(その他のパラメータは未指定のデフォルト値でOK)。
顔を検出した座標情報がRect型の配列として返されるので、その数だけループを回し、赤色の矩形を描画します。

private void Process(Mat img)        
{
    //顔検出データ生成
    if (faceCascade == null)
    {
        faceCascade = new CascadeClassifier(Path.Combine(Application.StartupPath, "haarcascade_frontalface_default.xml"));
    }

    //グレースケール化
    using (Mat gray = img.CvtColor(ColorConversionCodes.BGR2GRAY))
    {
        //顔検出
        Rect[] rects = faceCascade.DetectMultiScale(gray);
        foreach(Rect r in rects)
        {
            //赤い四角を描画
            Cv2.Rectangle(img, r, Scalar.Red, 2);
        }
    }
}


実行します。
人の顔で画像検索した結果を映したモニタをWebカメラで撮っています。
画像内の人の顔をある程度検出できています。 f:id:SKProgramLab:20200526003600p:plain
精度はそこそこですが、極々簡単なプログラムで顔検出機能を実装することができました。


コード全文を載せておきます。
C#

using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
using OpenCvSharp;
using OpenCvSharp.Extensions;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Task.Run(() =>
            {
                using (VideoCapture v = new VideoCapture(0))
                using (Mat img = new Mat())
                {
                    while (true)
                    {
                        v.Read(img);
                        Process(img);
                        pictureBox1.Image = BitmapConverter.ToBitmap(img);
                    }
                }
            });
        }

        //顔検出データ
        private CascadeClassifier faceCascade;

        private void Process(Mat img)        
        {
            //顔検出データ生成
            if (faceCascade == null)
            {
                faceCascade = new CascadeClassifier(Path.Combine(Application.StartupPath, "haarcascade_frontalface_default.xml"));
            }

            //グレースケール化
            using (Mat gray = img.CvtColor(ColorConversionCodes.BGR2GRAY))
            {
                //顔検出
                Rect[] rects = faceCascade.DetectMultiScale(gray);
                foreach(Rect r in rects)
                {
                    //赤い四角を描画
                    Cv2.Rectangle(img, r, Scalar.Red, 2);
                }
            }
        }

    }
}


VB.NET

Imports System.IO
Imports OpenCvSharp
Imports OpenCvSharp.Extensions

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Task.Run(Sub()
                     Using v As New VideoCapture(0)
                         Using img As New Mat
                             Do
                                 v.Read(img)
                                 Process(img)
                                 PictureBox1.Image = img.ToBitmap
                             Loop
                         End Using
                     End Using
                 End Sub)
    End Sub

    '顔検出データ
    Private faceCascade As CascadeClassifier = Nothing

    Private Sub Process(ByVal img As Mat)

        '顔検出データ生成
        If faceCascade Is Nothing Then
            faceCascade = New CascadeClassifier(Path.Combine(Application.StartupPath, "haarcascade_frontalface_default.xml"))
        End If

        'グレースケール化
        Using gray As Mat = img.CvtColor(ColorConversionCodes.BGR2GRAY)
            '顔検出
            Dim rects As Rect() = faceCascade.DetectMultiScale(gray)
            For Each r As Rect In rects
                '赤い四角を描画
                Cv2.Rectangle(img, r, Scalar.Red, 2)
            Next
        End Using

    End Sub

End Class


C#/VB.NETで画像処理シリーズは、この辺で一区切りつけようと思います。

優れたGUI設計環境を持つC#/VB.NET言語、多種多様な画像処理を簡単に実現できるOpenCVライブラリ、そしてそれらを繋ぐラッパーライブラリOpenCVSharp、まだあまり広くは知られていないかもしれませんが、非常に美しい組み合わせだと私は思います。

これまでの記事を通して、画像処理プログラムは決して難しくない、楽しみながら学べる分野であるということが、少しでも伝われば幸いです。

次は、簡単なゲームプログラミングをやろうかと検討中。。