Closed imranbaloch closed 3 years ago
Call the Init
function once at server startup.
You have to protect the process function to avoid concurrent access:
mutex.lock();
process();
mutex.unlock();
The process function is already massively multithreaded. Without access control you'll be forking the threads and will end up flooding your CPU. On quad core with hyper-threading you'll have 8 threads created by the SDK. If you're using 8 threads to call the process function then, you'll have 8x8=64 threads. Our code is already well designed to avoid context switching and thread forking (https://github.com/DoubangoTelecom/compv/tree/master/base/parallel). See https://www.doubango.org/SDKs/mrz/docs/Architecture_overview.html#thread-safety.
The minimum frame rate is 15fps (https://github.com/DoubangoTelecom/ultimateMRZ-SDK/tree/master/samples/c%2B%2B/benchmark#peformance-numbers) which means you could process at least 900 requests per minutes when all images have MRZ lines.
I don't know how 900 RPM will be achieved if you have mutex around the process. Is it the right place to ask a question for support or should we send an email for support(because we already purchased the license)
The benchmark application is sequential which means the lock is nop. If you run the benchmark for 1 minute you'll have the maximum requests you can process.
You can contact our support team at tech at doubango doT org
There seems to be an issue running the sample in .NET web application(specifically ASP.NET MVC). When you mark the process(w3wp) as 32 bit it throws TypeInitializationexception but when I mark it as 64 bit it crashes the w3wp process. I checked your console application it marked explicitly application target as x64 but our web application is using AnyCpu. If I change my applications to x64 then my application won't run because of other dependencies.
As you can clearly see on the Github pages and the pricing (https://www.doubango.org/pricing.html), we always make sure to write "x86_64" instead of "x86". The binaries distributed are for 64-bit CPUs and we don't have 32-bit version. Because you have a commercial license we'll build a 32-bit version for you but keep in mind many optimizations are not available to these CPUs. If you're planning to build a high performance server it's not a good idea.
If you try "AnyCPU" and uncheck "Prefer 32-bit", it works
I have checked on the web and looks like with "AnyCPU" x86_64 binaries will be correctly loaded unless you're running a 32-bit system or have checked "Prefer 32-bit". I'm closing this ticket, if you really want to force your app to run as 32-bit let us know and I'll prepare. Quote from https://stackoverflow.com/questions/516730/what-does-the-visual-studio-any-cpu-target-mean#comment23739204_516743 -> "Which could be terrible if your writing for a server environment and want your application to be able to use more then 2GB of memory. You are also opting out of any x64 JIT optimizations that may someday come down the pipe."
Unfortunately, Prefer 32-bit works for executables that run in the process. In web we have a w3wp.exe process. which can be both 32 bit and 64 bit. With 32 bit w3wp.exe process, application throwing an error while in 64-bit w3wp.exe process case it is crashing when calling init,
Sorry but I don't really understand what you're trying to explain. An application cannot be both 32-bit and 64-bit. When you start it the process will be one of 32-bit or 64-bit but not both. The assembly could embed both architectures but the process is one arch the another. Your screen shows 2 different processes, one is 32-bit and the other is 64-bit. It's normal for the 32-bit to crash but not for the 64-bit. Please share the crash report for the 64-bit process.
Also, have you tried to run IIS as 64-bit (https://stackoverflow.com/a/43417170) to check if it crash?
https://stackoverflow.com/a/14748308 This one looks more appropriate to enable full x64
Sorry but I don't really understand what you're trying to explain. An application cannot be both 32-bit and 64-bit. When you start it the process will be one of 32-bit or 64-bit but not both. The assembly could embed both architectures but the process is one arch the another.
Actually, I am running my application both in 32 bit and 64 bit that's why you see both applications in above screenshot.
Also, have you tried to run IIS as 64-bit (https://stackoverflow.com/a/43417170) to check if it crash?
This is for IIS express not IIS (yes IIS and IIS express are different web servers)
https://stackoverflow.com/a/14748308 This one looks more appropriate to enable full x64
This is what I did for IIS (and that's what you see in the screenshot above for running the app in both 32 bit and 64 bit)
I have crash dumps for the application running on 64 bit. Of course, you guys can analyze the dump better so please let me know what is the best way to share the dump. At the time of the crash there were 60 threads. Exception message was,
Unhandled exception at 0x00007FFBD3D5E75E (ucrtbase.dll) in MyDump.dmp: Fatal program exit requested.
The assembly instruction at ucrtbase!abort+4e in C:\WINDOWS\System32\ucrtbase.dll has caused an unknown exception (0xc0000409) on thread 51
Full Call Stack
Function | Arg 1 | Arg 2 | Arg 3 | Arg 4 | Source |
---|---|---|---|---|---|
ucrtbase!abort+4e | 000001e600000003 | 00007ffb 00000003 |
00007ffb3b2a0db0 | 00007ffb 3b2a0df8 |
|||
ultimateMRZ_SDK!ultimateMrzSdk::UltMrzSdkResult::operatorAssign+1826d1 | 000001e6d5c7fc30 | 00000000 00000000 |
00000020a09cf789 | 00000020 a1e3ab90 |
|||
ultimateMRZ_SDK!ultimateMrzSdk::UltMrzSdkResult::operatorAssign+1834c4 | 0000000000000000 | 000001e6 d5c7fc30 |
0000000000000000 | 00007ffb 3aead186 |
|||
ultimateMRZ_SDK!ultimateMrzSdk::UltMrzSdkResult::operatorAssign+1ba6 | 0000000000000000 | 00007ffb 3af2f295 |
0000000000000000 | 00000020 a09cf710 |
|||
ultimateMRZ_SDK!ultimateMrzSdk::UltMrzSdkResult::operatorAssign+2fb4 | 000001e6d341da60 000001e6 d341da60 |
000001e6d341eb00 | 000001e6 d341da68 |
|||
ultimateMRZ_SDK!ultimateMrzSdk::UltMrzSdkResult::operatorAssign+8e629 | 0000000000000000 | 00000000 00000000 |
0000000000000000 | 00000000 00000000 |
|||
kernel32!BaseThreadInitThunk+14 | 0000000000000000 | 00000000 00000000 |
0000000000000000 | 00000000 00000000 |
|||
ntdll!RtlUserThreadStart+21 | 0000000000000000 | 00000000 00000000 |
0000000000000000 | 00000000 00000000 |
I'm not familiar with IIS. Is it possible to retrieve logs to stderr? The assign operator is called before returning a result. Inside this function we call VirtualAlloc. At startup, before reaching this function we print many useful logs (see recognizer sample app). It would be useful for us if we can have these logs. Also, we will probably add more logs to understand the issue.
Unfortunately, IIS does not keep stdout/stderr but IIS Express does via command line. I got the reason for this crash it was missing the mrz.traineddata file 🤦
You can see the output below,
*[COMPV INFO]: [UltMrzSdkEngine] Call: ultimateMrzSdk::UltMrzSdkEngine::init
*[COMPV INFO]: [UltMrzSdkEngine] jsonConfig: {"debug_level":"info","debug_write_input_image_enabled":false,"debug_internal_data_path":".","num_threads":-1,"gpgpu_enabled":true,"gpgpu_workload_balancing_enabled":false,"segmenter_accuracy":"high","interpolation":"bilinear","min_num_lines":2,"roi":[0,0,0,0],"min_score":0,"assets_folder":"/assets","license_token_data":""}
*[COMPV INFO]: [UltMrzSdkEngine] **** Copyright (C) 2011-2020 Doubango Telecom <https://www.doubango.org> ****
ultimateMRZ-SDK <https://github.com/DoubangoTelecom/ultimateMRZ-SDK> version 2.1.0
*[COMPV INFO]: [CompVBase] Initializing [base] modules (v 1.0.0, nt -1)...
*[COMPV INFO]: [CompVBase] sizeof(compv_scalar_t)= #8
*[COMPV INFO]: [CompVBase] sizeof(float)= #4
*[COMPV INFO]: [CompVBase] Windows dwMajorVersion=10, dwMinorVersion=0
*[COMPV INFO]: Initializing window registery
*[COMPV INFO]: [ImageDecoder] Initializing image decoder...
*[COMPV INFO]: [CompVCpu] Hardware: 'GenuineIntel', Serial: '***', Model: ''
*[COMPV INFO]: [CompVBase] CPU features: (intel);[x86];[x64];mmx;sse;sse2;sse3;ssse3;sse41;sse42;avx;avx2;fma3;erms;bmi1;bmi2;popcnt;cmov;aes;rdrand;
*[COMPV INFO]: [CompVBase] CPU cores: #8
*[COMPV INFO]: [CompVBase] CPU cache1: line size: #64B, size :#32KB
*[COMPV INFO]: [CompVBase] CPU Phys RAM size: #32590GB
*[COMPV INFO]: [CompVBase] CPU endianness: LITTLE
*[COMPV INFO]: [CompVBase] Binary type: X86_64
*[COMPV INFO]: [CompVBase] Intrinsic enabled
*[COMPV INFO]: [CompVBase] Assembler enabled
*[COMPV INFO]: [CompVBase] Math Fast Trig.: true
*[COMPV INFO]: [CompVBase] Math Fixed Point: true
*[COMPV INFO]: [CompVMathExp] Init
*[COMPV INFO]: [CompVBase] Default alignment: #64
*[COMPV INFO]: [CompVBase] Best alignment: #64
*[COMPV INFO]: [CompVBase] Heap limit: #1668637KB (#1629MB)
*[COMPV INFO]: [CompVParallel] Initializing [parallel] module...
*[COMPV INFO]: /!\ Code in file 'compv_mem.cxx' in function 'compv::CompVMemZero_C' starting at line #501: Not optimized -> No SIMD implementation found
*[COMPV INFO]: [CompVThreadDispatcher] Thread dispatcher created with #8 threads/#8 cores
*[COMPV INFO]: [CompVParallel] [Parallel] module initialized
*[COMPV INFO]: [CompVBase] [Base] modules initialized
*[COMPV INFO]: [CompVAsyncTask11] compv::CompVAsyncTask11::run(coreId:requested=2,set=useless, threadId:0000000000006CB8, kThreadSetAffinity:false) - ENTER
*[COMPV INFO]: [CompVAsyncTask11] compv::CompVAsyncTask11::run(coreId:requested=3,set=useless, threadId:00000000000018E0, kThreadSetAffinity:false) - ENTER
*[COMPV INFO]: [CompVAsyncTask11] compv::CompVAsyncTask11::run(coreId:requested=4,set=useless, threadId:0000000000006BD0, kThreadSetAffinity:false) - ENTER
*[COMPV INFO]: [CompVAsyncTask11] compv::CompVAsyncTask11::run(coreId:requested=5,set=useless, threadId:0000000000006DAC, kThreadSetAffinity:false) - ENTER
*[COMPV INFO]: [CompVAsyncTask11] compv::CompVAsyncTask11::run(coreId:requested=6,set=useless, threadId:00000000000065E8, kThreadSetAffinity:false) - ENTER
*[COMPV INFO]: [CompVAsyncTask11] compv::CompVAsyncTask11::run(coreId:requested=7,set=useless, threadId:000000000000B028, kThreadSetAffinity:false) - ENTER
*[COMPV INFO]: [CompVAsyncTask11] compv::CompVAsyncTask11::run(coreId:requested=0,set=useless, threadId:0000000000007FA8, kThreadSetAffinity:false) - ENTER
*[COMPV INFO]: [CompVAsyncTask11] compv::CompVAsyncTask11::run(coreId:requested=1,set=useless, threadId:000000000000AB68, kThreadSetAffinity:false) - ENTER
*[COMPV INFO]: [CompVCore] Initializing [core] module (v 1.0.0)...
*[COMPV INFO]: [CompVFeature] Registering feature factory with id = 1 and name = 'FAST (Features from Accelerated Segment Test)'...
*[COMPV INFO]: [CompVFeature] Registering feature factory with id = 8 and name = 'ORB (Oriented FAST and Rotated BRIEF)'...
*[COMPV INFO]: [CompVFeature] Registering feature factory with id = 27 and name = 'Sobel edge detector'...
*[COMPV INFO]: [CompVFeature] Registering feature factory with id = 28 and name = 'Scharr edge detector'...
*[COMPV INFO]: [CompVFeature] Registering feature factory with id = 29 and name = 'Prewitt edge detector'...
*[COMPV INFO]: [CompVFeature] Registering feature factory with id = 20 and name = 'Canny edge detector'...
*[COMPV INFO]: [CompVFeature] Registering feature factory with id = 30 and name = 'Hough standard (STD)'...
*[COMPV INFO]: [CompVFeature] Registering feature factory with id = 31 and name = 'Kernel-based Hough transform (KHT)'...
*[COMPV INFO]: [CompVFeature] Registering feature factory with id = 41 and name = 'Standard Histogram of oriented gradients (S-HOG)'...
*[COMPV INFO]: [CompVMatcher] Registering matcher factory with id = 0 and name = 'Brute force matcher'...
*[COMPV INFO]: [CompVConnectedComponentLabeling] Registering connected component labeling factory with id = 1 and name = 'PLSL (Parallel Light Speed Labeling)'...
*[COMPV INFO]: [CompVConnectedComponentLabeling] Registering connected component labeling factory with id = 19 and name = 'LMSER (Linear Time Maximally Stable Extremal Regions)'...
*[COMPV INFO]: [CompVGL] Initializing [gl] module (v 1.0.0)...
*[COMPV INFO]: [CompVGL] GL module initialized
*[COMPV INFO]: [CompVGpu] Initializing [gpu] module (v 1.0.0)...
*[COMPV INFO]: [CompVCamera] Initializing [camera] module (v 1.0.0)...
*[COMPV INFO]: [CompVCamera] Camera plugin path: C:\Users\iq.baksh\CompVPluginMFoundation.dll
*[COMPV INFO]: [CompVDrawing] Initializing [drawing] module (v 1.0.0)...
*[COMPV INFO]: [CompVDrawing] /!\ No jpeg decoder found
*[COMPV INFO]: [CompVDrawing] Drawing module initialized
*[COMPV INFO]: [CompVGpu] GPU enabled: true
*[COMPV INFO]: /!\ Code in file 'source\ultimate_base_engine.cxx' in function 'ultimateBase::UltBaseEngine::init' starting at line #26: Not optimized for GPU -> GPGPU computing not enabled or deactivated
*[COMPV INFO]: [UltBaseOpenCL] Trying to load [OpenCL.dll]
*[COMPV INFO]: Loaded shared lib: OpenCL.dll
*[COMPV INFO]: [UltBaseOpenCL] Loaded [OpenCL.dll], looksLikeValid: yes...
*[COMPV INFO]: [UltBaseOpenCLUtils] Selected platform vendor: Intel(R) Corporation
*[COMPV INFO]: [UltBaseOpenCLUtils] deviceCount=1
*[COMPV INFO]: [UltBaseOpenCLUtils] Device -> name: Intel(R) HD Graphics P530, id: 00000209CD984200
*[COMPV INFO]: [UltBaseOpenCLUtils] CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT=1
*[COMPV INFO]: [UltBaseOpenCLUtils] CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE=1
*[COMPV INFO]: [UltBaseOpenCLUtils] CL_DEVICE_MAX_COMPUTE_UNITS=24
*[COMPV INFO]: [UltBaseOpenCLUtils] CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS=3
*[COMPV INFO]: [UltBaseOpenCLUtils] CL_DEVICE_MAX_WORK_ITEM_SIZES=256, 256, 256,
*[COMPV INFO]: [UltBaseOpenCLUtils] CL_DEVICE_MAX_WORK_GROUP_SIZE=256
*[COMPV INFO]: [UltBaseOpenCLUtils] CL_DEVICE_MAX_CLOCK_FREQUENCY=1050 MHz
*[COMPV INFO]: [UltBaseOpenCLUtils] CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE=64 B
*[COMPV INFO]: [UltBaseOpenCLUtils] CL_DEVICE_GLOBAL_MEM_SIZE=13669478400 B (13036 MB)
*[COMPV INFO]: [UltBaseOpenCLUtils] CL_DEVICE_LOCAL_MEM_SIZE=65536 B (64 KB)
*[COMPV INFO]: [UltBaseOpenCLUtils] CL_DEVICE_MAX_MEM_ALLOC_SIZE=4095 MB
*[COMPV INFO]: [UltBaseOpenCLUtils] CL_PLATFORM_VERSION=OpenCL 2.1
*[COMPV INFO]: [UltBaseOpenCLUtils] CL_DEVICE_VERSION=OpenCL 2.1 NEO
*[COMPV INFO]: [UltBaseOpenCLUtils] CL_DRIVER_VERSION=26.20.100.6913
*[COMPV INFO]: [UltBaseOpenCLUtils] CL_DEVICE_OPENCL_C_VERSION=OpenCL C 2.0
***[COMPV ERROR]: function: "ultimateBase::UltBaseOpenCLUtils::init()"
file: "source\opencl\ultimate_base_opencl_utils.cxx"
line: "96"
message: [UltBaseOpenCLUtils] OpenCL operation failed (-30 -> CL_INVALID_VALUE) ->
***[COMPV ERROR]: function: "ultimateBase::UltBaseOpenCLUtils::init()"
file: "source\opencl\ultimate_base_opencl_utils.cxx"
line: "106"
message: Operation Failed (COMPV_ERROR_CODE_E_UNKNOWN) ->
*[COMPV INFO]: [UltBaseOpenCL] Failed to hook functions using [OpenCL.dll] library
*[COMPV INFO]: [UltMrzSdkEnginePrivate] **** Copyright (C) 2011-2020 Doubango Telecom <https://www.doubango.org> ****
You're using an unlicensed version of ultimateMRZ-SDK <https://github.com/DoubangoTelecom/ultimateMRZ-SDK>
without the rights to include the SDK in any form of commercial product.
*[COMPV INFO]: [CompVCpu] Enabling asm code
*[COMPV INFO]: [CompVCpu] Enabling intrinsic code
*[COMPV INFO]: [UltLstmNetwork] Old local: C, new local: C
*[COMPV INFO]: [UltLstmNetwork] Create LSTM engine for thread 0
*[COMPV INFO]: [UltLstmNetwork] Create LSTM engine for thread 1
*[COMPV INFO]: [UltLstmNetwork] Create LSTM engine for thread 2
Error opening data file assets/models/mrz.traineddata
Please make sure the TESSDATA_PREFIX environment variable is set to your "tessdata" directory.
Error opening data file assets/models/mrz.traineddata
Please make sure the TESSDATA_PREFIX environment variable is set to your "tessdata" directory.
Failed loading language 'mrz'
Tesseract couldn't load any languages!
Failed loading language 'mrz'
Tesseract couldn't load any languages!
****[COMPV FATAL]: function: "ultimateLstm::UltLstmNetworkThreadData::UltLstmNetworkThreadData()"
file: "source\ultimate_lstm_network.cxx"
line: "53"
message: Assertion failed!
Currently, I am getting a masked response. Will I get same JSON that you have at https://www.doubango.org/webapps/mrz/ after applying liceance token?
Good to see you managed to debug the crash. You'll have the same JSON but without the fields (expiry date, document number...). The code used on the server to extract these fields is open source: https://github.com/DoubangoTelecom/ultimateMRZ-SDK/tree/master/samples/c%2B%2B/parser. The description is at https://www.doubango.org/SDKs/mrz/docs/MRZ_parser.html. Like C++, C# supports parsing regular expression which means it should be easy to convert the code at https://github.com/DoubangoTelecom/ultimateMRZ-SDK/blob/master/samples/c%2B%2B/mrz_parser.h. If you have used local id documents then you have probably noticed that the server fails to parse them. We follow the standard (https://www.doubango.org/SDKs/mrz/docs/MRZ_formats.html) and most local documents don't respect them and this is why we haven't included the parser in the SDK to avoid get reports about document from XXXYY.
Additional note: If you're testing your JSON parser using what is returned from the server there is another difference. The server returns "warppedBox" while the SDK returns "warpedBox". There is a typo on the server but will not change for backward compatibility
I have ported this in C#. It will be great if can also take a look of this https://gist.github.com/imranbaloch/4c048d1e0bb615cbe784b73f898957fe
Also, I think this line should be doc_number instead of doc https://github.com/DoubangoTelecom/ultimateMRZ-SDK/blob/71e507ffc33fb5a24a2fa127c72a41f3755f31e0/samples/c%2B%2B/mrz_parser.h#L256
Thanks, I'll review the code
Sorry to ask another related question. For finding lines do we need to loop through all zones to find all lines and the first line will be in the first zone?
I have a few more questions,
1) I see some fields have with P< and personal number with Should I replace with < with empty? 2) Do we have a standard of mapping list of countries with code in MRZ? 3) Do we have mapping of P<, VI, C1, etc. document types? 4) I tried with my id,
In your portal https://www.doubango.org/webapps/mrz/ the surname and given name have issues? Is this is not standard or there might in issue in parsing?
Sorry to ask another related question. For finding lines do we need to loop through all zones to find all lines and the first line will be in the first zone?
A zone defines a group of lines. This means you should have as many zones as documents. If you have 1 document you should have a single zone unless there is a false positive. If you check the sample images at https://www.doubango.org/webapps/mrz/ you'll see that only the 3rd image has 2 zones because there are 2 documents.
So, looping through zones means looping through different documents.
I have a few more questions,
- I see some fields have with P< and personal number with Should I replace with < with empty?
- Do we have a standard of mapping list of countries with code in MRZ?
- Do we have mapping of P<, VI, C1, etc. document types?
- I tried with my id,
In your portal https://www.doubango.org/webapps/mrz/ the surname and given name have issues? Is this is not standard or there might in issue in parsing?
switch (Doc) {
case 'P': document = "Passport"; break;
case 'V': document = "Visa"; break;
case 'I': document = "Identity card"; break;
case 'C': if (firstLineString[1] == '1' && countryCode == "USA") { document = "Permanent resident card"; } break;
default: break;
}
QADIR<BAKSH<<IMRAN
Thanks for your detailed answer.
Without seeing the MRZ I don't know. Based on the standard your document should be QADIR<BAKSH<<IMRAN
Mine is P<PAKQADIR<BAKSH<<IMRAN<<<<<<<<<<<<<<<<<<<<<
If you see above pic of my passport my surname is QADIR BAKSH
and given name is IMRAN
Edit: also, if you have any idea how should we handle YY? For example, sometimes we have 30 50 which both means 1950 and 2050
Any idea why expiry date is different here,
Any idea why expiry date is different here,
Even without checking you can know the mrz doesn't match the document content (there is no 24). Don't expect specimens to be correct.
Thanks. do you have any idea how should we handle YY year case? For example, sometimes we have 30 50 which both means 1950 and 2050
Thanks. do you have any idea how should we handle YY year case? For example, sometimes we have 30 50 which both means 1950 and 2050
Checked but for now I have no idea
Just need to confirm the sample code in your repo will be enough to handle the normal sever load (at least 100 Requests per Minute) or there are some threading issues we need to tackle,
There will be a lot of threads that will be executing the same code parallelly. off course,
somPostedFileToWebServer
will be different for each request.