我一直在使用EmguCV(C#)开发人脸识别应用程序。如果我将面部图像(训练集)存储在简单的Windows文件夹中,我就可以完成所有工作。但是,在我尝试迁移面部图像以存储在Microsoft Access数据库中之后,当应用程序尝试时,经常会出现“对象引用未设置为对象的实例”异常消息(并非总是如此,但大多数情况下)从视频Feed中识别脸部。
有趣的是,如果没有发生异常,识别实际上仍然可行。
这是我程序代码的片段,使用windows文件夹和数据库:
从Windows文件夹中读取存储的图像
private void FaceRecognition_Load(object sender, EventArgs e)
{
//if capture is not created, create it now
if (capture == null)
{
try
{
capture = new Capture();
}
catch (NullReferenceException excpt)
{
MessageBox.Show(excpt.Message);
}
}
if (capture != null)
{
if (captureInProgress)
{
Application.Idle -= ProcessFrame;
}
else
{
Application.Idle += ProcessFrame;
}
captureInProgress = !captureInProgress;
}
#endregion
{
// adjust path to find your xml at loading
haar = new HaarCascade("haarcascade_frontalface_default.xml");
try
{
//Load of previus trainned faces and labels for each image
string Labelsinfo = File.ReadAllText(Application.StartupPath + "\\TrainedFaces\\TrainedLabels.txt");
string[] Labels = Labelsinfo.Split('%');
NumLabels = Convert.ToInt16(Labels[0]);
ContTrain = NumLabels;
string LoadFaces;
for (int tf = 1; tf < NumLabels + 1; tf++)
{
LoadFaces = "face" + tf + ".bmp";
trainingImages.Add(new Image<Gray, byte>(Application.StartupPath + "\\TrainedFaces\\" + LoadFaces));
labels.Add(Labels[tf]);
}
}
catch (Exception error)
{
//MessageBox.Show(e.ToString());
MessageBox.Show("Nothing in binary database, please add at least a face(Simply train the prototype with the Add Face Button).", "Triained faces load", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
}
从Microsoft Access数据库中读取存储的图像
private void connectToDatabase()
{
DBConnection.ConnectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=FacesDatabase.mdb";
DBConnection.Open();
dataAdapter = new OleDbDataAdapter("Select * from TrainingSet1", DBConnection);
dataAdapter.Fill(localDataTable);
if (localDataTable.Rows.Count != 0)
{
numOfRows = localDataTable.Rows.Count;
}
}
private void FaceRecognition_Load(object sender, EventArgs e)
{
//if capture is not created, create it now
if (capture == null)
{
try
{
capture = new Capture();
}
catch (NullReferenceException excpt)
{
MessageBox.Show(excpt.Message);
}
}
if (capture != null)
{
if (captureInProgress)
{
Application.Idle -= ProcessFrame;
}
else
{
Application.Idle += ProcessFrame;
}
captureInProgress = !captureInProgress;
}
#endregion
{
// adjust path to find your xml at loading
haar = new HaarCascade("haarcascade_frontalface_default.xml");
connectToDatabase();
Bitmap bmpImage;
for (int i = 0; i < numOfRows; i++)
{
byte[] fetchedBytes = (byte[])localDataTable.Rows[i]["FaceImage"];
MemoryStream stream = new MemoryStream(fetchedBytes);
bmpImage = new Bitmap(stream);
trainingImages.Add(new Emgu.CV.Image<Gray, Byte>(bmpImage));
String faceName = (String)localDataTable.Rows[i]["Name"];
labels.Add(faceName);
}
}
}
导致异常的面部识别功能(使用Windows文件夹和Access数据库时完全相同):
private void ProcessFrame(object sender, EventArgs arg)
{
Image<Bgr, Byte> ImageFrame = capture.QueryFrame();
Image<Gray, byte> grayframe = ImageFrame.Convert<Gray, byte>();
MinNeighbors = int.Parse(comboBoxMinNeighbors.Text);
WindowsSize = int.Parse(textBoxWinSiz.Text);
ScaleIncreaseRate = Double.Parse(comboBoxMinNeighbors.Text);
var faces = grayframe.DetectHaarCascade(haar, ScaleIncreaseRate, MinNeighbors,
HAAR_DETECTION_TYPE.DO_CANNY_PRUNING,
new Size(WindowsSize, WindowsSize))[0];
if (faces.Length > 0)
{
Bitmap BmpInput = grayframe.ToBitmap();
Graphics FaceCanvas;
foreach (var face in faces)
{
t = t + 1;
result = ImageFrame.Copy(face.rect).Convert<Gray, byte>().Resize(100, 100, Emgu.CV.CvEnum.INTER.CV_INTER_CUBIC);
ImageFrame.Draw(face.rect, new Bgr(Color.Red), 2);
ExtractedFace = new Bitmap(face.rect.Width, face.rect.Height);
FaceCanvas = Graphics.FromImage(ExtractedFace);
FaceCanvas.DrawImage(BmpInput, 0, 0, face.rect, GraphicsUnit.Pixel);
ImageFrame.Draw(face.rect, new Bgr(Color.Red), 2);
if (trainingImages.ToArray().Length != 0)
{
MCvTermCriteria termCrit = new MCvTermCriteria(ContTrain, 0.001);
EigenObjectRecognizer recognizer = new EigenObjectRecognizer(
trainingImages.ToArray(),
labels.ToArray(),
3000,
ref termCrit);
try
{
name = recognizer.Recognize(result).Label;
}
catch (Exception error)
{
MessageBox.Show(error.ToString());
}
ImageFrame.Draw(name, ref font, new Point(face.rect.X - 2, face.rect.Y - 2), new Bgr(Color.LightGreen));
}
}
}
CamImageBox.Image = ImageFrame;
}
以下是异常消息的屏幕截图: http://i.imgur.com/DvAhABK.jpg
发生异常的第146行是ProcessFrame函数的这一行:
name = recognizer.Recognize(result).Label;
我尝试在互联网上搜索类似的问题,并发现这些: 'Object reference not set to instance of an object' error when trying to upload image to database Object reference not set to an instance of an object #5 C# Error 'Object Reference Not Set To An Instance Of An Object' C#, "Object reference not set to an instance of an object." error
他们中的大多数建议检查所涉及的任何变量是否为空。我检查了涉及的变量,实际上当recognizer.Recognize(result)
语句返回null时发生异常。
所以我的问题是,当我使用数据库中的训练图像时,为什么该语句经常返回null,而当我使用来自windows文件夹的训练图像时它永远不会返回null?
感谢任何帮助,对不起,如果问题很长,我只想清楚。 如果需要,我很乐意添加代码的其他部分:)
提前致谢!
答案 0 :(得分:0)
检查您的fetchedBytes
数组,看看您是否始终只表示BMP图像的字节流(以0x42 0x4D
开头),或者是否有“其他东西“也在那里。”
根据BMP数据如何插入Access数据库,可能包含OLE“包装器”。例如,MSPAINT.EXE就像这样保存了一个纯红色的8x8 24位BMP图像
如果我复制该文件并将其粘贴到Access窗体中的绑定对象框中,则在将BMP数据写入表之前,Access会将BMP数据包装在某些“OLE内容”中。之后,如果我尝试通过代码检索BMP图像,使用类似的东西......
Sub oleDumpTest()
Dim rst As ADODB.Recordset, ads As ADODB.Stream
Set rst = New ADODB.Recordset
rst.Open "SELECT * FROM TrainingSet1 WHERE ID = 1", Application.CurrentProject.Connection
Set ads = New ADODB.Stream
ads.Type = adTypeBinary
ads.Open
ads.Write rst("FaceImage").Value
rst.Close
Set rst = Nothing
ads.SaveToFile "C:\Users\Gord\Pictures\oleDump_red."
ads.Close
Set ads = Nothing
End Sub
...然后生成的文件还包含OLE“包装器”......
...显然不是一个有效的独立BMP文件。如果我重命名该文件以赋予它.bmp
扩展名并尝试在Paint中打开它,我会得到
因此,数据库中的[FaceImage]对象可能(某些)不是原始BMP数据,也许其他软件拒绝它们(或者根本无法理解它们)。
另一个可能的问题是,当您从文件夹中的文件中获取图像时,您将Image
对象包含一个包含文件路径的字符串...
trainingImages.Add(new Image<Gray, byte>(Application.StartupPath + "\\TrainedFaces\\" + LoadFaces));
...但是当您尝试从数据库中检索图像时,您将同一个对象传递给Bitmap
对象
MemoryStream stream = new MemoryStream(fetchedBytes);
bmpImage = new Bitmap(stream);
trainingImages.Add(new Emgu.CV.Image<Gray, Byte>(bmpImage));
我无法知道Emgu.CV.Image
对象的行为是否会有所不同,具体取决于给定对象的类型,但快速+脏的解决方法可能是将bmpImage
写入临时文件,手trainingImages.Add
该文件的路径,然后删除该文件。
答案 1 :(得分:0)
终于成功了!!再过一天的编码帮助我解决了问题:
adb shell monkey -p com.android.mms 1
答案 2 :(得分:-1)
我无法通过从图像所在的数据库中读取直接Stream来解决问题,但是您的解决方法是将图像保存到本地文件夹,为我工作,很多人都可以共享。这是我的演示页面。从DB加载文件:http://www.edatasoluciones.com/FaceDetection/FaceDataBase