Recent

Author Topic: TOpenALPR with Lazarus - Issue at call to OpenALPR  (Read 5947 times)

af0815

  • Hero Member
  • *****
  • Posts: 1409
TOpenALPR with Lazarus - Issue at call to OpenALPR
« on: July 08, 2019, 03:42:28 pm »
OpenALPR is a open source (and closed too) library to recognize License Plates. It haves now (but not released) bindings to C and this bindings was used by the project TOpenALPR for Delphi.

I have tested the C-bindings in Delphi and the samples work, with the recompiled openalpr.dll. When i fix some minor issue the example in delphi-vcl-image is convertible to Lazarus. The source for Lazarus is here https://github.com/afriess/TOpenALPR/tree/Lazarus. All is actual for Win32 !! Delphi, Lazarus and Libraries are for win32 only.

If you want to run the program you have to follow the rules in the read.me file for getting the correct libraries and support files.

But at runtime it is throwing an exception inside of the openalpr.dll - It is the same for Delphi !! - so something must be different in Lazarus. The exception is 'External:?' at adress 582BB424. I callstack, i see here a call to openalp_free_response_string in the call stack.

Any ideas what can be the difference between Lazarus and Delphi, where can i search ? Any ideas ?

   
regards
Andreas

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: TOpenALPR with Lazarus - Issue at call to OpenALPR
« Reply #1 on: July 09, 2019, 12:31:45 am »
A very random guess. Use external memory manager like cmem

jamie

  • Hero Member
  • *****
  • Posts: 7526
Re: TOpenALPR with Lazarus - Issue at call to OpenALPR
« Reply #2 on: July 09, 2019, 01:52:26 am »
I tried it, I am still on 3.0.4 fpc so I had to use FGL unit and rename the Tobjectlist<..> ////etc

I also had to create a type PUtf8char = Pchar….

But after that I got it to compile fine, however, the DLL that is provided fails to load.. it reports as not
being found but I know its there because I built a full path string to the file and use that instead of the
standard way.. It still fails.
I did a file check in code prior to the loadLibrary and the file is there, its just that Windows reports it as
not being there, so it must not be a valid file or it does not like where it's install.

 Hmm.
I did this with 32 bit Laz..
The only true wisdom is knowing you know nothing

af0815

  • Hero Member
  • *****
  • Posts: 1409
Re: TOpenALPR with Lazarus - Issue at call to OpenALPR
« Reply #3 on: July 09, 2019, 06:51:05 am »
But after that I got it to compile fine, however, the DLL that is provided fails to load.. it reports as not
being found but I know its there because I built a full path string to the file and use that instead of the
standard way.. It still fails.

You must use the DLL from TOpenALPR instead of OpenALPR AND to copy the correct other DLLs to fullfill the requirements. In the same directory alpr.exe from openalpr MUST run without a problem.

The 'not found' Error is reported if the depencies are not corect fullfilled.
regards
Andreas

af0815

  • Hero Member
  • *****
  • Posts: 1409
Re: TOpenALPR with Lazarus - Issue at call to OpenALPR
« Reply #4 on: July 09, 2019, 07:34:13 am »
A very random guess. Use external memory manager like cmem
Nothing differnt, if i use cmem in the first place in LPR and recompile, nothing differnet, The exception is the same

Quote
585EB40C 8b75f0                   mov    -0x10(%ebp),%esi
585EB40F 0f57d2                   xorps  %xmm2,%xmm2
585EB412 f20f104de8               movsd  -0x18(%ebp),%xmm1
585EB417 f20f100578706658         movsd  0x58667078,%xmm0
585EB41F f20f105e68               movsd  0x68(%esi),%xmm3
585EB424 f20f5ecb                 divsd  %xmm3,%xmm1
Always on 585EB424 and the assembler says it is in openalpr_free_response_string (18348)

No difference if i use fpc fixes32 + Lazarus fixes20 and fpcTrunk + LazarusTrunk
« Last Edit: July 09, 2019, 07:42:47 am by af0815 »
regards
Andreas

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: TOpenALPR with Lazarus - Issue at call to OpenALPR
« Reply #5 on: July 09, 2019, 07:42:56 am »
Yes, cmem is not needed. I saw the code. I tried to run it here. Did not work, my kernel32 misses at least one function, I'll have to try on a different system later when I get a chance.

af0815

  • Hero Member
  • *****
  • Posts: 1409
Re: TOpenALPR with Lazarus - Issue at call to OpenALPR
« Reply #6 on: July 09, 2019, 08:07:44 am »
I am using a Win10/64 Computer with the latest M$ patches.

For testing purposes i have the latest community version of Delphi in a VM.
regards
Andreas

Thaddy

  • Hero Member
  • *****
  • Posts: 18729
  • To Europe: simply sell USA bonds: dollar collapses
Re: TOpenALPR with Lazarus - Issue at call to OpenALPR
« Reply #7 on: July 09, 2019, 08:46:20 am »
If it is indeed a win32 dll, you should mask out the floating point exceptions, because M$ handles them in a non-standard (not IEEE compliant) way. This is a known issue. The mask you need is $1331 or $133f, but first save the exception mask and restore it on exit.  Set8087CW() and family, see the manual, and even if you use divsd. On win32 these also go through the FPU.

See also http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/System_Set8087CW.html That is also valid for FreePascal, since both Delphi and Freepascal are IEEE compliant.
« Last Edit: July 09, 2019, 09:00:43 am by Thaddy »
If Europe sells their USA bonds the USD will collapse. Europe can affort that given average state debts. The USA can't affort that. Just an advice...

af0815

  • Hero Member
  • *****
  • Posts: 1409
Re: TOpenALPR with Lazarus - Issue at call to OpenALPR
« Reply #8 on: July 09, 2019, 09:25:25 am »
I have tried both mask with Set8087CW and according the example, but the exception is the same. No change at all.
regards
Andreas

af0815

  • Hero Member
  • *****
  • Posts: 1409
Re: TOpenALPR with Lazarus - Issue at call to OpenALPR
« Reply #9 on: July 09, 2019, 09:37:12 am »
Interesting, i have activated the FirstDetectionDelayFix define. This make only one dry run of plate search at startup with the buffer version.

Code: Pascal  [Select][+][-]
  1.     {$IFDEF FirstDetectionDelayFix}
  2.     roi.x := 0;
  3.     roi.y := 0;
  4.     roi.width := 100;
  5.     roi.height := 100;
  6.     GetMem(buff, 100 * 100 * 3);
  7.     try
  8.       res := openalpr_recognize_rawimage(FOpenALPRInstance, buff, 3, 100, 100, roi);
  9.       openalpr_free_response_string(res);
  10.     finally
  11.       FreeMem(buff);
  12.     end;
  13.     {$ENDIF}
  14.  

It defines a (empty) buffer and do one recognize, but it fails too, but with another exception. The exeption shown in Lazarus is the dame (58524FB8  ... Exception: ?) but the position is another and the shown routine.

openalpr_set_topn (251764)
Quote
58524FA7 0f1101                   movups %xmm0,(%ecx)
58524FAA 0f114110                 movups %xmm0,0x10(%ecx)
58524FAE 660fd64120               movq   %xmm0,0x20(%ecx)
58524FB3 f20f104508               movsd  0x8(%ebp),%xmm0
58524FB8 f20f2cc0                 cvttsd2si %xmm0,%eax

Callstack
Quote
#0 openalpr_set_topn at :0
#1 openalpr!?toJson@Alpr@alpr@@SA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@VAlprResults@2@@Z at :0
#2 openalpr!?toJson@Alpr@alpr@@SA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@VAlprResults@2@@Z at :0
#3 openalpr_recognize_rawimage at :0
#4 TOPENALPR__INITIALIZE(0x5a4084 'eu', 0x5a4068 'openalpr.conf', 0x5a404c 'runtime_data', <error reading variable>) at C:\data\Pascal\TOpenALPR\openalpr.pas:325
#5 TOPENALPRIMAGEFORM__FORMCREATE(0x27e6784, <error reading variable>) at FormOpenALPRImage.pas:108
#6 TCUSTOMFORM__DOCREATE(<error reading variable>) at .\include\customform.inc:939
#7 TCUSTOMFORM__AFTERCONSTRUCTION(<error reading variable>) at .\include\customform.inc:149
#8 TFORM__CREATE(0x27e4b44, <incomplete type>, <error reading variable>) at .\include\customform.inc:3184
#9 TAPPLICATION__CREATEFORM(<incomplete type>, <error reading variable: Attempt to dereference a generic pointer.>, <error reading variable>) at .\include\application.inc:2241
#10 main at Lazarus_LCL_image.lpr:19



if you look inside of  the sources, you see all are C++ Objects, flattend to C for interfacing.

Code: C  [Select][+][-]
  1. // Recognizes the provided image and responds with JSON.  
  2. // Caller must call free() on the returned object
  3. OPENALPRC_DLL_EXPORT char* openalpr_recognize_rawimage(OPENALPR* instance, unsigned char* pixelData, int bytesPerPixel, int imgWidth, int imgHeight, AlprCRegionOfInterest roi)
  4. {
  5.   std::vector<alpr::AlprRegionOfInterest> rois;
  6.   alpr::AlprRegionOfInterest cpproi(roi.x, roi.y, roi.width, roi.height);
  7.   rois.push_back(cpproi);
  8.  
  9.   alpr::AlprResults results = ((alpr::Alpr*) instance)->recognize(pixelData,bytesPerPixel, imgWidth, imgHeight, rois);
  10.   std::string json_string = alpr::Alpr::toJson(results);
  11.  
  12.   char* result_obj = strdup(json_string.c_str());
  13.  
  14.   return result_obj;
  15.  
  16. }
  17.  
« Last Edit: July 09, 2019, 09:42:02 am by af0815 »
regards
Andreas

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: TOpenALPR with Lazarus - Issue at call to OpenALPR
« Reply #10 on: July 09, 2019, 04:52:35 pm »
A quick search for OPENALPRC_DLL_EXPORT showed:
Code: C  [Select][+][-]
  1. #ifdef WIN32
  2.   #define OPENALPRC_DLL_EXPORT __declspec( dllexport )
  3. #else
  4.   #define OPENALPRC_DLL_EXPORT
  5. #endif

If this is true, that means this pascal conversion is wrong:
Code: Pascal  [Select][+][-]
  1. type
  2.   Tfnopenalpr_init = function(const country: PUTF8Char; const configFile: PUTF8Char; const runtimeDir: PUTF8Char): TAlpr; cdecl;
  3.   Tfnopenalpr_is_loaded = function(instance: TAlpr): Boolean; cdecl;
  4.   Tfnopenalpr_set_country = procedure(instance: TAlpr; const country: PUTF8Char); cdecl;
  5.   Tfnopenalpr_set_prewarp = procedure(instance: TAlpr; const prewarp_config: PUTF8Char); cdecl;
  6.   Tfnopenalpr_set_mask = procedure(instance: TAlpr; pixelData: Pointer; bytesPerPixel, imgWidth, imgHeight: Integer); cdecl;
  7.   Tfnopenalpr_set_detect_region = procedure(instance: TAlpr; detectRegion: Boolean); cdecl;
  8.   Tfnopenalpr_set_topn = procedure(instance: TAlpr; topN: Integer); cdecl;
  9.   Tfnopenalpr_set_default_region = procedure(instance: TAlpr; const region: PUTF8Char); cdecl;
  10.   Tfnopenalpr_recognize_rawimage = function(instance: TAlpr; pixelData: Pointer; bytesPerPixel, imgWidth, imgHeight: Integer; roi: TAlprCRegionOfInterest): PUTF8Char; cdecl;
  11.   Tfnopenalpr_recognize_encodedimage = function(instance: TAlpr; bytes: Pointer; len: Int64; roi: TAlprCRegionOfInterest): PUTF8Char; cdecl;
  12.   Tfnopenalpr_free_response_string = procedure(response: PUTF8Char); cdecl;
  13.   Tfnopenalpr_cleanup = procedure(instance: TAlpr); cdecl;

The calling convention should be stdcall instead of cdecl.

Please check OPENALPRC_DLL_EXPORT, and confirm.

Thaddy

  • Hero Member
  • *****
  • Posts: 18729
  • To Europe: simply sell USA bonds: dollar collapses
Re: TOpenALPR with Lazarus - Issue at call to OpenALPR
« Reply #11 on: July 09, 2019, 05:51:14 pm »
Yes it is stdcall, confirmed. But you also need the exception mask I showed.
If Europe sells their USA bonds the USD will collapse. Europe can affort that given average state debts. The USA can't affort that. Just an advice...

af0815

  • Hero Member
  • *****
  • Posts: 1409
Re: TOpenALPR with Lazarus - Issue at call to OpenALPR
« Reply #12 on: July 09, 2019, 06:18:51 pm »
If i change the declaration from cdecl to stdcall, i get a SIGSEGV on the end of the TOpenALPR.Initalize - its looks like the stack is corrupt yet.

So i cannot confirm this.

I can only confirm, in alpr.h is the declaration , shown by engkin.

I read this article https://docs.microsoft.com/en-us/cpp/build/exporting-from-a-dll-using-declspec-dllexport?view=vs-2019 and
Quote
.. __declspec(dllexport) adds the export directive to the object file so you do not need to use a .def file.

This convenience is most apparent when trying to export decorated C++ function names. ...
So i undwerstand, it is only for the correct 'decoration' of the names.
« Last Edit: July 09, 2019, 06:45:41 pm by af0815 »
regards
Andreas

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: TOpenALPR with Lazarus - Issue at call to OpenALPR
« Reply #13 on: July 09, 2019, 07:47:36 pm »
Check the default calling convention when none is mentioned to the right side of __declspec(dllexport).

The same page you linked above shows:

__declspec(dllexport) void __cdecl Function1(void);

What calling convention when you use:

__declspec(dllexport) void Function1(void);



The answer applies to the code you posted above:
Code: C  [Select][+][-]
  1. OPENALPRC_DLL_EXPORT char* openalpr_recognize_rawimage(OPENALPR* instance, unsigned char* pixelData, int bytesPerPixel, int imgWidth, int imgHeight, AlprCRegionOfInterest roi)

What is the calling convention here?
« Last Edit: July 09, 2019, 07:51:47 pm by engkin »

af0815

  • Hero Member
  • *****
  • Posts: 1409
Re: TOpenALPR with Lazarus - Issue at call to OpenALPR
« Reply #14 on: July 09, 2019, 08:04:17 pm »
I go back to my first post.

The library is working in Delphi with cdecl. So i think this have to be cdecl or Delphi works differnt to Lazarus.

The callingconvention maybe depend on the Compiler defaults.
« Last Edit: July 09, 2019, 08:09:54 pm by af0815 »
regards
Andreas

 

TinyPortal © 2005-2018