From 881d2e413b1b1b7ff4ad31cddd1989502baea48b Mon Sep 17 00:00:00 2001 From: Peter Rekdal Sunde Date: Tue, 7 Jul 2015 18:28:15 +0200 Subject: [PATCH 01/10] Feature: Allow .NET users to manage configuration after it has been loaded from disk. --- .../csharp/openalpr-net/openalpr-net.cpp | 666 +++++++++++++++++- src/openalpr/alpr.cpp | 5 +- src/openalpr/alpr.h | 3 + src/openalpr/config.cpp | 24 +- src/openalpr/config.h | 2 +- 5 files changed, 684 insertions(+), 16 deletions(-) diff --git a/src/bindings/csharp/openalpr-net/openalpr-net.cpp b/src/bindings/csharp/openalpr-net/openalpr-net.cpp index 521988a..17ea868 100644 --- a/src/bindings/csharp/openalpr-net/openalpr-net.cpp +++ b/src/bindings/csharp/openalpr-net/openalpr-net.cpp @@ -19,6 +19,7 @@ #include "stdafx.h" #include "openalpr-net.h" #include "alpr.h" +#include "config.h" // alpr #include #include #include @@ -89,6 +90,655 @@ namespace openalprnet { } }; + public enum class AlprDetectorTypeNet : int { + DetectorLbpCpu = alpr::DETECTOR_LBP_CPU, + DetectorLbpGpu = alpr::DETECTOR_LBP_GPU, + DetectorLbpMorphCpu = alpr::DETECTOR_MORPH_CPU + }; + + public ref class AlprConfigNet sealed + { + public: + + AlprConfigNet(Config* config) : m_config (config) + { + + } + + property bool IsLoaded { + bool get() + { + return this->m_config->loaded; + } + } + + property AlprDetectorTypeNet Detector { + AlprDetectorTypeNet get() { + return static_cast(this->m_config->detector); + } + void set(AlprDetectorTypeNet value) + { + this->m_config->detector = static_cast(value); + } + } + + property float DetectionIterationIncrease { + float get() + { + return this->m_config->detection_iteration_increase; + } + void set(float value) + { + this->m_config->detection_iteration_increase = value; + } + } + + property float DetectionStrictness { + float get() + { + return this->m_config->detectionStrictness; + } + void set(float value) + { + this->m_config->detectionStrictness = value; + } + } + + property float MaxPlateWidthPercent { + float get() + { + return this->m_config->maxPlateWidthPercent; + } + void set(float value) + { + this->m_config->maxPlateWidthPercent = value; + } + } + + property float MaxPlateHeightPercent { + float get() + { + return this->m_config->maxPlateHeightPercent; + } + void set(float value) + { + this->m_config->maxPlateHeightPercent = value; + } + } + + property int MaxDetectionInputWidth { + int get() + { + return this->m_config->maxDetectionInputWidth; + } + void set(int value) + { + this->m_config->maxDetectionInputWidth = value; + } + } + + property int MaxDetectionInputHeight { + int get() + { + return this->m_config->maxDetectionInputHeight; + } + void set(int value) + { + this->m_config->maxDetectionInputHeight = value; + } + } + + property bool SkipDetection { + bool get() + { + return this->m_config->skipDetection; + } + void set(bool value) + { + this->m_config->skipDetection = true; + } + } + + property String^ PreWarp { + String^ get() + { + return AlprHelper::ToManagedString(this->m_config->prewarp); + } + void set(String^ value) + { + this->m_config->prewarp = marshal_as(value); + } + } + + property int MaxPlateAngleDegrees { + int get() + { + return this->m_config->maxPlateAngleDegrees; + } + void set(int value) + { + this->m_config->maxPlateAngleDegrees = value; + } + } + + property float MinPlateSizeWidthPx { + float get() + { + return this->m_config->minPlateSizeWidthPx; + } + void set(float value) + { + this->m_config->minPlateSizeWidthPx = value; + } + } + + property float minPlateSizeHeightPx { + float get() + { + return this->m_config->minPlateSizeHeightPx; + } + void set(float value) + { + this->m_config->minPlateSizeHeightPx = value; + } + } + + property bool Multiline { + bool get() + { + return this->m_config->multiline; + } + void set(bool value) + { + this->m_config->multiline = value; + } + } + + property float PlateWidthMM { + float get() + { + return this->m_config->plateWidthMM; + } + void set(float value) + { + this->m_config->plateWidthMM = value; + } + } + + property float PlateHeightMM { + float get() + { + return this->m_config->plateHeightMM; + } + void set(float value) + { + this->m_config->plateHeightMM = value; + } + } + + property float CharHeightMM { + float get() + { + return this->m_config->charHeightMM; + } + void set(float value) + { + this->m_config->charHeightMM = value; + } + } + + property float CharWidthMM { + float get() + { + return this->m_config->charWidthMM; + } + void set(float value) + { + this->m_config->charWidthMM = value; + } + } + + property float CharWhitespaceTopMM { + float get() + { + return this->m_config->charWhitespaceTopMM; + } + void set(float value) + { + this->m_config->charWhitespaceTopMM = value; + } + } + + property float CharWhitespaceBotMM { + float get() + { + return this->m_config->charWhitespaceBotMM; + } + void set(float value) + { + this->m_config->charWhitespaceBotMM = value; + } + } + + property int TemplateWidthPx { + int get() + { + return this->m_config->templateWidthPx; + } + void set(int value) + { + this->m_config->templateWidthPx = value; + } + } + + property int TemplateHeightPx { + int get() + { + return this->m_config->templateHeightPx; + } + void set(int value) + { + this->m_config->templateHeightPx = value; + } + } + + property int OcrImageWidthPx { + int get() + { + return this->m_config->ocrImageWidthPx; + } + void set(int value) + { + this->m_config->ocrImageWidthPx = value; + } + } + + property int OcrImageHeightPx { + int get() + { + return this->m_config->ocrImageHeightPx; + } + void set(int value) + { + this->m_config->ocrImageHeightPx = value; + } + } + + property int StateIdImageWidthPx { + int get() + { + return this->m_config->stateIdImageWidthPx; + } + void set(int value) + { + this->m_config->stateIdImageWidthPx = value; + } + } + + property int StateIdimageHeightPx { + int get() + { + return this->m_config->stateIdimageHeightPx; + } + void set(int value) + { + this->m_config->stateIdimageHeightPx = value; + } + } + + property float CharAnalysisMinPercent { + float get() + { + return this->m_config->charAnalysisMinPercent; + } + void set(float value) + { + this->m_config->charAnalysisMinPercent = value; + } + } + + property float CharAnalysisHeightRange { + float get() + { + return this->m_config->charAnalysisHeightRange; + } + void set(float value) + { + this->m_config->charAnalysisHeightRange = value; + } + } + + property float CharAnalysisHeightStepSize { + float get() + { + return this->m_config->charAnalysisHeightStepSize; + } + void set(float value) + { + this->m_config->charAnalysisHeightStepSize = value; + } + } + + property int CharAnalysisNumSteps { + int get() + { + return this->m_config->charAnalysisNumSteps; + } + void set(int value) + { + this->m_config->charAnalysisNumSteps = value; + } + } + + property float PlateLinesSensitivityVertical { + float get() + { + return this->m_config->plateLinesSensitivityVertical; + } + void set(float value) + { + this->m_config->plateLinesSensitivityVertical = value; + } + } + + property float PlateLinesSensitivityHorizontal { + float get() + { + return this->m_config->plateLinesSensitivityHorizontal; + } + void set(float value) + { + this->m_config->plateLinesSensitivityHorizontal = value; + } + } + + property int SegmentationMinBoxWidthPx { + int get() + { + return this->m_config->segmentationMinBoxWidthPx; + } + void set(int value) + { + this->m_config->segmentationMinBoxWidthPx = value; + } + } + + property float SegmentationMinCharHeightPercent { + float get() + { + return this->m_config->segmentationMinCharHeightPercent; + } + void set(float value) + { + this->m_config->segmentationMinCharHeightPercent = value; + } + } + + property float SegmentationMaxCharWidthvsAverage { + float get() + { + return this->m_config->segmentationMaxCharWidthvsAverage; + } + void set(float value) + { + this->m_config->segmentationMaxCharWidthvsAverage = value; + } + } + + property String^ OcrLanguage { + String^ get() + { + return AlprHelper::ToManagedString(this->m_config->ocrLanguage); + } + void set(String^ value) + { + this->m_config->ocrLanguage = marshal_as(value); + } + } + + property int OcrMinFontSize { + int get() + { + return this->m_config->ocrMinFontSize; + } + void set(int value) + { + this->m_config->ocrMinFontSize = value; + } + } + + property float PostProcessMinConfidence { + float get() + { + return this->m_config->postProcessMinConfidence; + } + void set(float value) + { + this->m_config->postProcessMinConfidence = value; + } + } + + property float PostProcessConfidenceSkipLevel { + float get() + { + return this->m_config->postProcessConfidenceSkipLevel; + } + void set(float value) + { + this->m_config->postProcessConfidenceSkipLevel = value; + } + } + + property unsigned int PostProcessMinCharacters { + unsigned int get() + { + return this->m_config->postProcessMinCharacters; + } + void set(unsigned int value) + { + this->m_config->postProcessMinCharacters = value; + } + } + + property unsigned int PostProcessMaxCharacters { + unsigned int get() + { + return this->m_config->postProcessMaxCharacters; + } + void set(unsigned int value) + { + this->m_config->postProcessMaxCharacters = value; + } + } + + property bool DebugGeneral { + bool get() + { + return this->m_config->debugGeneral; + } + void set(bool value) + { + this->m_config->debugGeneral = value; + } + } + + property bool DebugTiming { + bool get() + { + return this->m_config->debugTiming; + } + void set(bool value) + { + this->m_config->debugTiming = value; + } + } + + property bool DebugPrewarp { + bool get() + { + return this->m_config->debugPrewarp; + } + void set(bool value) + { + this->m_config->debugPrewarp = value; + } + } + + property bool DebugDetector { + bool get() + { + return this->m_config->debugDetector; + } + void set(bool value) + { + this->m_config->debugDetector = value; + } + } + + property bool DebugStateId { + bool get() + { + return this->m_config->debugStateId; + } + void set(bool value) + { + this->m_config->debugStateId = value; + } + } + + property bool DebugPlateLines { + bool get() + { + return this->m_config->debugPlateLines; + } + void set(bool value) + { + this->m_config->debugPlateLines = value; + } + } + + property bool DebugPlateCorners { + bool get() + { + return this->m_config->debugPlateCorners; + } + void set(bool value) + { + this->m_config->debugPlateCorners = value; + } + } + + property bool DebugCharSegmenter { + bool get() + { + return this->m_config->debugCharSegmenter; + } + void set(bool value) + { + this->m_config->debugCharSegmenter = value; + } + } + + property bool DebugCharAnalysis { + bool get() + { + return this->m_config->debugCharAnalysis; + } + void set(bool value) + { + this->m_config->debugCharAnalysis = value; + } + } + + property bool DebugColorFiler { + bool get() + { + return this->m_config->debugColorFiler; + } + void set(bool value) + { + this->m_config->debugColorFiler = value; + } + } + + property bool DebugOcr { + bool get() + { + return this->m_config->debugOcr; + } + void set(bool value) + { + this->m_config->debugOcr = value; + } + } + + property bool DebugPostProcess { + bool get() + { + return this->m_config->debugPostProcess; + } + void set(bool value) + { + this->m_config->debugPostProcess = value; + } + } + + property bool DebugShowImages { + bool get() + { + return this->m_config->debugShowImages; + } + void set(bool value) + { + this->m_config->debugShowImages = value; + } + } + + property bool DebugPauseOnFrame { + bool get() + { + return this->m_config->debugPauseOnFrame; + } + void set(bool value) + { + this->m_config->debugPauseOnFrame = value; + } + } + + void DebugOff(bool value) + { + this->m_config->debugOff(value); + } + + String^ GetKeypointsRuntimeDir() + { + return AlprHelper::ToManagedString(this->m_config->getKeypointsRuntimeDir()); + } + + String^ GetCascadeRuntimeDir() + { + return AlprHelper::ToManagedString(this->m_config->getCascadeRuntimeDir()); + } + + String^ GetPostProcessRuntimeDir() + { + return AlprHelper::ToManagedString(this->m_config->getPostProcessRuntimeDir()); + } + + String^ GetTessdataPrefix() + { + return AlprHelper::ToManagedString(this->m_config->getTessdataPrefix()); + } + + ~AlprConfigNet() + { + // void + } + + private: + Config *m_config; + }; + public ref class AlprPlateNet sealed { public: @@ -338,13 +988,23 @@ namespace openalprnet { { public: // Allocate the native object on the C++ Heap via a constructor - AlprNet(System::String^ country, System::String^ configFile, System::String^ runtimeDir) : m_Impl( new Alpr(marshal_as(country), marshal_as(configFile), marshal_as(runtimeDir)) ) { } + AlprNet(System::String^ country, System::String^ configFile, System::String^ runtimeDir) : m_Impl( new Alpr(marshal_as(country), marshal_as(configFile), marshal_as(runtimeDir)) ) + { + this->m_config = gcnew AlprConfigNet(this->m_Impl->getConfig()); + } // Deallocate the native object on a destructor ~AlprNet(){ delete m_Impl; } + property AlprConfigNet^ Configuration { + AlprConfigNet^ get() + { + return this->m_config; + } + } + property int TopN { int get() { return m_topN; @@ -459,10 +1119,12 @@ namespace openalprnet { // Deallocate the native object on the finalizer just in case no destructor is called !AlprNet() { delete m_Impl; + delete m_config; } - + private: Alpr * m_Impl; + AlprConfigNet^ m_config; int m_topN; bool m_detectRegion; System::String^ m_defaultRegion; diff --git a/src/openalpr/alpr.cpp b/src/openalpr/alpr.cpp index bb4bf28..840b96b 100644 --- a/src/openalpr/alpr.cpp +++ b/src/openalpr/alpr.cpp @@ -108,5 +108,8 @@ namespace alpr return AlprImpl::getVersion(); } - + Config* Alpr::getConfig() + { + return impl->config; + } } \ No newline at end of file diff --git a/src/openalpr/alpr.h b/src/openalpr/alpr.h index 9c90a88..7146322 100644 --- a/src/openalpr/alpr.h +++ b/src/openalpr/alpr.h @@ -116,6 +116,7 @@ namespace alpr }; + class Config; class AlprImpl; class Alpr { @@ -145,6 +146,8 @@ namespace alpr static std::string getVersion(); + Config* getConfig(); + private: AlprImpl* impl; }; diff --git a/src/openalpr/config.cpp b/src/openalpr/config.cpp index 7146a4c..d89b7a3 100644 --- a/src/openalpr/config.cpp +++ b/src/openalpr/config.cpp @@ -241,19 +241,19 @@ namespace alpr } - void Config::debugOff() + void Config::debugOff(bool value) { - debugGeneral = false; - debugTiming = false; - debugStateId = false; - debugPlateLines = false; - debugPlateCorners = false; - debugCharSegmenter = false; - debugCharAnalysis = false; - debugColorFiler = false; - debugOcr = false; - debugPostProcess = false; - debugPauseOnFrame = false; + debugGeneral = !value; + debugTiming = !value; + debugStateId = !value; + debugPlateLines = !value; + debugPlateCorners = !value; + debugCharSegmenter = !value; + debugCharAnalysis = !value; + debugColorFiler = !value; + debugOcr = !value; + debugPostProcess = !value; + debugPauseOnFrame = !value; } diff --git a/src/openalpr/config.h b/src/openalpr/config.h index aad1588..2a1105c 100644 --- a/src/openalpr/config.h +++ b/src/openalpr/config.h @@ -119,7 +119,7 @@ namespace alpr bool debugShowImages; bool debugPauseOnFrame; - void debugOff(); + void debugOff(bool value); std::string getKeypointsRuntimeDir(); std::string getCascadeRuntimeDir(); From 14db7fb6e62c75ac8474c1ee60ff1461f775500e Mon Sep 17 00:00:00 2001 From: Peter Rekdal Sunde Date: Wed, 8 Jul 2015 13:04:08 +0200 Subject: [PATCH 02/10] Add preprocessor definition: WINDOWS --- src/bindings/csharp/openalpr-net/openalpr-net.vcxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bindings/csharp/openalpr-net/openalpr-net.vcxproj b/src/bindings/csharp/openalpr-net/openalpr-net.vcxproj index 652721c..e8d5fde 100644 --- a/src/bindings/csharp/openalpr-net/openalpr-net.vcxproj +++ b/src/bindings/csharp/openalpr-net/openalpr-net.vcxproj @@ -93,7 +93,7 @@ Level3 Disabled - WIN32;_DEBUG;%(PreprocessorDefinitions) + WIN32;_DEBUG;WINDOWS;%(PreprocessorDefinitions) Use $(OpenALPRWindowsDir)\tesseract-ocr\src\api;$(OpenALPRWindowsDir)\tesseract-ocr\src\ccstruct;$(OpenALPRWindowsDir)\tesseract-ocr\src\ccmain;$(OpenALPRWindowsDir)\tesseract-ocr\src\ccutil;$(OpenALPRWindowsDir)\opencv;$(OpenALPRWindowsDir)\opencv\include;$(OpenALPRWindowsDir)\opencv\include\opencv;$(OpenALPRWindowsDir)\opencv\modules\core\include;$(OpenALPRWindowsDir)\opencv\modules\flann\include;$(OpenALPRWindowsDir)\opencv\modules\imgproc\include;$(OpenALPRWindowsDir)\opencv\modules\highgui\include;$(OpenALPRWindowsDir)\opencv\modules\features2d\include;$(OpenALPRWindowsDir)\opencv\modules\calib3d\include;$(OpenALPRWindowsDir)\opencv\modules\ml\include;$(OpenALPRWindowsDir)\opencv\modules\video\include;$(OpenALPRWindowsDir)\opencv\modules\legacy\include;$(OpenALPRWindowsDir)\opencv\modules\objdetect\include;$(OpenALPRWindowsDir)\opencv\modules\photo\include;$(OpenALPRWindowsDir)\opencv\modules\gpu\include;$(OpenALPRWindowsDir)\opencv\modules\ocl\include;$(OpenALPRWindowsDir)\opencv\modules\nonfree\include;$(OpenALPRWindowsDir)\opencv\modules\contrib\include;$(OpenALPRWindowsDir)\opencv\modules\stitching\include;$(OpenALPRWindowsDir)\opencv\modules\superres\include;$(OpenALPRWindowsDir)\opencv\modules\ts\include;$(OpenALPRWindowsDir)\opencv\modules\videostab\include;$(OpenALPRWindowsDir)\..\src\openalpr;%(AdditionalIncludeDirectories) @@ -106,7 +106,7 @@ Level3 Disabled - WIN32;_DEBUG;%(PreprocessorDefinitions) + WIN32;_DEBUG;WINDOWS;%(PreprocessorDefinitions) Use $(OpenALPRWindowsDir)\tesseract-ocr\src\api;$(OpenALPRWindowsDir)\tesseract-ocr\src\ccstruct;$(OpenALPRWindowsDir)\tesseract-ocr\src\ccmain;$(OpenALPRWindowsDir)\tesseract-ocr\src\ccutil;$(OpenALPRWindowsDir)\opencv;$(OpenALPRWindowsDir)\opencv\include;$(OpenALPRWindowsDir)\opencv\include\opencv;$(OpenALPRWindowsDir)\opencv\modules\core\include;$(OpenALPRWindowsDir)\opencv\modules\flann\include;$(OpenALPRWindowsDir)\opencv\modules\imgproc\include;$(OpenALPRWindowsDir)\opencv\modules\highgui\include;$(OpenALPRWindowsDir)\opencv\modules\features2d\include;$(OpenALPRWindowsDir)\opencv\modules\calib3d\include;$(OpenALPRWindowsDir)\opencv\modules\ml\include;$(OpenALPRWindowsDir)\opencv\modules\video\include;$(OpenALPRWindowsDir)\opencv\modules\legacy\include;$(OpenALPRWindowsDir)\opencv\modules\objdetect\include;$(OpenALPRWindowsDir)\opencv\modules\photo\include;$(OpenALPRWindowsDir)\opencv\modules\gpu\include;$(OpenALPRWindowsDir)\opencv\modules\ocl\include;$(OpenALPRWindowsDir)\opencv\modules\nonfree\include;$(OpenALPRWindowsDir)\opencv\modules\contrib\include;$(OpenALPRWindowsDir)\opencv\modules\stitching\include;$(OpenALPRWindowsDir)\opencv\modules\superres\include;$(OpenALPRWindowsDir)\opencv\modules\ts\include;$(OpenALPRWindowsDir)\opencv\modules\videostab\include;$(OpenALPRWindowsDir)\..\src\openalpr;%(AdditionalIncludeDirectories) @@ -118,7 +118,7 @@ Level3 - WIN32;NDEBUG;%(PreprocessorDefinitions) + WIN32;NDEBUG;WINDOWS;%(PreprocessorDefinitions) Use $(OpenALPRWindowsDir)\tesseract-ocr\src\api;$(OpenALPRWindowsDir)\tesseract-ocr\src\ccstruct;$(OpenALPRWindowsDir)\tesseract-ocr\src\ccmain;$(OpenALPRWindowsDir)\tesseract-ocr\src\ccutil;$(OpenALPRWindowsDir)\opencv;$(OpenALPRWindowsDir)\opencv\include;$(OpenALPRWindowsDir)\opencv\include\opencv;$(OpenALPRWindowsDir)\opencv\modules\core\include;$(OpenALPRWindowsDir)\opencv\modules\flann\include;$(OpenALPRWindowsDir)\opencv\modules\imgproc\include;$(OpenALPRWindowsDir)\opencv\modules\highgui\include;$(OpenALPRWindowsDir)\opencv\modules\features2d\include;$(OpenALPRWindowsDir)\opencv\modules\calib3d\include;$(OpenALPRWindowsDir)\opencv\modules\ml\include;$(OpenALPRWindowsDir)\opencv\modules\video\include;$(OpenALPRWindowsDir)\opencv\modules\legacy\include;$(OpenALPRWindowsDir)\opencv\modules\objdetect\include;$(OpenALPRWindowsDir)\opencv\modules\photo\include;$(OpenALPRWindowsDir)\opencv\modules\gpu\include;$(OpenALPRWindowsDir)\opencv\modules\ocl\include;$(OpenALPRWindowsDir)\opencv\modules\nonfree\include;$(OpenALPRWindowsDir)\opencv\modules\contrib\include;$(OpenALPRWindowsDir)\opencv\modules\stitching\include;$(OpenALPRWindowsDir)\opencv\modules\superres\include;$(OpenALPRWindowsDir)\opencv\modules\ts\include;$(OpenALPRWindowsDir)\opencv\modules\videostab\include;$(OpenALPRWindowsDir)\..\src\openalpr;%(AdditionalIncludeDirectories) @@ -130,7 +130,7 @@ Level3 - WIN32;NDEBUG;%(PreprocessorDefinitions) + WIN32;NDEBUG;WINDOWS;%(PreprocessorDefinitions) Use $(OpenALPRWindowsDir)\tesseract-ocr\src\api;$(OpenALPRWindowsDir)\tesseract-ocr\src\ccstruct;$(OpenALPRWindowsDir)\tesseract-ocr\src\ccmain;$(OpenALPRWindowsDir)\tesseract-ocr\src\ccutil;$(OpenALPRWindowsDir)\opencv;$(OpenALPRWindowsDir)\opencv\include;$(OpenALPRWindowsDir)\opencv\include\opencv;$(OpenALPRWindowsDir)\opencv\modules\core\include;$(OpenALPRWindowsDir)\opencv\modules\flann\include;$(OpenALPRWindowsDir)\opencv\modules\imgproc\include;$(OpenALPRWindowsDir)\opencv\modules\highgui\include;$(OpenALPRWindowsDir)\opencv\modules\features2d\include;$(OpenALPRWindowsDir)\opencv\modules\calib3d\include;$(OpenALPRWindowsDir)\opencv\modules\ml\include;$(OpenALPRWindowsDir)\opencv\modules\video\include;$(OpenALPRWindowsDir)\opencv\modules\legacy\include;$(OpenALPRWindowsDir)\opencv\modules\objdetect\include;$(OpenALPRWindowsDir)\opencv\modules\photo\include;$(OpenALPRWindowsDir)\opencv\modules\gpu\include;$(OpenALPRWindowsDir)\opencv\modules\ocl\include;$(OpenALPRWindowsDir)\opencv\modules\nonfree\include;$(OpenALPRWindowsDir)\opencv\modules\contrib\include;$(OpenALPRWindowsDir)\opencv\modules\stitching\include;$(OpenALPRWindowsDir)\opencv\modules\superres\include;$(OpenALPRWindowsDir)\opencv\modules\ts\include;$(OpenALPRWindowsDir)\opencv\modules\videostab\include;$(OpenALPRWindowsDir)\..\src\openalpr;%(AdditionalIncludeDirectories) From d3b3fb08f19cc5c711f20ee9f335d62e52dd85da Mon Sep 17 00:00:00 2001 From: Peter Rekdal Sunde Date: Wed, 8 Jul 2015 13:05:08 +0200 Subject: [PATCH 03/10] Properly implement IDisposable. --- .../csharp/openalpr-net/openalpr-net.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/bindings/csharp/openalpr-net/openalpr-net.cpp b/src/bindings/csharp/openalpr-net/openalpr-net.cpp index 17ea868..a5c8fb8 100644 --- a/src/bindings/csharp/openalpr-net/openalpr-net.cpp +++ b/src/bindings/csharp/openalpr-net/openalpr-net.cpp @@ -984,7 +984,7 @@ namespace openalprnet { bool m_cancel; }; - public ref class AlprNet sealed + public ref class AlprNet sealed : IDisposable { public: // Allocate the native object on the C++ Heap via a constructor @@ -993,11 +993,16 @@ namespace openalprnet { this->m_config = gcnew AlprConfigNet(this->m_Impl->getConfig()); } - // Deallocate the native object on a destructor - ~AlprNet(){ - delete m_Impl; - } + ~AlprNet() { + if(this->m_Disposed) + { + return; + } + this->!AlprNet(); + this->m_Disposed = true; + } + property AlprConfigNet^ Configuration { AlprConfigNet^ get() { @@ -1128,5 +1133,6 @@ namespace openalprnet { int m_topN; bool m_detectRegion; System::String^ m_defaultRegion; + bool m_Disposed; }; } From 0490bf9127ec7f3586481cfb11bada36acf77855 Mon Sep 17 00:00:00 2001 From: Peter Rekdal Sunde Date: Wed, 8 Jul 2015 13:06:46 +0200 Subject: [PATCH 04/10] Add marshalling support for Bitmap, Rectangle and MemoryStream. --- .../csharp/openalpr-net/openalpr-net.cpp | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/src/bindings/csharp/openalpr-net/openalpr-net.cpp b/src/bindings/csharp/openalpr-net/openalpr-net.cpp index a5c8fb8..8a1bafa 100644 --- a/src/bindings/csharp/openalpr-net/openalpr-net.cpp +++ b/src/bindings/csharp/openalpr-net/openalpr-net.cpp @@ -35,6 +35,8 @@ using namespace msclr::interop; using namespace System::Collections::Generic; using namespace System::Runtime::InteropServices; using namespace System::Drawing; +using namespace System::Drawing::Imaging; +using namespace System::IO; using namespace alpr; namespace openalprnet { @@ -42,6 +44,7 @@ namespace openalprnet { private ref class AlprHelper sealed { public: + static std::vector ToVector(array^ src) { std::vector result(src->Length); @@ -51,6 +54,94 @@ namespace openalprnet { return result; } + static cv::Mat BitmapToMat(Bitmap^ bitmap) + { + int channels = 0; + + switch(bitmap->PixelFormat) + { + case PixelFormat::Format8bppIndexed: + case PixelFormat::Format1bppIndexed: + channels = 1; + break; + case PixelFormat::Format24bppRgb: + channels = 3; + break; + case PixelFormat::Format32bppRgb: + case PixelFormat::Format32bppArgb: + case PixelFormat::Format32bppPArgb: + channels = 4; + break; + default: + throw gcnew NotImplementedException(); + } + + BitmapData^ bitmapData = bitmap->LockBits( + System::Drawing::Rectangle(0, 0, bitmap->Width, bitmap->Height), + ImageLockMode::ReadOnly, + bitmap->PixelFormat + ); + + cv::Mat dstMat(cv::Size(bitmap->Width, bitmap->Height), CV_8UC(channels), reinterpret_cast(bitmapData->Scan0.ToPointer())); + + bitmap->UnlockBits(bitmapData); + + return dstMat; + } + + static Bitmap^ MatToBitmap(cv::Mat mat) + { + const int width = mat.size().width; + const int height = mat.size().height; + const int channels = mat.channels(); + const int totalSize = mat.total(); + void* data = reinterpret_cast(mat.data); + Bitmap ^bitmap; + + if (channels == 1) + { + bitmap = gcnew Bitmap(width, height, PixelFormat::Format8bppIndexed); + + ColorPalette ^palette = bitmap->Palette; + for (int i = 0; i < 256; i++) + { + palette->Entries[i] = Color::FromArgb(i, i, i); + } + + bitmap->Palette = palette; + } + else + { + bitmap = gcnew Bitmap(width, height, PixelFormat::Format24bppRgb); + } + + System::Drawing::Imaging::BitmapData ^bitmapData = bitmap->LockBits( + System::Drawing::Rectangle(0, 0, bitmap->Width, bitmap->Height), + System::Drawing::Imaging::ImageLockMode::ReadWrite, + bitmap->PixelFormat + ); + + ::memcpy(bitmapData->Scan0.ToPointer(), data, totalSize); + + bitmap->UnlockBits(bitmapData); + + return bitmap; + } + + static MemoryStream^ BitmapToMemoryStream(Bitmap^ bitmap, ImageFormat^ imageFormat) + { + MemoryStream^ ms = gcnew System::IO::MemoryStream(); + bitmap->Save(ms, imageFormat); + return ms; + } + + static std::vector MemoryStreamToVector(MemoryStream^ ms) + { + unsigned char* byteArray = ToCharPtr(ms->ToArray()); + std::vector result(byteArray, byteArray + ms->Length); + return result; + } + static std::vector ToVector(List^ src) { std::vector result; @@ -88,6 +179,12 @@ namespace openalprnet { } return std::string(); } + + static System::Drawing::Rectangle ToRectangle(cv::Rect rect) + { + return System::Drawing::Rectangle(rect.x, rect.y, rect.width, rect.height); + } + }; public enum class AlprDetectorTypeNet : int { From 349df763c0bbe5f225933ee900ac3ecc0ddf1e04 Mon Sep 17 00:00:00 2001 From: Peter Rekdal Sunde Date: Wed, 8 Jul 2015 13:07:32 +0200 Subject: [PATCH 05/10] Add motion detector. --- .../csharp/openalpr-net/openalpr-net.cpp | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/src/bindings/csharp/openalpr-net/openalpr-net.cpp b/src/bindings/csharp/openalpr-net/openalpr-net.cpp index 8a1bafa..2a7c21f 100644 --- a/src/bindings/csharp/openalpr-net/openalpr-net.cpp +++ b/src/bindings/csharp/openalpr-net/openalpr-net.cpp @@ -20,6 +20,7 @@ #include "openalpr-net.h" #include "alpr.h" #include "config.h" // alpr +#include "motiondetector.h" // alpr #include #include #include @@ -187,6 +188,89 @@ namespace openalprnet { }; + public enum class OpenCVMatType { + Unchanged = CV_LOAD_IMAGE_UNCHANGED, + Grayscale = CV_LOAD_IMAGE_GRAYSCALE, + Color = CV_LOAD_IMAGE_COLOR, + AnyDepth = CV_LOAD_IMAGE_ANYDEPTH, + AnyColor = CV_LOAD_IMAGE_ANYCOLOR + }; + + public ref class AlprMotionDetectionNet : IDisposable { + public: + AlprMotionDetectionNet() + { + m_motionDetector = new MotionDetector(); + } + + void ResetMotionDetection(Bitmap^ bitmap) + { + ResetMotionDetection(Mat(bitmap)); + } + + void ResetMotionDetection(String^ filename, OpenCVMatType matType) + { + return ResetMotionDetection(Mat(filename, matType)); + } + + System::Drawing::Rectangle MotionDetect(Bitmap^ bitmap) + { + return MotionDetect(Mat(bitmap)); + } + + System::Drawing::Rectangle MotionDetect(String^ filename, OpenCVMatType matType) + { + return MotionDetect(Mat(filename, matType)); + } + + private: + void ResetMotionDetection(cv::Mat mat) + { + this->m_motionDetector->ResetMotionDetection(&mat); + } + + System::Drawing::Rectangle MotionDetect(cv::Mat mat) + { + cv::Rect rect = this->m_motionDetector->MotionDetect(&mat); + return AlprHelper::ToRectangle(rect); + } + + cv::Mat Mat(String^ filename, OpenCVMatType matType) + { + cv::Mat mat = cv::imread(AlprHelper::ToStlString(filename), static_cast(matType)); + return mat; + } + + cv::Mat Mat(Bitmap^ bitmap) + { + cv::Mat mat = AlprHelper::BitmapToMat(bitmap); + return mat; + } + + private: + + ~AlprMotionDetectionNet() + { + if(this->m_Disposed) + { + return; + } + + this->!AlprMotionDetectionNet(); + this->m_Disposed = true; + } + + !AlprMotionDetectionNet() + { + delete m_motionDetector; + } + + private: + MotionDetector* m_motionDetector; + bool m_Disposed; + }; + + public enum class AlprDetectorTypeNet : int { DetectorLbpCpu = alpr::DETECTOR_LBP_CPU, DetectorLbpGpu = alpr::DETECTOR_LBP_GPU, From 97c198e55a6e08be15d2a763ca76e999af27a5d0 Mon Sep 17 00:00:00 2001 From: Peter Rekdal Sunde Date: Wed, 8 Jul 2015 13:10:08 +0200 Subject: [PATCH 06/10] Add method overloads for recognize (Bitmap & MemoryStream). --- .../csharp/openalpr-net/openalpr-net.cpp | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/bindings/csharp/openalpr-net/openalpr-net.cpp b/src/bindings/csharp/openalpr-net/openalpr-net.cpp index 2a7c21f..9325579 100644 --- a/src/bindings/csharp/openalpr-net/openalpr-net.cpp +++ b/src/bindings/csharp/openalpr-net/openalpr-net.cpp @@ -1269,6 +1269,35 @@ namespace openalprnet { 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 ); + /// + /// Recognize from a bitmap + /// + AlprResultsNet^ recognize(Bitmap^ bitmap, List^ regionsOfInterest) + { + cv::Mat frame = AlprHelper::BitmapToMat(bitmap); + std::vector rois = AlprHelper::ToVector(regionsOfInterest); + AlprResults results = m_Impl->recognize(frame.data, frame.elemSize(), frame.cols, frame.rows, rois); + return gcnew AlprResultsNet(results); + } + + /// + /// Recognize from a bitmap + /// + AlprResultsNet^ recognize(Bitmap^ bitmap) + { + 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); + } + + /// + /// Recognize from MemoryStream representing an encoded image (e.g., BMP, PNG, JPG, GIF etc). + /// + AlprResultsNet^ recognize(MemoryStream^ memoryStream) + { + std::vector p = AlprHelper::MemoryStreamToVector(memoryStream); + AlprResults results = m_Impl->recognize(p); return gcnew AlprResultsNet(results); } From 998cd4775d7318556cb205f20bd66da1679639c6 Mon Sep 17 00:00:00 2001 From: Peter Rekdal Sunde Date: Wed, 8 Jul 2015 13:14:18 +0200 Subject: [PATCH 07/10] Damn you CRLF. --- src/bindings/csharp/openalpr-net/openalpr-net.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bindings/csharp/openalpr-net/openalpr-net.cpp b/src/bindings/csharp/openalpr-net/openalpr-net.cpp index 9325579..7f31828 100644 --- a/src/bindings/csharp/openalpr-net/openalpr-net.cpp +++ b/src/bindings/csharp/openalpr-net/openalpr-net.cpp @@ -1269,6 +1269,9 @@ namespace openalprnet { 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 ); + return gcnew AlprResultsNet(results); + } + /// /// Recognize from a bitmap /// From f38f487507f334e2b00b20b3cb0c1742eec587a4 Mon Sep 17 00:00:00 2001 From: Peter Rekdal Sunde Date: Wed, 8 Jul 2015 13:15:07 +0200 Subject: [PATCH 08/10] Add missing reference to openalprnet.cli --- src/bindings/csharp/openalprnet-cli/openalprnet-cli.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bindings/csharp/openalprnet-cli/openalprnet-cli.csproj b/src/bindings/csharp/openalprnet-cli/openalprnet-cli.csproj index 7e30a53..c193a24 100644 --- a/src/bindings/csharp/openalprnet-cli/openalprnet-cli.csproj +++ b/src/bindings/csharp/openalprnet-cli/openalprnet-cli.csproj @@ -67,6 +67,7 @@ + From cf3a536bb8c74193fc3ee63f2e1baa9256128f4c Mon Sep 17 00:00:00 2001 From: Peter Rekdal Sunde Date: Wed, 8 Jul 2015 13:19:12 +0200 Subject: [PATCH 09/10] Bugfix: must be in global configuration. --- src/bindings/csharp/openalpr-net/openalpr-net.vcxproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bindings/csharp/openalpr-net/openalpr-net.vcxproj b/src/bindings/csharp/openalpr-net/openalpr-net.vcxproj index e8d5fde..e80ce8d 100644 --- a/src/bindings/csharp/openalpr-net/openalpr-net.vcxproj +++ b/src/bindings/csharp/openalpr-net/openalpr-net.vcxproj @@ -24,6 +24,7 @@ ManagedCProj openalprnet 2.0.1 + v120 ..\..\..\..\windows $(OpenALPRWindowsDir)\build\dist\$(OpenALPRVersion)\$(PlatformToolset)\$(Configuration)\$(Platform) 248 From 1cd6cdf269822048b468c15641cabae1b15bd351 Mon Sep 17 00:00:00 2001 From: Peter Rekdal Sunde Date: Wed, 8 Jul 2015 13:20:46 +0200 Subject: [PATCH 10/10] Bugfix: Incorrect version. --- src/bindings/csharp/openalpr-net/openalpr-net.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bindings/csharp/openalpr-net/openalpr-net.vcxproj b/src/bindings/csharp/openalpr-net/openalpr-net.vcxproj index e80ce8d..2734299 100644 --- a/src/bindings/csharp/openalpr-net/openalpr-net.vcxproj +++ b/src/bindings/csharp/openalpr-net/openalpr-net.vcxproj @@ -23,7 +23,7 @@ v4.0 ManagedCProj openalprnet - 2.0.1 + 2.1.0 v120 ..\..\..\..\windows $(OpenALPRWindowsDir)\build\dist\$(OpenALPRVersion)\$(PlatformToolset)\$(Configuration)\$(Platform)