DoubangoTelecom / ultimateMRZ-SDK

Machine-readable zone/travel document (MRZ / MRTD) detector and recognizer using deep learning
https://www.doubango.org/webapps/mrz/
Other
175 stars 49 forks source link

Running the SDK on Web Server #23

Closed imranbaloch closed 3 years ago

imranbaloch commented 4 years ago

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,

            UltMrzSdkResult result = CheckResult("Init", UltMrzSdkEngine.init(BuildJSON(@"SomePathOnWebServer", "")));
            Bitmap image = new Bitmap(somPostedFileToWebServer);
            BitmapData imageData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            try
            {
                result = CheckResult("Process", UltMrzSdkEngine.process(
                        ULTMRZ_SDK_IMAGE_TYPE.ULTMRZ_SDK_IMAGE_TYPE_RGB24, 
                        imageData.Scan0,
                        (uint)image.Width,
                        (uint)image.Height
                    ));
                 //result.json() include final
            }
            finally
            {
                image.UnlockBits(imageData);
            }

There will be a lot of threads that will be executing the same code parallelly. off course, somPostedFileToWebServer will be different for each request.

DoubangoTelecom commented 4 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.

imranbaloch commented 4 years ago

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)

DoubangoTelecom commented 4 years ago

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

imranbaloch commented 4 years ago

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.

DoubangoTelecom commented 4 years ago

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.

DoubangoTelecom commented 4 years ago

If you try "AnyCPU" and uncheck "Prefer 32-bit", it works

DoubangoTelecom commented 4 years ago

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."

imranbaloch commented 4 years ago

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,

image

image

DoubangoTelecom commented 4 years ago

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.

DoubangoTelecom commented 4 years ago

Also, have you tried to run IIS as 64-bit (https://stackoverflow.com/a/43417170) to check if it crash?

DoubangoTelecom commented 4 years ago

https://stackoverflow.com/a/14748308 This one looks more appropriate to enable full x64

imranbaloch commented 4 years ago

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 | 00007ffb00000003 00007ffb3b2a0db0 | 00007ffb3b2a0df8
ultimateMRZ_SDK!ultimateMrzSdk::UltMrzSdkResult::operatorAssign+1826d1 000001e6d5c7fc30 | 0000000000000000 00000020a09cf789 | 00000020a1e3ab90
ultimateMRZ_SDK!ultimateMrzSdk::UltMrzSdkResult::operatorAssign+1834c4 0000000000000000 | 000001e6d5c7fc30 0000000000000000 | 00007ffb3aead186
ultimateMRZ_SDK!ultimateMrzSdk::UltMrzSdkResult::operatorAssign+1ba6 0000000000000000 | 00007ffb3af2f295 0000000000000000 | 00000020a09cf710
ultimateMRZ_SDK!ultimateMrzSdk::UltMrzSdkResult::operatorAssign+2fb4 000001e6d341da60 000001e6d341da60 000001e6d341eb00 | 000001e6d341da68
ultimateMRZ_SDK!ultimateMrzSdk::UltMrzSdkResult::operatorAssign+8e629 0000000000000000 | 0000000000000000 0000000000000000 | 0000000000000000
kernel32!BaseThreadInitThunk+14 0000000000000000 | 0000000000000000 0000000000000000 | 0000000000000000
ntdll!RtlUserThreadStart+21 0000000000000000 | 0000000000000000 0000000000000000 | 0000000000000000
DoubangoTelecom commented 4 years ago

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.

imranbaloch commented 4 years ago

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?

DoubangoTelecom commented 4 years ago

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.

DoubangoTelecom commented 4 years ago

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

imranbaloch commented 4 years ago

I have ported this in C#. It will be great if can also take a look of this https://gist.github.com/imranbaloch/4c048d1e0bb615cbe784b73f898957fe

imranbaloch commented 4 years ago

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

DoubangoTelecom commented 4 years ago

Thanks, I'll review the code

imranbaloch commented 4 years ago

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?

imranbaloch commented 4 years ago

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,

image

image

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?

DoubangoTelecom commented 4 years ago

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.

DoubangoTelecom commented 4 years ago

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,

image

image

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?

  1. Yes, '<' are used to match length. It may also be used as space. Check https://www.doubango.org/SDKs/mrz/docs/MRZ_formats.html
  2. Yes, it's defined at https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3
  3. Yes, see https://www.doubango.org/SDKs/mrz/docs/MRZ_formats.html.
    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;
    }
  4. Without seeing the MRZ I don't know. Based on the standard your document should be QADIR<BAKSH<<IMRAN
imranbaloch commented 4 years ago

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

imranbaloch commented 4 years ago

Any idea why expiry date is different here,

image

DoubangoTelecom commented 4 years ago

Any idea why expiry date is different here,

image

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.

imranbaloch commented 4 years ago

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

DoubangoTelecom commented 4 years ago

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