diff --git a/src/bindings/csharp/openalpr-net/AssemblyInfo.cpp b/src/bindings/csharp/openalpr-net/AssemblyInfo.cpp index f600e22..ac5af8d 100644 --- a/src/bindings/csharp/openalpr-net/AssemblyInfo.cpp +++ b/src/bindings/csharp/openalpr-net/AssemblyInfo.cpp @@ -31,9 +31,9 @@ using namespace System::Security::Permissions; // You can specify all the value or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersionAttribute("2.0.1")] -[assembly: AssemblyFileVersionAttribute("2.0.1")] -[assembly: AssemblyInformationalVersionAttribute("2.0.1")] +[assembly: AssemblyVersionAttribute("2.1.0")] +[assembly: AssemblyFileVersionAttribute("2.1.0")] +[assembly: AssemblyInformationalVersionAttribute("2.1.0")] [assembly:ComVisible(false)]; diff --git a/src/bindings/csharp/openalpr-net/openalpr-net.cpp b/src/bindings/csharp/openalpr-net/openalpr-net.cpp index 2849380..eafc926 100644 --- a/src/bindings/csharp/openalpr-net/openalpr-net.cpp +++ b/src/bindings/csharp/openalpr-net/openalpr-net.cpp @@ -55,6 +55,16 @@ namespace openalprnet { return result; } + static std::vector ToVector(array^ src) + { + std::vector result(src->Length); + pin_ptr pin(&src[0]); + char* pch = reinterpret_cast(pin); + char *first(pch), *last(pch + src->Length); + std::copy(first, last, result.begin()); + return result; + } + static cv::Mat BitmapToMat(Bitmap^ bitmap) { int channels = 0; @@ -83,13 +93,31 @@ namespace openalprnet { bitmap->PixelFormat ); - cv::Mat dstMat(cv::Size(bitmap->Width, bitmap->Height), CV_8UC(channels), reinterpret_cast(bitmapData->Scan0.ToPointer())); + char *src = reinterpret_cast(bitmapData->Scan0.ToPointer()); + pin_ptr pin(&src[0]); + + cv::Mat dstMat(cv::Size(bitmap->Width, bitmap->Height), CV_8UC(channels), pin); bitmap->UnlockBits(bitmapData); return dstMat; } + static cv::Mat MemoryStreamBitmapToMat(MemoryStream^ memoryStream) + { + Bitmap^ bitmap = gcnew Bitmap(memoryStream); + cv::Mat mat = BitmapToMat(bitmap); + return mat; + } + + static cv::Mat ByteArrayToMat(array^ byteArray) + { + MemoryStream^ ms = gcnew MemoryStream(byteArray); + cv::Mat mat(MemoryStreamBitmapToMat(ms)); + delete ms; + return mat; + } + static Bitmap^ MatToBitmap(cv::Mat mat) { const int width = mat.size().width; @@ -122,7 +150,10 @@ namespace openalprnet { bitmap->PixelFormat ); - ::memcpy(bitmapData->Scan0.ToPointer(), data, totalSize); + char *src = reinterpret_cast(bitmapData->Scan0.ToPointer()); + pin_ptr pin(&src[0]); + + ::memcpy(pin, data, totalSize); bitmap->UnlockBits(bitmapData); @@ -213,6 +244,16 @@ namespace openalprnet { return ResetMotionDetection(Mat(filename, matType)); } + void ResetMotionDetection(MemoryStream^ memoryStream) + { + return ResetMotionDetection(Mat(memoryStream)); + } + + void ResetMotionDetection(array^ byteArray) + { + return ResetMotionDetection(Mat(byteArray)); + } + System::Drawing::Rectangle MotionDetect(Bitmap^ bitmap) { return MotionDetect(Mat(bitmap)); @@ -223,6 +264,16 @@ namespace openalprnet { return MotionDetect(Mat(filename, matType)); } + System::Drawing::Rectangle MotionDetect(MemoryStream^ memoryStream) + { + return MotionDetect(Mat(memoryStream)); + } + + System::Drawing::Rectangle MotionDetect(array^ byteArray) + { + return MotionDetect(Mat(byteArray)); + } + private: void ResetMotionDetection(cv::Mat mat) { @@ -247,17 +298,29 @@ namespace openalprnet { return mat; } + cv::Mat Mat(MemoryStream^ memoryStream) + { + cv::Mat mat = AlprHelper::MemoryStreamBitmapToMat(memoryStream); + return mat; + } + + cv::Mat Mat(array^ byteArray) + { + cv::Mat mat = AlprHelper::ByteArrayToMat(byteArray); + return mat; + } + private: ~AlprMotionDetectionNet() { - if(this->m_Disposed) + if(this->m_disposed) { return; } this->!AlprMotionDetectionNet(); - this->m_Disposed = true; + this->m_disposed = true; } !AlprMotionDetectionNet() @@ -267,7 +330,7 @@ namespace openalprnet { private: MotionDetector* m_motionDetector; - bool m_Disposed; + bool m_disposed; }; @@ -279,13 +342,14 @@ namespace openalprnet { public ref class AlprConfigNet sealed { - public: - - AlprConfigNet(Config* config) : m_config (config) + internal: + AlprConfigNet(Config* config) : m_config(config) { - + } + public: + property bool IsLoaded { bool get() { @@ -413,7 +477,7 @@ namespace openalprnet { } } - property float minPlateSizeHeightPx { + property float MinPlateSizeHeightPx { float get() { return this->m_config->minPlateSizeHeightPx; @@ -930,19 +994,19 @@ namespace openalprnet { m_matches_template=plate.matches_template; } - property System::String^ characters { + property System::String^ Characters { System::String^ get() { return m_characters; } } - property float overall_confidence { + property float OverallConfidence { float get() { return m_overall_confidence; } } - property bool matches_template { + property bool MatchesTemplate { bool get() { return m_matches_template; } @@ -978,49 +1042,49 @@ namespace openalprnet { } } - property int requested_topn { + property int RequestedTopN { int get() { return m_requested_topn; } } - property int regionConfidence { + property int RegionConfidence { int get() { return m_regionConfidence; } } - property int plate_index { + property int PlateIndex { int get() { return m_plate_index; } } - property System::String^ region { + property System::String^ Region { System::String^ get() { return m_region; } } - property AlprPlateNet^ bestPlate { + property AlprPlateNet^ BestPlate { AlprPlateNet^ get() { return m_bestPlate; } } - property List^ plate_points { + property List^ PlatePoints { List^ get() { return m_plate_points; } } - property List^ topNPlates { + property List^ TopNPlates { List^ get() { return m_topNPlates; } } - property float processing_time_ms { + property float ProcessingTimeMs { float get() { return m_processing_time_ms; } @@ -1069,43 +1133,43 @@ namespace openalprnet { m_json = AlprHelper::ToManagedString(json); } - property long epoch_time { + property long EpochTime { long get() { return m_epoch_time; } } - property int img_width { + property int ImageWidth { int get() { return m_img_width; } } - property int img_height { + property int ImageHeight { int get() { return m_img_height; } } - property float total_processing_time_ms { + property float TotalProcessingTimeMs { float get() { return m_total_processing_time_ms; } } - property List^ regionsOfInterest { + property List^ RegionsOfInterest { List^ get() { return m_regionsOfInterest; } } - property List^ plates { + property List^ Plates { List^ get() { return m_plates; } } - property System::String^ json { + property System::String^ Json { System::String^ get() { return m_json; } @@ -1175,13 +1239,13 @@ namespace openalprnet { } ~AlprNet() { - if(this->m_Disposed) + if(this->m_disposed) { return; } this->!AlprNet(); - this->m_Disposed = true; + this->m_disposed = true; } property AlprConfigNet^ Configuration { @@ -1257,7 +1321,7 @@ namespace openalprnet { /// /// Recognize from an image on disk /// - AlprResultsNet^ recognize(System::String^ filepath) { + AlprResultsNet^ Recognize(System::String^ filepath) { AlprResults results = m_Impl->recognize(marshal_as(filepath)); return gcnew AlprResultsNet(results); } @@ -1265,7 +1329,7 @@ namespace openalprnet { /// /// Recognize from an image on disk /// - AlprResultsNet^ recognize(System::String^ filepath, List^ regionsOfInterest) { + AlprResultsNet^ Recognize(System::String^ filepath, List^ regionsOfInterest) { cv::Mat frame = cv::imread( marshal_as(filepath) ); std::vector rois = AlprHelper::ToVector(regionsOfInterest); AlprResults results = m_Impl->recognize(frame.data, frame.elemSize(), frame.cols, frame.rows, rois ); @@ -1275,7 +1339,15 @@ namespace openalprnet { /// /// Recognize from a bitmap /// - AlprResultsNet^ recognize(Bitmap^ bitmap, List^ regionsOfInterest) + AlprResultsNet^ Recognize(Bitmap^ bitmap) + { + return Recognize(bitmap, gcnew List()); + } + + /// + /// Recognize from a bitmap + /// + AlprResultsNet^ Recognize(Bitmap^ bitmap, List^ regionsOfInterest) { cv::Mat frame = AlprHelper::BitmapToMat(bitmap); std::vector rois = AlprHelper::ToVector(regionsOfInterest); @@ -1284,20 +1356,17 @@ namespace openalprnet { } /// - /// Recognize from a bitmap + /// Recognize from MemoryStream representing an encoded image (e.g., BMP, PNG, JPG, GIF etc). /// - AlprResultsNet^ recognize(Bitmap^ bitmap) + AlprResultsNet^ Recognize(MemoryStream^ memoryStream) { - cv::Mat frame = AlprHelper::BitmapToMat(bitmap); - std::vector rois; - AlprResults results = m_Impl->recognize(frame.data, frame.elemSize(), frame.cols, frame.rows, rois); - return gcnew AlprResultsNet(results); + return Recognize(memoryStream, gcnew List()); } /// /// Recognize from MemoryStream representing an encoded image (e.g., BMP, PNG, JPG, GIF etc). /// - AlprResultsNet^ recognize(MemoryStream^ memoryStream) + AlprResultsNet^ Recognize(MemoryStream^ memoryStream, List^ regionsOfInterest) { std::vector p = AlprHelper::MemoryStreamToVector(memoryStream); AlprResults results = m_Impl->recognize(p); @@ -1308,7 +1377,15 @@ namespace openalprnet { /// Recognize from byte data representing an encoded image (e.g., BMP, PNG, JPG, GIF etc). /// /// Bytes representing image data - AlprResultsNet^ recognize(cli::array^ imageBuffer) { + AlprResultsNet^ Recognize(cli::array^ imageBuffer) { + return Recognize(imageBuffer, gcnew List()); + } + + /// + /// Recognize from byte data representing an encoded image (e.g., BMP, PNG, JPG, GIF etc). + /// + /// Bytes representing image data + AlprResultsNet^ Recognize(cli::array^ imageBuffer, List^ regionsOfInterest) { std::vector p = AlprHelper::ToVector(imageBuffer); AlprResults results = m_Impl->recognize(p); return gcnew AlprResultsNet(results); @@ -1317,19 +1394,26 @@ namespace openalprnet { /// /// Recognize from raw pixel data /// - AlprResultsNet^ recognize(cli::array^ pixelData, int bytesPerPixel, int imgWidth, int imgHeight, List^ regionsOfInterest) { - unsigned char* p = AlprHelper::ToCharPtr(pixelData); + AlprResultsNet^ Recognize(cli::array^ imageBuffer, int bytesPerPixel, int imgWidth, int imgHeight) { + return Recognize(imageBuffer, bytesPerPixel, imgWidth, imgHeight, gcnew List()); + } + + /// + /// Recognize from raw pixel data + /// + AlprResultsNet^ Recognize(cli::array^ imageBuffer, int bytesPerPixel, int imgWidth, int imgHeight, List^ regionsOfInterest) { + unsigned char* p = AlprHelper::ToCharPtr(imageBuffer); std::vector rois = AlprHelper::ToVector(regionsOfInterest); AlprResults results = m_Impl->recognize(p, bytesPerPixel, imgWidth, imgHeight, rois); free(p); // ?? memory leak? return gcnew AlprResultsNet(results); } - bool isLoaded() { + bool IsLoaded() { return m_Impl->isLoaded(); } - static System::String^ getVersion() { + static System::String^ GetVersion() { return AlprHelper::ToManagedString(Alpr::getVersion()); } @@ -1346,6 +1430,6 @@ namespace openalprnet { int m_topN; bool m_detectRegion; System::String^ m_defaultRegion; - bool m_Disposed; + bool m_disposed; }; } diff --git a/src/bindings/csharp/openalprnet-cli/Program.cs b/src/bindings/csharp/openalprnet-cli/Program.cs index fee8e32..556d4d3 100644 --- a/src/bindings/csharp/openalprnet-cli/Program.cs +++ b/src/bindings/csharp/openalprnet-cli/Program.cs @@ -66,11 +66,11 @@ namespace openalprnet_cli val => { if (val.Any()) filename = val.First().Trim(); }) ); - Console.WriteLine("OpenAlpr Version: {0}", AlprNet.getVersion()); + Console.WriteLine("OpenAlpr Version: {0}", AlprNet.GetVersion()); var config = Path.Combine(AssemblyDirectory, "openalpr.conf"); var runtime_data = Path.Combine(AssemblyDirectory, "runtime_data"); var alpr = new AlprNet(region, config, runtime_data); - if (!alpr.isLoaded()) + if (!alpr.IsLoaded()) { Console.WriteLine("OpenAlpr failed to load!"); return; @@ -110,8 +110,7 @@ namespace openalprnet_cli private static void PerformAlpr(AlprNet alpr, byte[] buffer, bool benchmark, bool writeJson) { var sw = Stopwatch.StartNew(); - sbyte[] signedBuffer = (sbyte[])(Array)buffer; - var results = alpr.recognize(signedBuffer); + var results = alpr.Recognize(buffer); sw.Stop(); if (benchmark) { @@ -125,14 +124,14 @@ namespace openalprnet_cli else { var i = 0; - foreach (var result in results.plates) + foreach (var result in results.Plates) { - Console.WriteLine("Plate {0}: {1} result(s)", i++, result.topNPlates.Count); - Console.WriteLine(" Processing Time: {0} msec(s)", result.processing_time_ms); - foreach (var plate in result.topNPlates) + Console.WriteLine("Plate {0}: {1} result(s)", i++, result.TopNPlates.Count); + Console.WriteLine(" Processing Time: {0} msec(s)", result.ProcessingTimeMs); + foreach (var plate in result.TopNPlates) { - Console.WriteLine(" - {0}\t Confidence: {1}\tMatches Template: {2}", plate.characters, - plate.overall_confidence, plate.matches_template); + Console.WriteLine(" - {0}\t Confidence: {1}\tMatches Template: {2}", plate.Characters, + plate.OverallConfidence, plate.MatchesTemplate); } } } diff --git a/src/bindings/csharp/openalprnet-windemo/Form1.cs b/src/bindings/csharp/openalprnet-windemo/Form1.cs index 98587c8..e60ab62 100644 --- a/src/bindings/csharp/openalprnet-windemo/Form1.cs +++ b/src/bindings/csharp/openalprnet-windemo/Form1.cs @@ -22,6 +22,7 @@ using System.Drawing; using System.IO; using System.Linq; using System.Reflection; +using System.Threading.Tasks; using System.Windows.Forms; using openalprnet; @@ -135,7 +136,7 @@ namespace openalprnet_windemo String runtime_data_dir = Path.Combine(AssemblyDirectory, "runtime_data"); using (var alpr = new AlprNet(region, config_file, runtime_data_dir)) { - if (!alpr.isLoaded()) + if (!alpr.IsLoaded()) { lbxPlates.Items.Add("Error initializing OpenALPR"); return; @@ -143,24 +144,31 @@ namespace openalprnet_windemo picOriginal.ImageLocation = fileName; picOriginal.Load(); - var results = alpr.recognize(fileName); - - var images = new List(results.plates.Count()); - var i = 1; - foreach (var result in results.plates) + var motionDetection = new AlprMotionDetectionNet(); + var b = File.ReadAllBytes(fileName); + Parallel.For(0, int.MaxValue, (x) => { - var rect = boundingRectangle(result.plate_points); + motionDetection.MotionDetect(b); + }); + + var results = alpr.Recognize(fileName); + + var images = new List(results.Plates.Count()); + var i = 1; + foreach (var result in results.Plates) + { + var rect = boundingRectangle(result.PlatePoints); var img = Image.FromFile(fileName); var cropped = cropImage(img, rect); images.Add(cropped); lbxPlates.Items.Add("\t\t-- Plate #" + i++ + " --"); - foreach (var plate in result.topNPlates) + foreach (var plate in result.TopNPlates) { lbxPlates.Items.Add(string.Format(@"{0} {1}% {2}", - plate.characters.PadRight(12), - plate.overall_confidence.ToString("N1").PadLeft(8), - plate.matches_template.ToString().PadLeft(8))); + plate.Characters.PadRight(12), + plate.OverallConfidence.ToString("N1").PadLeft(8), + plate.MatchesTemplate.ToString().PadLeft(8))); } }