diff --git a/openalpr-net/AssemblyInfo.cpp b/openalpr-net/AssemblyInfo.cpp new file mode 100644 index 0000000..61560b3 --- /dev/null +++ b/openalpr-net/AssemblyInfo.cpp @@ -0,0 +1,40 @@ +#include "stdafx.h" + +using namespace System; +using namespace System::Reflection; +using namespace System::Runtime::CompilerServices; +using namespace System::Runtime::InteropServices; +using namespace System::Security::Permissions; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly:AssemblyTitleAttribute("openalprnet")]; +[assembly:AssemblyDescriptionAttribute("")]; +[assembly:AssemblyConfigurationAttribute("")]; +[assembly:AssemblyCompanyAttribute("")]; +[assembly:AssemblyProductAttribute("openalprnet")]; +[assembly:AssemblyCopyrightAttribute("Copyright (c) 2015")]; +[assembly:AssemblyTrademarkAttribute("")]; +[assembly:AssemblyCultureAttribute("")]; + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the value or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly:AssemblyVersionAttribute("1.0.*")]; + +[assembly:ComVisible(false)]; + +[assembly:CLSCompliantAttribute(true)]; + +[assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)]; diff --git a/openalpr-net/Stdafx.cpp b/openalpr-net/Stdafx.cpp new file mode 100644 index 0000000..144c129 --- /dev/null +++ b/openalpr-net/Stdafx.cpp @@ -0,0 +1,5 @@ +// stdafx.cpp : source file that includes just the standard includes +// openalpr-net.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" diff --git a/openalpr-net/Stdafx.h b/openalpr-net/Stdafx.h new file mode 100644 index 0000000..3cc4c24 --- /dev/null +++ b/openalpr-net/Stdafx.h @@ -0,0 +1,7 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, +// but are changed infrequently + +#pragma once + + diff --git a/openalpr-net/app.ico b/openalpr-net/app.ico new file mode 100644 index 0000000..3a5525f Binary files /dev/null and b/openalpr-net/app.ico differ diff --git a/openalpr-net/app.rc b/openalpr-net/app.rc new file mode 100644 index 0000000..eab4306 Binary files /dev/null and b/openalpr-net/app.rc differ diff --git a/openalpr-net/openalpr-net.cpp b/openalpr-net/openalpr-net.cpp new file mode 100644 index 0000000..3c6dc23 --- /dev/null +++ b/openalpr-net/openalpr-net.cpp @@ -0,0 +1,290 @@ +/* +* Copyright (c) 2015 Dr. Masroor Ehsan +* +* This file is part of OpenAlpr.Net. +* +* OpenAlpr.Net is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License +* version 3 as published by the Free Software Foundation +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +#include "stdafx.h" +#include "openalpr-net.h" +#include "alpr.h" +#include +#include +#include +#using +//#include +#include + +using namespace System; +using namespace msclr::interop; +using namespace System::Collections::Generic; +using namespace System::Runtime::InteropServices; +using namespace System::Drawing; + +namespace openalprnet { + + private ref class AlprHelper sealed + { + public: + static std::vector ToVector(array^ src) + { + std::vector result(src->Length); + pin_ptr pin(&src[0]); + unsigned char *first(pin), *last(pin + src->Length); + std::copy(first, last, result.begin()); + return result; + } + + static std::vector ToVector(List^ src) + { + std::vector result; + + for each(System::Drawing::Rectangle^ rect in src) + { + AlprRegionOfInterest roi; + roi.x = rect->X; + roi.y = rect->Y; + roi.height = rect->Height; + roi.width = rect->Width; + result.push_back(roi); + } + + return result; + } + + static System::String^ ToManagedString(std::string s) + { + return gcnew String(s.c_str()); + } + + static std::string ToStlString(System::String^ s) + { + IntPtr ptr = Marshal::StringToHGlobalAnsi(s); + if(ptr != IntPtr::Zero) + { + std::string tmp(reinterpret_cast(static_cast(ptr))); + Marshal::FreeHGlobal(ptr); + return tmp; + } + return std::string(); + } + }; + + public ref class AlprPlateNet sealed + { + public: + AlprPlateNet(AlprPlate plate){ + //_characters = marshal_as(plate.characters); + m_characters = AlprHelper::ToManagedString(plate.characters); + m_overall_confidence=plate.overall_confidence; + m_matches_template=plate.matches_template; + } + + property System::String^ characters { + System::String^ get() { + return m_characters; + } + } + + property float overall_confidence { + float get() { + return m_overall_confidence; + } + } + + property bool matches_template { + bool get() { + return m_matches_template; + } + } + + private: + System::String^ m_characters; + float m_overall_confidence; + bool m_matches_template; + }; + + public ref class AlprResultNet sealed + { + public: + AlprResultNet() : m_Impl( new AlprResult ) {} + + AlprResultNet(AlprResult* result) : m_Impl( result ) {} + + property int requested_topn { + int get() { + return m_Impl->requested_topn; + } + } + + property int regionConfidence { + int get() { + return m_Impl->regionConfidence; + } + } + + property System::String^ region { + System::String^ get() { + return AlprHelper::ToManagedString(m_Impl->region); + } + } + + property int result_count { + int get() { + return m_Impl->result_count; + } + } + + property AlprPlateNet^ bestPlate { + AlprPlateNet^ get() { + AlprPlateNet^ result = gcnew AlprPlateNet(m_Impl->bestPlate); + return result; + } + } + + property List^ plate_points { + List^ get() { + List^ list = gcnew List(4); + for (int i = 0; i < 4; i++) + { + list->Add(System::Drawing::Point(m_Impl->plate_points[i].x, m_Impl->plate_points[i].y)); + } + return list; + } + } + + property List^ topNPlates { + List^ get() { + List^ list = gcnew List(m_Impl->topNPlates.size()); + for (std::vector::iterator itr = m_Impl->topNPlates.begin(); itr != m_Impl->topNPlates.end(); itr++) + { + list->Add(gcnew AlprPlateNet(*itr)); + } + return list; + } + } + + property float processing_time_ms { + float get() { + return m_Impl->processing_time_ms; + } + } + + private: + AlprResult * m_Impl; + }; + + public ref class AlprNet sealed + { + public: + // Allocate the native object on the C++ Heap via a constructor + AlprNet(System::String^ country, System::String^ configFile) : m_Impl( new Alpr(marshal_as(country), marshal_as(configFile)) ) { } + + // Deallocate the native object on a destructor + ~AlprNet(){ + delete m_Impl; + } + + property int TopN { + int get() { + return m_topN; + } + void set( int topn ){ + m_topN = topn; + m_Impl->setTopN(topn); + } + } + + property bool DetectRegion { + bool get() { + return m_detectRegion; + } + void set( bool detectRegion ) { + m_detectRegion = detectRegion; + m_Impl->setDetectRegion(detectRegion); + } + } + + property System::String^ DefaultRegion { + System::String^ get() { + return m_defaultRegion; + } + void set( System::String^ region ){ + m_defaultRegion = region; + m_Impl->setDefaultRegion(marshal_as(region)); + } + } + + List^ recognize(System::String^ filepath) { + m_results = new std::vector(m_Impl->recognize(marshal_as(filepath))); + return this->processResults(); + } + + List^ recognize(System::String^ filepath, List^ regionsOfInterest) { + std::vector rois = AlprHelper::ToVector(regionsOfInterest); + m_results = new std::vector(m_Impl->recognize(marshal_as(filepath), rois)); + return this->processResults(); + } + + List^ recognize(cli::array^ imageBuffer) { + std::vector p = AlprHelper::ToVector(imageBuffer); + m_results = new std::vector(m_Impl->recognize(p)); + return this->processResults(); + } + + List^ recognize(cli::array^ imageBuffer, List^ regionsOfInterest) { + std::vector rois = AlprHelper::ToVector(regionsOfInterest); + std::vector p = AlprHelper::ToVector(imageBuffer); + m_results = new std::vector(m_Impl->recognize(p, rois)); + return this->processResults(); + } + + bool isLoaded() { + return m_Impl->isLoaded(); + } + + static System::String^ getVersion() { + return AlprHelper::ToManagedString(Alpr::getVersion()); + } + + System::String^ toJson() { + std::string json = m_Impl->toJson(*m_results, -1); + return AlprHelper::ToManagedString(json); + } + + protected: + // Deallocate the native object on the finalizer just in case no destructor is called + !AlprNet() { + delete m_Impl; + } + + private: + Alpr * m_Impl; + std::vector* m_results; + int m_topN; + bool m_detectRegion; + System::String^ m_defaultRegion; + + List^ processResults() { + std::vector& runList = *m_results; + std::vector::iterator itr; + List^ list = gcnew List(runList.size()); + for (itr = runList.begin(); itr != runList.end(); itr++) + { + list->Add(gcnew AlprResultNet(&*itr)); + } + return list; + } + }; +} \ No newline at end of file diff --git a/openalpr-net/openalpr-net.h b/openalpr-net/openalpr-net.h new file mode 100644 index 0000000..e56ad27 --- /dev/null +++ b/openalpr-net/openalpr-net.h @@ -0,0 +1,9 @@ +// openalpr-net.h + +#pragma once + +//using namespace System; + +namespace openalprnet { + +} diff --git a/openalpr-net/openalpr-net.vcxproj b/openalpr-net/openalpr-net.vcxproj new file mode 100644 index 0000000..5f37063 --- /dev/null +++ b/openalpr-net/openalpr-net.vcxproj @@ -0,0 +1,102 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {4044340C-C435-4A1F-8F12-0806C38AE3B6} + v4.0 + ManagedCProj + openalprnet + + + + DynamicLibrary + true + true + Unicode + + + DynamicLibrary + false + true + Unicode + false + + + + + + + + + + + + + true + + + false + + + + Level3 + Disabled + WIN32;_DEBUG;%(PreprocessorDefinitions) + Use + + + true + + + + + + + Level3 + WIN32;NDEBUG;%(PreprocessorDefinitions) + Use + C:\projects\openalpr\libraries\tesseract-ocr\api;C:\projects\openalpr\libraries\tesseract-ocr\ccstruct;C:\projects\openalpr\libraries\tesseract-ocr\ccmain;C:\projects\openalpr\libraries\tesseract-ocr\ccutil;C:\projects\openalpr\libraries\opencv;C:\projects\openalpr\libraries\opencv\include;C:\projects\openalpr\libraries\opencv\include\opencv;C:\projects\openalpr\libraries\opencv\modules\core\include;C:\projects\openalpr\libraries\opencv\modules\flann\include;C:\projects\openalpr\libraries\opencv\modules\imgproc\include;C:\projects\openalpr\libraries\opencv\modules\highgui\include;C:\projects\openalpr\libraries\opencv\modules\features2d\include;C:\projects\openalpr\libraries\opencv\modules\calib3d\include;C:\projects\openalpr\libraries\opencv\modules\ml\include;C:\projects\openalpr\libraries\opencv\modules\video\include;C:\projects\openalpr\libraries\opencv\modules\legacy\include;C:\projects\openalpr\libraries\opencv\modules\objdetect\include;C:\projects\openalpr\libraries\opencv\modules\photo\include;C:\projects\openalpr\libraries\opencv\modules\gpu\include;C:\projects\openalpr\libraries\opencv\modules\ocl\include;C:\projects\openalpr\libraries\opencv\modules\nonfree\include;C:\projects\openalpr\libraries\opencv\modules\contrib\include;C:\projects\openalpr\libraries\opencv\modules\stitching\include;C:\projects\openalpr\libraries\opencv\modules\superres\include;C:\projects\openalpr\libraries\opencv\modules\ts\include;C:\projects\openalpr\libraries\opencv\modules\videostab\include;C:\projects\openalpr\src\openalpr;%(AdditionalIncludeDirectories) + + + true + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;C:\projects\openalpr\libraries\opencv\lib\Release\opencv_videostab248.lib;C:\projects\openalpr\libraries\opencv\lib\Release\opencv_ts248.lib;C:\projects\openalpr\libraries\opencv\lib\Release\opencv_superres248.lib;C:\projects\openalpr\libraries\opencv\lib\Release\opencv_stitching248.lib;C:\projects\openalpr\libraries\opencv\lib\Release\opencv_contrib248.lib;C:\projects\openalpr\libraries\tesseract-ocr\vs2010\LIB_Release\libtesseract303-static.lib;C:\projects\openalpr\libraries\tesseract-ocr\vs2010\LIB_Release\liblept170.lib;ws2_32.lib;C:\projects\openalpr\libraries\opencv\lib\Release\opencv_nonfree248.lib;C:\projects\openalpr\libraries\opencv\lib\Release\opencv_ocl248.lib;C:\projects\openalpr\libraries\opencv\lib\Release\opencv_gpu248.lib;C:\projects\openalpr\libraries\opencv\lib\Release\opencv_photo248.lib;C:\projects\openalpr\libraries\opencv\lib\Release\opencv_objdetect248.lib;C:\projects\openalpr\libraries\opencv\lib\Release\opencv_legacy248.lib;C:\projects\openalpr\libraries\opencv\lib\Release\opencv_video248.lib;C:\projects\openalpr\libraries\opencv\lib\Release\opencv_ml248.lib;C:\projects\openalpr\libraries\opencv\lib\Release\opencv_calib3d248.lib;C:\projects\openalpr\libraries\opencv\lib\Release\opencv_features2d248.lib;C:\projects\openalpr\libraries\opencv\lib\Release\opencv_highgui248.lib;C:\projects\openalpr\libraries\opencv\lib\Release\opencv_imgproc248.lib;C:\projects\openalpr\libraries\opencv\lib\Release\opencv_flann248.lib;C:\projects\openalpr\libraries\opencv\lib\Release\opencv_core248.lib;C:\projects\openalpr\src\openalpr\support\Release\support.lib;C:\projects\openalpr\src\openalpr\Release\openalpr-static.lib + + + + + + + + + + + + + + + + + + Create + Create + + + + + + + + + + + + \ No newline at end of file diff --git a/openalpr-net/openalpr-net.vcxproj.filters b/openalpr-net/openalpr-net.vcxproj.filters new file mode 100644 index 0000000..221dbe4 --- /dev/null +++ b/openalpr-net/openalpr-net.vcxproj.filters @@ -0,0 +1,49 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/openalpr-net/openalpr-net.vcxproj.user b/openalpr-net/openalpr-net.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/openalpr-net/openalpr-net.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/openalpr-net/resource.h b/openalpr-net/resource.h new file mode 100644 index 0000000..d5ac7c4 --- /dev/null +++ b/openalpr-net/resource.h @@ -0,0 +1,3 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by app.rc diff --git a/openalprnet-cli/CommandLine.cs b/openalprnet-cli/CommandLine.cs new file mode 100644 index 0000000..c861a6b --- /dev/null +++ b/openalprnet-cli/CommandLine.cs @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015 Dr. Masroor Ehsan + * + * This file is part of OpenAlpr.Net. + * + * OpenAlpr.Net is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +namespace openalprnet_cli +{ + internal static class CommandLine + { + private const string NameGroup = "name"; // Names of capture groups + private const string ValueGroup = "value"; + /* The regex that extracts names and comma-separated values for switches + in the form ([="value 1",value2,...])+ */ + + private static readonly Regex RexPattern = + new Regex(@"(?[^=]+)=?((?\""?)(?(?(quoted)[^\""]+|[^,]+))\""?,?)*", + RegexOptions.Compiled | RegexOptions.CultureInvariant | + RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase); + + public static void Process(this string[] args, Action printUsage, params Switch[] switches) + { + /* Run through all matches in the argument list and if any of the switches + match, get the values and invoke the handler we were given. We do a Sum() + here for 2 reasons; a) To actually run the handlers + and b) see if any were invoked at all (each returns 1 if invoked). + If none were invoked, we simply invoke the printUsage handler. */ + if ((from arg in args + from Match match in RexPattern.Matches(arg) + from s in switches + where match.Success && + ((string.Compare(match.Groups[NameGroup].Value, s.Name, true) == 0) || + (string.Compare(match.Groups[NameGroup].Value, s.ShortForm, true) == 0)) + select s.InvokeHandler(match.Groups[ValueGroup].Value.Split(','))).Sum() == 0) + printUsage(); // We didn't find any switches + } + + public class Switch // Class that encapsulates switch data. + { + public Switch(string name, Action> handler, string shortForm) + { + Name = name; + Handler = handler; + ShortForm = shortForm; + } + + public Switch(string name, Action> handler) + { + Name = name; + Handler = handler; + ShortForm = null; + } + + public string Name { get; private set; } + public string ShortForm { get; private set; } + public Action> Handler { get; private set; } + + public int InvokeHandler(string[] values) + { + Handler(values); + return 1; + } + } + } +} \ No newline at end of file diff --git a/openalprnet-cli/Program.cs b/openalprnet-cli/Program.cs new file mode 100644 index 0000000..f6881e3 --- /dev/null +++ b/openalprnet-cli/Program.cs @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2015 Dr. Masroor Ehsan + * + * This file is part of OpenAlpr.Net. + * + * OpenAlpr.Net is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using openalprnet; + +namespace openalprnet_cli +{ + internal class Program + { + public static string AssemblyDirectory + { + get + { + var codeBase = Assembly.GetExecutingAssembly().CodeBase; + var uri = new UriBuilder(codeBase); + var path = Uri.UnescapeDataString(uri.Path); + return Path.GetDirectoryName(path); + } + } + + private static bool StrToBool(string s) + { + return !string.IsNullOrEmpty(s) && s.Trim() == "1"; + } + + private static void Main(string[] args) + { + var region = "us"; + var detectRegion = false; + var benchmark = false; + var json = false; + var filename = string.Empty; + + + args.Process( + () => Console.WriteLine("Usage: r=us/eu b=0/1 j=0/1 d=0/1 f="), + new CommandLine.Switch("r", + val => { if (val.Any()) region = val.First().Trim().ToLower(); }), + new CommandLine.Switch("b", + val => { if (val.Any()) benchmark = StrToBool(val.First()); }), + new CommandLine.Switch("j", + val => { if (val.Any()) json = StrToBool(val.First()); }), + new CommandLine.Switch("d", + val => { if (val.Any()) detectRegion = StrToBool(val.First()); }), + new CommandLine.Switch("f", + val => { if (val.Any()) filename = val.First().Trim(); }) + ); + + Console.WriteLine("OpenAlpr Version: {0}", AlprNet.getVersion()); + var config = Path.Combine(AssemblyDirectory, "openalpr.conf"); + var alpr = new AlprNet(region, config); + if (!alpr.isLoaded()) + { + Console.WriteLine("OpenAlpr failed to loaded!"); + return; + } + + //var samplePath = Path.Combine(AssemblyDirectory, @"samples\eu-1.jpg"); + //alpr.TopN = 3; + alpr.DefaultRegion = region; + alpr.DetectRegion = detectRegion; + + if (Directory.Exists(filename)) + { + var files = Directory.GetFiles(filename, "*.jpg", SearchOption.TopDirectoryOnly); + foreach (var fname in files) + { + PerformAlpr(alpr, fname, benchmark, json); + } + return; + } + + if (!File.Exists(filename)) + { + Console.WriteLine("The file doesn't exist!"); + return; + } + var buffer = File.ReadAllBytes(filename); + PerformAlpr(alpr, buffer, benchmark, json); + } + + private static void PerformAlpr(AlprNet alpr, string filename, bool benchmark, bool writeJson) + { + Console.WriteLine("Processing '{0}'...\n------------------", Path.GetFileName(filename)); + var buffer = File.ReadAllBytes(filename); + PerformAlpr(alpr, buffer, benchmark, writeJson); + } + + private static void PerformAlpr(AlprNet alpr, byte[] buffer, bool benchmark, bool writeJson) + { + var sw = Stopwatch.StartNew(); + var results = alpr.recognize(buffer); + sw.Stop(); + if (benchmark) + { + Console.WriteLine("Total Time to process image(s): {0} msec(s)", sw.ElapsedMilliseconds); + } + + if (writeJson) + { + Console.WriteLine(alpr.toJson()); + } + else + { + var i = 0; + foreach (var result in results) + { + Console.WriteLine("Plate {0}: {1} result(s)", i++, result.result_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); + } + } + } + } + } +} \ No newline at end of file diff --git a/openalprnet-cli/Properties/AssemblyInfo.cs b/openalprnet-cli/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..8c169b6 --- /dev/null +++ b/openalprnet-cli/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("openalprnet-cli")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("openalprnet-cli")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("42477de2-b13e-4959-a03e-ae43c65e68f3")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/openalprnet-cli/openalprnet-cli.csproj b/openalprnet-cli/openalprnet-cli.csproj new file mode 100644 index 0000000..2fb8ce5 --- /dev/null +++ b/openalprnet-cli/openalprnet-cli.csproj @@ -0,0 +1,64 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {BD50C6C1-EEB9-48D2-A87C-70F5342579DD} + Exe + Properties + openalprnet_cli + openalprnet-cli + v4.0 + Client + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + {4044340C-C435-4A1F-8F12-0806C38AE3B6} + openalpr-net + + + + + \ No newline at end of file diff --git a/openalprnet-windemo/Form1.Designer.cs b/openalprnet-windemo/Form1.Designer.cs new file mode 100644 index 0000000..56ea8e7 --- /dev/null +++ b/openalprnet-windemo/Form1.Designer.cs @@ -0,0 +1,192 @@ +namespace openalprnet_windemo +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnDetect = new System.Windows.Forms.Button(); + this.picLicensePlate = new System.Windows.Forms.PictureBox(); + this.picOriginal = new System.Windows.Forms.PictureBox(); + this.lbxPlates = new System.Windows.Forms.ListBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); + this.label4 = new System.Windows.Forms.Label(); + this.rbUSA = new System.Windows.Forms.RadioButton(); + this.rbEU = new System.Windows.Forms.RadioButton(); + ((System.ComponentModel.ISupportInitialize)(this.picLicensePlate)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.picOriginal)).BeginInit(); + this.SuspendLayout(); + // + // btnDetect + // + this.btnDetect.Location = new System.Drawing.Point(830, 25); + this.btnDetect.Name = "btnDetect"; + this.btnDetect.Size = new System.Drawing.Size(291, 37); + this.btnDetect.TabIndex = 0; + this.btnDetect.Text = "Detect License Plate"; + this.btnDetect.UseVisualStyleBackColor = true; + this.btnDetect.Click += new System.EventHandler(this.button1_Click); + // + // picLicensePlate + // + this.picLicensePlate.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.picLicensePlate.Location = new System.Drawing.Point(827, 403); + this.picLicensePlate.Name = "picLicensePlate"; + this.picLicensePlate.Size = new System.Drawing.Size(294, 123); + this.picLicensePlate.TabIndex = 1; + this.picLicensePlate.TabStop = false; + // + // picOriginal + // + this.picOriginal.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.picOriginal.Location = new System.Drawing.Point(12, 25); + this.picOriginal.Name = "picOriginal"; + this.picOriginal.Size = new System.Drawing.Size(809, 501); + this.picOriginal.TabIndex = 2; + this.picOriginal.TabStop = false; + // + // lbxPlates + // + this.lbxPlates.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lbxPlates.FormattingEnabled = true; + this.lbxPlates.Location = new System.Drawing.Point(827, 81); + this.lbxPlates.Name = "lbxPlates"; + this.lbxPlates.Size = new System.Drawing.Size(294, 303); + this.lbxPlates.TabIndex = 3; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(76, 13); + this.label1.TabIndex = 4; + this.label1.Text = "Source Image:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(827, 387); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(96, 13); + this.label2.TabIndex = 5; + this.label2.Text = "License Plate ROI:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(827, 65); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(124, 13); + this.label3.TabIndex = 6; + this.label3.Text = "Matched License Plates:"; + // + // openFileDialog + // + this.openFileDialog.Filter = "Image files (*.jpg, *.jpeg, *.jpe, *.jfif, *.png) | *.jpg; *.jpeg; *.jpe; *.jfif;" + + " *.png|All files (*.*)|*.*"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(827, 9); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(44, 13); + this.label4.TabIndex = 7; + this.label4.Text = "Region:"; + // + // rbUSA + // + this.rbUSA.AutoSize = true; + this.rbUSA.Checked = true; + this.rbUSA.Location = new System.Drawing.Point(878, 7); + this.rbUSA.Name = "rbUSA"; + this.rbUSA.Size = new System.Drawing.Size(40, 17); + this.rbUSA.TabIndex = 8; + this.rbUSA.TabStop = true; + this.rbUSA.Text = "US"; + this.rbUSA.UseVisualStyleBackColor = true; + // + // rbEU + // + this.rbEU.AutoSize = true; + this.rbEU.Location = new System.Drawing.Point(924, 7); + this.rbEU.Name = "rbEU"; + this.rbEU.Size = new System.Drawing.Size(40, 17); + this.rbEU.TabIndex = 9; + this.rbEU.Text = "EU"; + this.rbEU.UseVisualStyleBackColor = true; + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.White; + this.ClientSize = new System.Drawing.Size(1128, 538); + this.Controls.Add(this.rbEU); + this.Controls.Add(this.rbUSA); + this.Controls.Add(this.label4); + this.Controls.Add(this.label3); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Controls.Add(this.lbxPlates); + this.Controls.Add(this.picOriginal); + this.Controls.Add(this.picLicensePlate); + this.Controls.Add(this.btnDetect); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "Form1"; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "OpenALPR-Net Demo"; + this.Load += new System.EventHandler(this.Form1_Load); + ((System.ComponentModel.ISupportInitialize)(this.picLicensePlate)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.picOriginal)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button btnDetect; + private System.Windows.Forms.PictureBox picLicensePlate; + private System.Windows.Forms.PictureBox picOriginal; + private System.Windows.Forms.ListBox lbxPlates; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.OpenFileDialog openFileDialog; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.RadioButton rbUSA; + private System.Windows.Forms.RadioButton rbEU; + } +} + diff --git a/openalprnet-windemo/Form1.cs b/openalprnet-windemo/Form1.cs new file mode 100644 index 0000000..60572b4 --- /dev/null +++ b/openalprnet-windemo/Form1.cs @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2015 Dr. Masroor Ehsan + * + * This file is part of OpenAlpr.Net. + * + * OpenAlpr.Net is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Windows.Forms; +using openalprnet; + +namespace openalprnet_windemo +{ + public partial class Form1 : Form + { + public Form1() + { + InitializeComponent(); + } + + public static string AssemblyDirectory + { + get + { + var codeBase = Assembly.GetExecutingAssembly().CodeBase; + var uri = new UriBuilder(codeBase); + var path = Uri.UnescapeDataString(uri.Path); + return Path.GetDirectoryName(path); + } + } + + public Rectangle boundingRectangle(List points) + { + // Add checks here, if necessary, to make sure that points is not null, + // and that it contains at least one (or perhaps two?) elements + + var minX = points.Min(p => p.X); + var minY = points.Min(p => p.Y); + var maxX = points.Max(p => p.X); + var maxY = points.Max(p => p.Y); + + return new Rectangle(new Point(minX, minY), new Size(maxX - minX, maxY - minY)); + } + + private static Image cropImage(Image img, Rectangle cropArea) + { + var bmpImage = new Bitmap(img); + return bmpImage.Clone(cropArea, bmpImage.PixelFormat); + } + + public static Bitmap combineImages(List images) + { + //read all images into memory + Bitmap finalImage = null; + + try + { + var width = 0; + var height = 0; + + foreach (var bmp in images) + { + width += bmp.Width; + height = bmp.Height > height ? bmp.Height : height; + } + + //create a bitmap to hold the combined image + finalImage = new Bitmap(width, height); + + //get a graphics object from the image so we can draw on it + using (var g = Graphics.FromImage(finalImage)) + { + //set background color + g.Clear(Color.Black); + + //go through each image and draw it on the final image + var offset = 0; + foreach (Bitmap image in images) + { + g.DrawImage(image, + new Rectangle(offset, 0, image.Width, image.Height)); + offset += image.Width; + } + } + + return finalImage; + } + catch (Exception ex) + { + if (finalImage != null) + finalImage.Dispose(); + + throw ex; + } + finally + { + //clean up memory + foreach (var image in images) + { + image.Dispose(); + } + } + } + + private void button1_Click(object sender, EventArgs e) + { + if (openFileDialog.ShowDialog(this) == DialogResult.OK) + { + processImageFile(openFileDialog.FileName); + } + } + + + private void processImageFile(string fileName) + { + resetControls(); + var region = rbUSA.Checked ? "us" : "eu"; + using (var alpr = new AlprNet(region, Path.Combine(AssemblyDirectory, "openalpr.conf"))) + { + picOriginal.ImageLocation = fileName; + picOriginal.Load(); + + var results = alpr.recognize(fileName); + + var images = new List(results.Count()); + var i = 1; + foreach (var result in results) + { + var rect = boundingRectangle(result.plate_points); + 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) + { + 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))); + } + } + + if (images.Any()) + { + picLicensePlate.Image = combineImages(images); + } + } + } + + private void resetControls() + { + picOriginal.Image = null; + picLicensePlate.Image = null; + lbxPlates.Items.Clear(); + } + + private void Form1_Load(object sender, EventArgs e) + { + resetControls(); + } + } +} \ No newline at end of file diff --git a/openalprnet-windemo/Form1.resx b/openalprnet-windemo/Form1.resx new file mode 100644 index 0000000..a3d5a63 --- /dev/null +++ b/openalprnet-windemo/Form1.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/openalprnet-windemo/Program.cs b/openalprnet-windemo/Program.cs new file mode 100644 index 0000000..b5cd5ed --- /dev/null +++ b/openalprnet-windemo/Program.cs @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015 Dr. Masroor Ehsan + * + * This file is part of OpenAlpr.Net. + * + * OpenAlpr.Net is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; + +namespace openalprnet_windemo +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1()); + } + } +} diff --git a/openalprnet-windemo/Properties/AssemblyInfo.cs b/openalprnet-windemo/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4eccafe --- /dev/null +++ b/openalprnet-windemo/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("openalprnet-windemo")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("openalprnet-windemo")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b1ab96ca-afe9-497d-9aa0-74ace195dfca")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/openalprnet-windemo/Properties/Resources.Designer.cs b/openalprnet-windemo/Properties/Resources.Designer.cs new file mode 100644 index 0000000..5375cf1 --- /dev/null +++ b/openalprnet-windemo/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34209 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace openalprnet_windemo.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("openalprnet_windemo.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/openalprnet-windemo/Properties/Resources.resx b/openalprnet-windemo/Properties/Resources.resx new file mode 100644 index 0000000..ffecec8 --- /dev/null +++ b/openalprnet-windemo/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/openalprnet-windemo/Properties/Settings.Designer.cs b/openalprnet-windemo/Properties/Settings.Designer.cs new file mode 100644 index 0000000..b44f110 --- /dev/null +++ b/openalprnet-windemo/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34209 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace openalprnet_windemo.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/openalprnet-windemo/Properties/Settings.settings b/openalprnet-windemo/Properties/Settings.settings new file mode 100644 index 0000000..abf36c5 --- /dev/null +++ b/openalprnet-windemo/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/openalprnet-windemo/app.config b/openalprnet-windemo/app.config new file mode 100644 index 0000000..cb2586b --- /dev/null +++ b/openalprnet-windemo/app.config @@ -0,0 +1,3 @@ + + + diff --git a/openalprnet-windemo/openalprnet-windemo.csproj b/openalprnet-windemo/openalprnet-windemo.csproj new file mode 100644 index 0000000..5032e2c --- /dev/null +++ b/openalprnet-windemo/openalprnet-windemo.csproj @@ -0,0 +1,96 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {C7863A14-55D2-4389-9072-04AA6E30AAD1} + WinExe + Properties + openalprnet_windemo + openalprnet-windemo + v4.0 + + + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + Form + + + Form1.cs + + + + + Form1.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + {4044340C-C435-4A1F-8F12-0806C38AE3B6} + openalpr-net + + + + + \ No newline at end of file