#VisualStudio2019C#とOpenCvSharp4でWEBカメラ撮影して保存、顔認識
##環境
2020年9月
windows10
visualStduio 2019 C#
OpenCvSharp4
WEBカメラ
ロジクールのフルHD動画も撮影可能なウェブカム「HD Pro Webcam C910」
##概要
-
button1でカメラ撮影
bin\Debug\out
に出力。顔部分を赤枠で囲う。 -
button2で、フルパスで指定した画像を読み込んで、OpencvSharpの機能使って顔認識
顔でないところも顔と認識している。
オープンソースでここまで出来るのは凄いと思う。
##OpenCvSharp4のインストール
ツール>NuGetパッケージマネージャ>ソリューションのNuGetの管理
OpenCvSharp4
バージョン 4.4.0.20200725
「haarcascade_frontalface_default.xml」は以下より取得
https://github.com/opencv/opencv/blob/master/data/haarcascades/haarcascade_frontalface_default.xml
- ソースコード
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 Csharp_camera
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Util.Camera camera = new Util.Camera();
//カメラ撮影して保存
camera.cap();
}
private void button2_Click(object sender, EventArgs e)
{
Util.Camera camera = new Util.Camera();
//画像を読み込んで、顔に赤枠をつける
camera.Isface(textBox1.Text);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp; //OpenCvSharp4 4.4.0.20200725 (2020年7月25日 土曜日 (2020/07/25))
using System.Drawing;
using System.Windows.Forms;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.IO;
using System.Reflection;
namespace Csharp_camera.Util
{
class Camera
{
int WIDTH = 640;
int HEIGHT = 480;
OpenCvSharp.VideoCapture capture;
private Mat _matframe;
private Mat matframe { get { return _matframe; }set { _matframe = value; } }
public async void cap()
{
try
{
//ラムダ式は、デリゲート型に変換できます。
Func<Mat> function = () => capture_work();
//Task.Run(Action) メソッドの引数として使用すると、バックグラウンドで実行
matframe = await Task.Run(function);
//画像取得出来ていれば
if (matframe != null)
{
File.createDir(Directory.GetCurrentDirectory() + @"\out");
string path_img = Directory.GetCurrentDirectory() + @"\out\" + File.timestap() + ".png";
Func<bool> savefunc = () => save(path_img, matframe);
if (!(await Task.Run(savefunc)))
{
//Error
}
else
{
string path_img_face = Directory.GetCurrentDirectory() + @"\out\" + File.timestap() + "_face.png";
//顔認識
if (!await Task.Run(() => Isface( path_img, path_img_face)))
{
//Error
}
}
}
}
catch(Exception e)
{
Debug.WriteLine(e.ToString());
}
}
public async void Isface(string path_img)
{
string dir = Path.GetDirectoryName(path_img);
string filename = Path.GetFileNameWithoutExtension(path_img);
string path_img_face = dir + @"\" + filename + "_face.png";
//顔認識
if (!await Task.Run(() => Isface(path_img, path_img_face)))
{
//Error
}
}
private Mat capture_work()
{
//カメラ画像取得用のVideoCapture作成
capture = new VideoCapture(0);
//カメラが見つからない場合
if (!capture.IsOpened())
{
MessageBox.Show("camera was not found!");
}
capture.FrameWidth = WIDTH;
capture.FrameHeight = HEIGHT;
//取得先のMat作成
Mat matframe = new Mat(HEIGHT, WIDTH, MatType.CV_8UC3);
try
{
capture.Grab();
capture.Read(matframe);
}
catch(Exception e)
{
Debug.WriteLine(e.ToString());
return null;
}
return matframe;
}
private void bmp(ref Bitmap bmp)
{
//表示用のBitmap作成
bmp = new Bitmap(matframe.Cols, matframe.Rows, (int)matframe.Step(), System.Drawing.Imaging.PixelFormat.Format24bppRgb, matframe.Data);
}
private bool save(string path, Mat mat)
{
//エンコード
ImageEncodingParam encodingParam = new ImageEncodingParam(ImwriteFlags.PngBilevel, 0);
var buffer = new byte[mat.Rows * mat.Cols * mat.Channels()];
Cv2.ImEncode(".png", mat, out buffer, encodingParam);
// デコードして保存する
mat = Cv2.ImDecode(buffer, ImreadModes.Color);
// 画像の保存
Cv2.ImWrite(path, mat);
return true;
}
/// <summary>
/// 顔認識
/// </summary>
/// <returns></returns>
public bool Isface( string path_img, string path_img_face)
{
string path_xml = Directory.GetCurrentDirectory() + @"\xml\haarcascade_frontalface_default.xml";
//顔の矩形を抽出
using (Mat mat = new Mat(path_img))
{
// 分類機の用意
using (CascadeClassifier cascade = new CascadeClassifier(path_xml))
{
foreach (Rect rectFace in cascade.DetectMultiScale(mat))
{
// 見つかった場所に赤枠を表示
Rect rect = new Rect(rectFace.X, rectFace.Y, rectFace.Width, rectFace.Height);
Cv2.Rectangle(mat, rect, new OpenCvSharp.Scalar(0, 0, 255), 2);
}
}
//画像を保存
save(path_img_face, mat);
}
return true;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Reflection;
namespace Csharp_camera.Util
{
static class File
{
/// <summary>
/// タイムスタンプ
/// </summary>
/// <returns></returns>
public static string timestap()
{
DateTime dateTime = DateTime.Now;
string rlt = dateTime.ToString("yyyyMMdd_HHmmss");
return rlt;
}
/// <summary>
/// フォルダ作成
/// </summary>
/// <returns></returns>
public static bool createDir(string path)
{
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
return true;
}
}
}
##参考URL
https://www.it-swarm.dev/ja/c%23/c%EF%BC%83%E3%81%A7byte-%E3%81%8B%E3%82%89%E7%94%BB%E5%83%8F%E3%83%9C%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AB%E7%94%BB%E5%83%8F%E3%82%92%E9%85%8D%E7%BD%AE%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/942181192/
https://dobon.net/vb/dotnet/graphics/drawimage.html
https://qiita.com/miwazawa/items/50cf5b913b058f59daa6
https://shimat.github.io/opencvsharp_docs/html/5ae63540-c121-e3ff-d58f-39f5fc3ffdf7.htm
http://ni4muraano.hatenablog.com/entry/2017/11/20/190000
http://it-confiado.com/blog/%E3%83%89%E3%83%A9%E3%83%83%E3%82%B0%E3%82%A2%E3%83%B3%E3%83%89%E3%83%89%E3%83%AD%E3%83%83%E3%83%97%E3%81%A7%E3%83%91%E3%82%B9%E3%82%92%E6%B8%A1%E3%81%99/