2

我一直在使用 EmguCV (C#) 开发人脸识别应用程序。如果我将面部图像(训练集)存储在简单的 Windows 文件夹中,我可以让整个工作正常。但是,在我尝试迁移要存储在 Microsoft Access 数据库中的面部图像后,当应用程序尝试时,经常会出现“未设置对象实例的对象引用”异常消息(并非总是如此,但大多数情况下)从视频源中识别人脸。

有趣的是,如果碰巧没有发生异常,识别实际上仍然可以正常工作。

这是我的程序的代码片段,使用 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;

我尝试在互联网上搜索类似的问题,并找到了这些: 尝试将图像上传到数据库时出现“对象引用未设置为对象实例”错误 对象引用未设置为对象实例#5 C#错误“对象引用”未设置为对象的实例' C#,“对象引用未设置为对象的实例。” 错误

他们中的大多数人建议检查任何涉及的变量是否为空。我检查了所涉及的变量,当recognizer.Recognize(result)语句返回 null 时确实发生了异常。

所以我的问题是,为什么当我使用数据库中的训练图像时该语句经常返回 null,而当我使用 windows 文件夹中的训练图像时它从不返回 null?

4

3 回答 3

0

检查您的fetchedBytes数组,看看您是否始终获得表示 BMP 图像的字节流(以 开头0x42 0x4D),或者那里是否也可能有“其他东西”。

根据 BMP 数据插入 Access 数据库的方式,它可能包含 OLE“包装器”。例如,一个 8x8 24 位的纯红色 BMP 图像由 MSPAINT.EXE 保存如下

bmp转储文件

如果我复制该文件并将其粘贴到 Access 表单中的绑定对象框架中,则 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“包装器”...

oleDump.png

...显然不是一个有效的独立 BMP 文件。如果我重命名该文件以为其提供.bmp扩展名并尝试在 Paint 中打开它,我会得到

油漆错误.png

因此,数据库中的(某些)[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将路径交给该文件,然后删除该文件。

于 2013-05-09T13:09:29.533 回答
0

终于成功了!!仅仅一天的编码帮助我解决了问题:

public void ProcessRequest(HttpContext context)
{
    _httpContext = context;
    var imageid = context.Request.QueryString["Image"];
    if (imageid == null || imageid == "")
    {
        imageid = "1";
    }


    using (WebClient wc = new WebClient())
    {
        // Handler retrieves the image from database and load it on the stream
        using (Stream s = wc.OpenRead("http://mypageurl/Image.ashx?Image=" + imageid))
        {
            using (Bitmap bmp = new Bitmap(s))
            {
                AddFace(bmp);
            }
        }
    }

}

public void AddFace(Bitmap image)
{
    var faceImage = DetectFace(image);
    if (faceImage != null)
    {
        var stream = new MemoryStream();
        faceImage.Save(stream, ImageFormat.Bmp);
        stream.Position = 0;
        byte[] data = new byte[stream.Length];
        stream.Read(data, 0, (int)stream.Length);

        _httpContext.Response.Clear();
        _httpContext.Response.ContentType = "image/jpeg";
        _httpContext.Response.BinaryWrite(data);
    }
}

private Bitmap DetectFace(Bitmap faceImage)
{
    var image = new Image<Bgr, byte>(faceImage);
    var gray = image.Convert<Gray, Byte>();
    string filePath = HttpContext.Current.Server.MapPath("haarcascade_frontalface_default.xml");
    var face = new HaarCascade(filePath);
    MCvAvgComp[][] facesDetected = gray.DetectHaarCascade(face, 1.1, 10, HAAR_DETECTION_TYPE.DO_CANNY_PRUNING, new Size(20, 20));
    Image<Gray, byte> result = null;

    foreach (MCvAvgComp f in facesDetected[0])
    {
        //draw the face detected in the 0th (gray) channel with blue color
        image.Draw(f.rect, new Bgr(Color.Blue), 2);
        result = image.Copy(f.rect).Convert<Gray, byte>();
        break;
    }

    if (result != null)
    {
        result = result.Resize(200, 200, INTER.CV_INTER_CUBIC);
        return result.Bitmap;
    }


   return null;
}

public bool IsReusable
{
    get { return false; }
}
于 2015-10-29T20:57:45.007 回答
-1

我无法通过从图像所在的数据库中读取直接流来使其工作,但是您的解决方法,将图像保存到本地文件夹,对我有用,非常适合共享。这是我的演示页面,您可以从中加载文件数据库:http ://www.edatasoluciones.com/FaceDetection/FaceDataBase

于 2015-10-28T23:53:22.133 回答