I am making a face recognition and identification program using C# and EMGU. I got this error that I don't know why it occurs. The error occurs on (var result = recognizer.Predict(grayFacesResult);) This code should detect face, save images of detected faces and identify a person using the saved images. Please someone help me what I missed or what was the mistake here.
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;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.CV.Face;
using Emgu.CV.CvEnum;
using System.IO;
using System.Threading;
using System.Diagnostics;
namespace Version1
{
public partial class Form1 : Form
{
#region Variables
// for camera capture
private Capture videoCapture = null;
private Image<Bgr, Byte> currentFrame = null;
Mat frame = new Mat();
// for toggle camera capture
private bool facesDetectionEnabled = false;
// for saving face images
bool EnabledSaveImage = false;
Image<Bgr, Byte> faceResult = null;
List<Image<Gray, Byte>> TrainedFaces = new List<Image<Gray, byte>>();
List<int> PersonsLabels = new List<int>();
// ???
private static bool isTrained = false;
EigenFaceRecognizer recognizer;
List<string> PersonsNames = new List<string>();
// load cascade file
CascadeClassifier faceCascadeClassifier = new CascadeClassifier("haarcascade_frontalface_alt.xml");
#endregion
public Form1()
{
InitializeComponent();
}
private void btnCapture_Click(object sender, EventArgs e)
{
// start camera capture
videoCapture = new Capture();
videoCapture.ImageGrabbed += ProcessFrame;
videoCapture.Start();
}
private void ProcessFrame(object sender, EventArgs e)
{
// video capture
videoCapture.Retrieve(frame, 0);
currentFrame = frame.ToImage<Bgr, Byte>().Resize(picCapture.Width, picCapture.Height, Inter.Cubic);
// render captured frame into the picture box picCapture2
picCapture.Image = currentFrame.Bitmap;
// toggle start camera capture
if (facesDetectionEnabled)
{
Mat grayImage = new Mat();
CvInvoke.CvtColor(currentFrame, grayImage, ColorConversion.Bgr2Gray);
CvInvoke.EqualizeHist(grayImage, grayImage);
Rectangle[] faces = faceCascadeClassifier.DetectMultiScale(grayImage, 1.1, 3, Size.Empty, Size.Empty);
if (faces.Length > 0)
{
foreach (var face in faces) {
// draw square around each faces
CvInvoke.Rectangle(currentFrame, face, new Bgr(Color.Red).MCvScalar, 2);
// display face on picDetected
Image<Bgr, Byte> resultImage = currentFrame.Convert<Bgr, Byte>();
resultImage.ROI = face;
picDetected.SizeMode = PictureBoxSizeMode.StretchImage;
picDetected.Image = resultImage.Bitmap;
if (EnabledSaveImage)
{
string path = Directory.GetCurrentDirectory() + @"\TrainedImages";
// check and create the directory if not exists
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
// save 10 images
for (int i = 0; i < 10; i++)
{
resultImage.Resize(200, 200, Inter.Cubic).Save(path + @"\" + txtPersonName.Text + "_" + DateTime.Now.ToString("dd-mm-yyyy-hh-mm-ss") + ".jpg");
Thread.Sleep(1000);
}
// disable saving images
EnabledSaveImage = false;
if (btnAddPerson.InvokeRequired)
{
btnAddPerson.Invoke(new ThreadStart(delegate {
btnAddPerson.Enabled = true;
}));
}
// recognize face
Image<Gray, Byte> grayFacesResult = resultImage.Convert<Gray, Byte>().Resize(200, 200, Inter.Cubic);
var result = recognizer.Predict(grayFacesResult); // here is the error
if (result.Label > 0)
{
CvInvoke.PutText(currentFrame, PersonsNames[result.Label], new Point(face.X - 2, face.Y - 2), FontFace.HersheyComplex, 1.0, new Bgr(Color.Orange).MCvScalar);
CvInvoke.Rectangle(currentFrame, face, new Bgr(Color.Green).MCvScalar, 2);
}
else
{
CvInvoke.PutText(currentFrame, "Unknown", new Point(face.X - 2, face.Y - 2), FontFace.HersheyComplex, 1.0, new Bgr(Color.Orange).MCvScalar);
CvInvoke.Rectangle(currentFrame, face, new Bgr(Color.Green).MCvScalar, 2);
}
}
}
}
}
// render captured frame into the picture box picCapture2
picCapture2.Image = currentFrame.Bitmap;
}
private void btnDetect_Click(object sender, EventArgs e)
{
facesDetectionEnabled = true;
}
private void btnAddPerson_Click(object sender, EventArgs e)
{
btnSave.Enabled = false;
btnAddPerson.Enabled = true;
EnabledSaveImage = false;
}
private void btnSave_Click(object sender, EventArgs e)
{
btnSave.Enabled = true;
btnAddPerson.Enabled = false;
EnabledSaveImage = true;
}
private void btnTrain_Click(object sender, EventArgs e)
{
TrainImagesFromDir();
}
private bool TrainImagesFromDir()
{
int ImagesCount = 0;
int Threshold = -1;
TrainedFaces.Clear();
PersonsLabels.Clear();
PersonsNames.Clear();
try
{
string path = Directory.GetCurrentDirectory() + @"\TrainedImages";
string[] files = Directory.GetFiles(path, "*.jpg", SearchOption.AllDirectories);
foreach (var file in files)
{
Image<Gray, Byte> trainedImage = new Image<Gray, byte>(file);
TrainedFaces.Add(trainedImage);
PersonsLabels.Add(ImagesCount);
string name = file.Split('\\').Last().Split('_')[0];
PersonsNames.Add(name);
ImagesCount++;
Debug.WriteLine(ImagesCount + ". " + name);
}
recognizer = new EigenFaceRecognizer(ImagesCount, Threshold);
recognizer.Train(TrainedFaces.ToArray(), PersonsLabels.ToArray());
isTrained = true;
Debug.WriteLine(ImagesCount);
Debug.WriteLine(isTrained);
return isTrained;
}
catch (Exception ex)
{
isTrained = false;
MessageBox.Show("Error in Train Images: " + ex.Message);
return isTrained;
}
}
}
}
I'm guessing that ProcessFrame is called before the recognizer variable is created, which would give you the null reference. Have you tried stepping through your code with breakpoints to see what happens? This would show you exactly which variable is null :)
You could add something like this to validate your variables before running the code, it's always a good idea to ensure everything exists before trying to use it:
private void ProcessFrame(object sender, EventArgs e)
{
if(recognizer == null)
// Throw an error, log something, return, or
// just create the recognizer and continue