Search code examples
c#opencvexceptionopenalpr

OpenALPR crash - Attempted to read or write protected memory


I have a C# program that has been crashing after a variable amount of time. I've tracked it down to OpenALPR and have now duplicated the problem in a test program.

I basically ask to get the plates from an image in a while loop. It fails after a bunch of iterations. Failed after Iterations : 179, 221, 516, 429, 295, 150

Program output:

...
  Iter (219)  No Plates Found in image 71197e9d829d4d429e74a71c983380dc_09032015
134103267.jpg
Config file location provided via API
LBP Time: 0.005ms.
Total Time to process image: 1.916ms.
  Iter (220)  No Plates Found in image 71197e9d829d4d429e74a71c983380dc_09032015
134103267.jpg
Config file location provided via API
LBP Time: 0.003ms.
Total Time to process image: 4.071ms.
  Iter (221)  No Plates Found in image 71197e9d829d4d429e74a71c983380dc_09032015
134103267.jpg
Config file location provided via API

Failure message:

Unhandled Exception:
Unhandled Exception: System.AccessViolationException: Attempted to read or write
 protected memory. This is often an indication that other memory is corrupt.
   at openalprnet.AlprNet.Dispose(Boolean )
System.AccessViolationException: Attempted to read or write protected memory. Th
is is often an indication that other memory is corrupt.
   at alpr.Alpr.{ctor}(Alpr* , basic_string<char\,std::char_traits<char>\,std::a
llocator<char> >* , basic_string<char\,std::char_traits<char>\,std::allocator<ch
ar> >* , basic_string<char\,std::char_traits<char>\,std::allocator<char> >* )
   at openalprnet.AlprNet..ctor(String country, String configFile, String runtim
eDir)
   at AlprTest.Program.Main(String[] args) in C:\Users\foo\Desktop\c#LPR\A
lprTest\Program.cs:line 25

One time, I also got part of another error message(not sure if its related or not) : Unable to load regex: @###@@. Although the error above is pointing to the CTOR, I have, in my normal application, had it fail during the recognize call. I've also seen (not sure how accurate these stack traces are) it in openalprnet.AlprNet.Dispose(Boolean) which was called from alpr.Alpr.{ctor}(...

My test program :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using openalprnet;

namespace AlprTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string chipPath = "71197e9d829d4d429e74a71c983380dc_09032015134103267.jpg";
            string confPath = Path.GetFullPath(".\\openalpr.conf");
            string runtimeDirPath = Path.GetFullPath(".\\runtime_data");
            int i = 0;
            while (true)
            {
                ++i;
                try
                {
                    // Look at target velocity and pick a conf file to use.
                    //
                    AlprNet alpr = new AlprNet("us", confPath, runtimeDirPath);

                    if (!alpr.isLoaded())
                    {
                        return;
                    }
                    // Optionally apply pattern matching for a particular region
                    alpr.DefaultRegion = "va"; // was md
                    alpr.DetectRegion = true;

                    AlprResultsNet results = alpr.recognize(chipPath);

                    if (results.plates.Count < 1)
                    {
                        Console.WriteLine("  Iter ({1})  No Plates Found in image {0}", chipPath, i);
                    }
                    else
                    {
                        int j = 0;
                        foreach (var result in results.plates)
                        {
                            Console.WriteLine("Plate {0}: {1} result(s)", ++j, result.topNPlates.Count);
                            Console.WriteLine("  Processing Time: {0} msec(s)", result.processing_time_ms);
                            foreach (var plate in result.topNPlates)
                            {
                                Console.WriteLine("  - {0}\t Confidence: {1}\tMatches Template: {2}", plate.characters,
                                                    plate.overall_confidence, plate.matches_template);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception caught in LPR processing.  Ex={0}", ex);
                    return;
                }
            }
        }
    }
}

The program depends on the openalpr distribution and corresponding opencv dlls. openalpr-net.dll, liblept170.dll, opencv_core248.dll, opencv_features2d248.dll, opencv_ffmpeg248.dll, opencv_flann248.dll, opencv_highgui248.dll, opencv_imgproc248.dll, opencv_objdetect248.dll, opencv_video248.dll. It also uses a runtime_data directory (which I simply copied from the sample app) which seems to contain training data and such.

So, obviously, I'm using C#. I'm using Visual Studio 2010 and .NET 4.0

I'm assuming that I'm using OpenALPR wrong and that there is, in fact, nothing wrong with it. This would seem to be a pretty basic function. Aside from fixing it... why does this crash my program and how can I catch this and recover? You notice my try-catch totally fails to catch it and it crashes the whole application.

EDIT : While running the test app, it starts with like 2gig of memory, but it just grows and grows and grows. It crashed with 7.7 gig after 147 loops.

EDIT EDIT : Added in call to Dispose after each iteration and now the program sits pretty steady at 50-75 megs of memory.


Solution

  • Turns out the problem was the Dispose.

    Need to Dispose of the object. Better yet, don't dispose of the object and re-use it. So long as the config doesn't change you can reuse the object. Sadly, the prewarp is in the config so you likely won't be able to reuse the object. Call Dispose before the object leaves scope.

                try
                {
                    // Look at target velocity and pick a conf file to use.
                    //
                    AlprNet alpr = new AlprNet("us", confPath, runtimeDirPath);
    
                    if (!alpr.isLoaded())
                    {
                        return;
                    }
                    // Optionally apply pattern matching for a particular region
                    alpr.DefaultRegion = "va"; // was md
                    alpr.DetectRegion = true;
    
                    AlprResultsNet results = alpr.recognize(chipPath);
    
                    ...
    
                    alpr.Dispose(); // Dispose of the object so it can clean up
                }