EmguCV - Face Recognition - 'Object reference not set' exception when using training set from Microsoft Access Database

给你一囗甜甜゛ 提交于 2019-11-29 12:21:01

Check your fetchedBytes array to see if you are consistently getting just a stream of bytes representing a BMP image (starting with 0x42 0x4D), or if there may be "other stuff" in there, too.

Depending on how the BMP data was inserted into the Access database it may contain an OLE "wrapper". For example, an 8x8 24-bit BMP image of pure red is saved by MSPAINT.EXE like this

If I copy that file and paste it into a Bound Object Frame in an Access form then Access wraps the BMP data in some "OLE stuff" before writing it to the table. Later, if I try to retrieve the BMP image via code, using something like this...

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

...then the resulting file also contains the OLE "wrapper"...

...and obviously is not a valid stand-alone BMP file. If I rename that file to give it a .bmp extension and try to open it in Paint, I get

So maybe (some of) the [FaceImage] objects in your database are not raw BMP data, and perhaps the other software is rejecting them (or simply not able to understand them).

Edit

Another possible issue is that when you get the images from files in a folder you hand the Image object a string containing the file path...

trainingImages.Add(new Image<Gray, byte>(Application.StartupPath + "\\TrainedFaces\\" + LoadFaces));

...but when you try to retrieve the images from the database you hand the same object a Bitmap object

MemoryStream stream = new MemoryStream(fetchedBytes);
bmpImage = new Bitmap(stream);
trainingImages.Add(new Emgu.CV.Image<Gray, Byte>(bmpImage));

I have no way of knowing whether the Emgu.CV.Image object might behave differently depending on the type of object it is given, but a quick+dirty workaround might be to write bmpImage to a temporary file, hand trainingImages.Add the path to that file, and then delete the file.

Finally made it!! just one more day of coding helped me to got the problem solved:

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; }
}

I couldnt make it work from reading a direct Stream from the the Database where the images are located but your workaround, saving the images to a local folder, worked for me, thx a lot for sharing.Here's my demo page where you load files from DB: http://www.edatasoluciones.com/FaceDetection/FaceDataBase

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!