docs: def evaluate_mrz():
      """
      A script for evaluating the current MRZ recognition pipeline by applying it to a list of files in a directory and reporting how well it went.
      """
      parser = argparse.ArgumentParser(description='Run the MRZ OCR recognition algorithm on the sample test data, reporting the quality summary.')
      parser.add_argument('-j', '--jobs', default=1, type=int, help='Number of parallel jobs to run')
      parser.add_argument('-dd', '--data-dir', default=pkg_resources.resource_filename('passporteye.mrz', 'testdata'),
                          help='Read files from this directory instead of the package test files')
      parser.add_argument('-sd', '--success-dir', default=None,
                          help='Copy files with successful (nonzero score) extraction results to this directory')
      parser.add_argument('-fd', '--fail-dir', default=None,
                          help='Copy files with unsuccessful (zero score) extraction resutls to this directory')
      parser.add_argument('-rd', '--roi-dir', default=None,
                          help='Extract ROIs to this directory')
      parser.add_argument('-l', '--limit', default=-1, type=int, help='Only process the first <limit> files in the directory.')
      parser.add_argument('--legacy', action='store_true',
                          help='Use the "legacy" Tesseract OCR engine (--oem 0). Despite the name, it most often results in better '
                          'results. It is not the default option, because it will only work if '
                          'your Tesseract installation includes the legacy *.traineddata files. You can download them at '
                          'https://github.com/tesseract-ocr/tesseract/wiki/Data-Files#data-files-for-version-400-november-29-2016')
      args = parser.parse_args()
      files = sorted(glob.glob(os.path.join(args.data_dir, '*.*')))
      if args.limit >= 0:
          files = files[0:args.limit]
  
      logging.basicConfig(level=logging.INFO)
      log = logging.getLogger("evaluate_mrz")
  
      tic = time.time()
      pool = multiprocessing.Pool(args.jobs)
      log.info("Preparing computation for %d files from %s", len(files), args.data_dir)
      log.info("Running %d workers", args.jobs)
      results = []
      save_roi = args.roi_dir is not None
      for d in [args.success_dir, args.fail_dir, args.roi_dir]:
          if d is not None and not os.path.isdir(d):
              os.mkdir(d)
  
      def valid_score(mrz_):
          return 0 if mrz_ is None else mrz_.valid_score
  
      def score_change_type(filename, mrz_):
          try:
              new_score = valid_score(mrz_)
              old_score = int(os.path.basename(filename).split('_')[0])
              schange = new_score - old_score
              return '=' if schange == 0 else ('>' if schange > 0 else '<')
          except Exception:
              return '?'
  
      method_stats = Counter()
  
      extra_params = '--oem 0' if args.legacy else ''
      for result in pool.imap_unordered(process_file, [(f, save_roi, extra_params) for f in files]):
          filename, mrz_, walltime = result
          results.append(result)
          log.info("Processed %s in %0.2fs (score %d) [%s]", os.path.basename(filename), walltime, valid_score(mrz_), score_change_type(filename, mrz_))
          log.debug("\t%s", mrz_)
  
          vs = valid_score(mrz_)
          if args.success_dir is not None and vs > 0:
              shutil.copyfile(filename, os.path.join(args.success_dir, '%d_%s' % (vs, os.path.basename(filename))))
          if args.fail_dir is not None and vs == 0:
              shutil.copyfile(filename, os.path.join(args.fail_dir, '%d_%s' % (vs, os.path.basename(filename))))
          if args.roi_dir is not None and mrz_ is not None and 'roi' in mrz_.aux:
              roi_fn = '%d_roi_%s.png' % (vs, os.path.basename(filename))
              io.imsave(os.path.join(args.roi_dir, roi_fn), mrz_.aux['roi'])
  
          if vs > 0 and 'method' in mrz_.aux:
              method_stats[mrz_.aux['method']] += 1
  
      num_files = len(results)
      score_changes = [score_change_type(fn, mrz_) for fn, mrz_, wt in results]
      scores = [valid_score(mrz_) for fn, mrz_, wt in results]
      num_perfect = scores.count(100)
      num_invalid = scores.count(0)
      total_score = sum(scores)
      total_computation_walltime = sum([wt for fn, mrz_, wt in results])
      total_walltime = time.time() - tic
      log.info("Completed")
      print("Walltime:          %0.2fs" % total_walltime)
      print("Compute walltime:  %0.2fs" % total_computation_walltime)
      print("Processed files:   %d" % num_files)
      print("Perfect parses:    %d" % num_perfect)
      print("Invalid parses:    %d" % num_invalid)
      print("Improved parses:   %d" % len([x for x in score_changes if x == '>']))
      print("Worsened parses:   %d" % len([x for x in score_changes if x == '<']))
      print("Total score:       %d" % total_score)
      print("Mean score:        %0.2f" % (float(total_score)/num_files))
      print("Mean compute time: %0.2fs" % (total_computation_walltime/num_files))
      print("Methods used:")
      for stat in method_stats.most_common():
          print("  %s: %d" % stat)