From 73ea1d453feb5c5d22de5894ac791f518273ef19 Mon Sep 17 00:00:00 2001 From: tgandor Date: Tue, 2 May 2017 11:07:59 +0200 Subject: [PATCH] implemented recognize_ndarray in Python bindings (for cv2 images) --- src/CMakeLists.txt | 1 + src/bindings/python/openalpr/openalpr.py | 39 +++++++++++++++++--- src/bindings/python/openalprpy.cpp | 45 ++++++++++++++++++------ 3 files changed, 69 insertions(+), 16 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f90a8e3..51fa37b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -174,6 +174,7 @@ IF (WITH_DAEMON) daemon/beanstalk.cc ) + FIND_PACKAGE( CURL REQUIRED ) FIND_PACKAGE( log4cplus REQUIRED ) TARGET_LINK_LIBRARIES(alprd diff --git a/src/bindings/python/openalpr/openalpr.py b/src/bindings/python/openalpr/openalpr.py index 10f38be..03a192b 100644 --- a/src/bindings/python/openalpr/openalpr.py +++ b/src/bindings/python/openalpr/openalpr.py @@ -13,6 +13,7 @@ else: unicode = str _PYTHON_3 = True + def _convert_to_charp(string): # Prepares function input for use in c-functions as char* if type(string) == unicode: @@ -22,6 +23,7 @@ def _convert_to_charp(string): else: raise TypeError("Expected unicode string values or ascii/bytes values. Got: %r" % type(string)) + def _convert_from_charp(charp): # Prepares char* output from c-functions into Python strings if _PYTHON_3 and type(charp) == bytes: @@ -29,7 +31,8 @@ def _convert_from_charp(charp): else: return charp -class Alpr(): + +class Alpr: def __init__(self, country, config_file, runtime_dir): """ Initializes an OpenALPR instance in memory. @@ -43,7 +46,7 @@ class Alpr(): config_file = _convert_to_charp(config_file) runtime_dir = _convert_to_charp(runtime_dir) try: - # Load the .dll for Windows and the .so for Unix-based + # Load the .dll for Windows and the .so for Unix-based if platform.system().lower().find("windows") != -1: self._openalprpy_lib = ctypes.cdll.LoadLibrary("libopenalprpy.dll") elif platform.system().lower().find("darwin") != -1: @@ -76,6 +79,17 @@ class Alpr(): self._recognize_array_func.restype = ctypes.c_void_p self._recognize_array_func.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_ubyte), ctypes.c_uint] + try: + import numpy as np + import numpy.ctypeslib as npct + self._recognize_raw_image_func = self._openalprpy_lib.recognizeRawImage + self._recognize_raw_image_func.restype = ctypes.c_void_p + array_1_uint8 = npct.ndpointer(dtype=np.uint8, ndim=1, flags='CONTIGUOUS') + self._recognize_raw_image_func.argtypes = [ + ctypes.c_void_p, array_1_uint8, ctypes.c_uint, ctypes.c_uint, ctypes.c_uint] + except ImportError: + self._recognize_raw_image_func = None + self._free_json_mem_func = self._openalprpy_lib.freeJsonMem self._set_country_func = self._openalprpy_lib.setCountry @@ -90,7 +104,6 @@ class Alpr(): self._set_detect_region_func = self._openalprpy_lib.setDetectRegion self._set_detect_region_func.argtypes = [ctypes.c_void_p, ctypes.c_bool] - self._set_top_n_func = self._openalprpy_lib.setTopN self._set_top_n_func.argtypes = [ctypes.c_void_p, ctypes.c_int] @@ -157,6 +170,24 @@ class Alpr(): self._free_json_mem_func(ctypes.c_void_p(ptr)) return response_obj + def recognize_ndarray(self, ndarray): + """ + This causes OpenALPR to attempt to recognize an image passed in as a numpy array. + + :param ndarray: numpy.array as used in cv2 module + :return: An OpenALPR analysis in the form of a response dictionary + """ + if self._recognize_raw_image_func is None: + raise RuntimeError('NumPy missing') + height, width = ndarray.shape[:2] + bpp = ndarray.shape[2] if len(ndarray.shape) > 2 else 1 + ptr = self._recognize_raw_image_func(self.alpr_pointer, ndarray.flatten(), bpp, width, height) + json_data = ctypes.cast(ptr, ctypes.c_char_p).value + json_data = _convert_from_charp(json_data) + response_obj = json.loads(json_data) + self._free_json_mem_func(ctypes.c_void_p(ptr)) + return response_obj + def get_version(self): """ This gets the version of OpenALPR @@ -202,7 +233,6 @@ class Alpr(): prewarp = _convert_to_charp(prewarp) self._set_prewarp_func(self.alpr_pointer, prewarp) - def set_default_region(self, region): """ This sets the default region for detecting license plates. For example, @@ -224,7 +254,6 @@ class Alpr(): """ self._set_detect_region_func(self.alpr_pointer, enabled) - def __del__(self): if self.is_loaded(): self.unload() diff --git a/src/bindings/python/openalprpy.cpp b/src/bindings/python/openalprpy.cpp index aa6d365..9076146 100644 --- a/src/bindings/python/openalprpy.cpp +++ b/src/bindings/python/openalprpy.cpp @@ -5,9 +5,9 @@ #include extern "C" { - + #if defined(WIN32) - // Microsoft + // Microsoft #define OPENALPR_EXPORT __declspec(dllexport) #else // do nothing @@ -59,15 +59,15 @@ extern "C" { AlprResults results = nativeAlpr->recognize(imageFile); std::string json = Alpr::toJson(results); - + int strsize = sizeof(char) * (strlen(json.c_str()) + 1); char* membuffer = (char*)malloc(strsize); strcpy(membuffer, json.c_str()); //printf("allocated address: %p\n", membuffer); - + return membuffer; } - + OPENALPR_EXPORT void freeJsonMem(char* ptr) { //printf("freeing address: %p\n", ptr); @@ -87,12 +87,35 @@ extern "C" { AlprResults results = nativeAlpr->recognize(cvec); std::string json = Alpr::toJson(results); - + int strsize = sizeof(char) * (strlen(json.c_str()) + 1); char* membuffer = (char*)malloc(strsize); strcpy(membuffer, json.c_str()); //printf("allocated address: %p\n", membuffer); - + + return membuffer; + } + + // AlprResults recognize(unsigned char* pixelData, + // int bytesPerPixel, int imgWidth, int imgHeight, + // std::vector regionsOfInterest); + OPENALPR_EXPORT char* recognizeRawImage(Alpr* nativeAlpr, unsigned char* buf, int bytesPerPixel, int imgWidth, int imgHeight) + { + //printf("Recognize raw image"); + //printf("buffer pointer: %p\n", buf); + //printf("buffer length: %d\n", len); + + //std::cout << "Using instance: " << nativeAlpr << std::endl; + + std::vector regionsOfInterest; + AlprResults results = nativeAlpr->recognize(buf, bytesPerPixel, imgWidth, imgHeight, regionsOfInterest); + std::string json = Alpr::toJson(results); + + int strsize = sizeof(char) * (strlen(json.c_str()) + 1); + char* membuffer = (char*)malloc(strsize); + strcpy(membuffer, json.c_str()); + //printf("allocated address: %p\n", membuffer); + return membuffer; } @@ -103,7 +126,7 @@ extern "C" { nativeAlpr->setCountry(country); } - + OPENALPR_EXPORT void setPrewarp(Alpr* nativeAlpr, char* cprewarp) { // Convert strings from java to C++ and release resources @@ -111,7 +134,7 @@ extern "C" { nativeAlpr->setPrewarp(prewarp); } - + OPENALPR_EXPORT void setDefaultRegion(Alpr* nativeAlpr, char* cdefault_region) { // Convert strings from java to C++ and release resources @@ -138,9 +161,9 @@ extern "C" { char* membuffer = (char*)malloc(strsize); strcpy(membuffer, version.c_str()); //printf("allocated address: %p\n", membuffer); - + return membuffer; } -} \ No newline at end of file +}