How to Read Nonstandard 1D Barcodes with Dynamsoft Barcode SDK in Python

Start and stop characters are defined by 1D (linear) barcode standards. Sometimes you’ll encounter nonstandard barcodes where these characters differ. This guide takes Code 39 as the example and shows how to decode such barcodes in Python with the Dynamsoft Barcode Reader (via the Dynamsoft Capture Vision Bundle) by supplying a custom template.

Prerequisites

  • Python 3.x
  • A free trial license for Dynamsoft Barcode Reader SDK
  • Install the SDK:

      pip install dynamsoft-capture-vision-bundle
    

Dataset (for comparison)

Standard Code 39 (start/stop *)

Nonstandard Code 39 (start/stop +)

Nonstandard Code 39 (start/stop -)

Quick Start: Read a Standard Code 39

Here is the code snippet for decoding a standard 1D barcode image:

    from dynamsoft_capture_vision_bundle import *

    license_key = "LICENSE-KEY" # https://www.dynamsoft.com/customer/license/trialLicense/?product=dcv&package=cross-platform
    cvr_instance = CaptureVisionRouter()
    error_code, error_message = LicenseManager.init_license(license_key)
    result = cvr_instance.capture(filename, EnumPresetTemplate.PT_READ_BARCODES.value)
    
    if result.get_error_code() != EnumErrorCode.EC_OK:
        print("Error:", result.get_error_code(),
                result.get_error_string())
    else:
        items = result.get_items()
        print('Found {} barcodes.'.format(len(items)))
        for item in items:
            format_type = item.get_format_string()
            text = item.get_text()
            print("Barcode Format:", format_type)
            print("Barcode Text:", text)

            location = item.get_location()
            x1 = location.points[0].x
            y1 = location.points[0].y
            x2 = location.points[1].x
            y2 = location.points[1].y
            x3 = location.points[2].x
            y3 = location.points[2].y
            x4 = location.points[3].x
            y4 = location.points[3].y
            print("Location Points:")
            print("({}, {})".format(x1, y1))
            print("({}, {})".format(x2, y2))
            print("({}, {})".format(x3, y3))
            print("({}, {})".format(x4, y4))
            print("-------------------------------------------------")

Reading Nonstandard 1D Barcodes with Custom Templates

To decode variants (e.g., Code 39 using + or - as start/stop), provide a custom template that tells the SDK what to expect.

Minimal template for Code 39 with + start/stop Save as template_plus.json:

{
  "BarcodeFormatSpecificationOptions": [
    {
      "BarcodeFormatIds": [
        "BF_DEFAULT",
        "BF_NONSTANDARD_BARCODE"
      ],
      "HeadModuleRatio": "131113131",
      "Name": "bfs_0",
      "StandardFormat": "BF_CODE_39",
      "TailModuleRatio": "131113131"
    }
  ],
  "BarcodeReaderTaskSettingOptions": [
    {
      "BarcodeFormatIds": [
        "BF_DEFAULT",
        "BF_NONSTANDARD_BARCODE"
      ],
      "BarcodeFormatSpecificationNameArray": [
        "bfs_0"
      ],
      "Name": "dbr_task_0",
      "SectionArray": [
        {
          "ImageParameterName": "IP_0",
          "Section": "ST_REGION_PREDETECTION",
          "StageArray": [
            {
              "Stage": "SST_PREDETECT_REGIONS"
            }
          ]
        },
        {
          "ImageParameterName": "IP_0",
          "Section": "ST_BARCODE_LOCALIZATION",
          "StageArray": [
            {
              "Stage": "SST_LOCALIZE_CANDIDATE_BARCODES"
            },
            {
              "Stage": "SST_LOCALIZE_BARCODES"
            }
          ]
        },
        {
          "ImageParameterName": "IP_0",
          "Section": "ST_BARCODE_DECODING",
          "StageArray": [
            {
              "Stage": "SST_RESIST_DEFORMATION"
            },
            {
              "Stage": "SST_COMPLEMENT_BARCODE"
            },
            {
              "Stage": "SST_SCALE_BARCODE_IMAGE"
            },
            {
              "Stage": "SST_DECODE_BARCODES"
            }
          ]
        }
      ]
    }
  ],
  "CaptureVisionTemplates": [
    {
      "ImageROIProcessingNameArray": [
        "roi_default"
      ],
      "Name": "CV_0",
      "Timeout": 1000000
    }
  ],
  "ImageParameterOptions": [
    {
      "ApplicableStages": [
        {
          "Stage": "SST_INPUT_COLOR_IMAGE"
        },
        {
          "Stage": "SST_SCALE_IMAGE"
        },
        {
          "Stage": "SST_CONVERT_TO_GRAYSCALE"
        },
        {
          "Stage": "SST_TRANSFORM_GRAYSCALE"
        },
        {
          "Stage": "SST_ENHANCE_GRAYSCALE"
        },
        {
          "Stage": "SST_BINARIZE_IMAGE"
        },
        {
          "Stage": "SST_DETECT_TEXTURE"
        },
        {
          "Stage": "SST_REMOVE_TEXTURE_FROM_GRAYSCALE"
        },
        {
          "Stage": "SST_BINARIZE_TEXTURE_REMOVED_GRAYSCALE"
        },
        {
          "Stage": "SST_FIND_CONTOURS"
        },
        {
          "Stage": "SST_DETECT_SHORTLINES"
        },
        {
          "Stage": "SST_ASSEMBLE_LINES"
        },
        {
          "Stage": "SST_DETECT_TEXT_ZONES"
        },
        {
          "Stage": "SST_REMOVE_TEXT_ZONES_FROM_BINARY"
        }
      ],
      "Name": "IP_0"
    }
  ],
  "TargetROIDefOptions": [
    {
      "Name": "roi_default",
      "TaskSettingNameArray": [
        "dbr_task_0"
      ]
    }
  ]
}

Minimal template for Code 39 with - start/stop

Save as template_minus.json. Only the tail/head ratios differ:

{
  "BarcodeFormatSpecificationOptions": [
    {
      "BarcodeFormatIds": [
        "BF_DEFAULT",
        "BF_NONSTANDARD_BARCODE"
      ],
      "HeadModuleRatio": "131111313",
      "Name": "bfs_0",
      "StandardFormat": "BF_CODE_39",
      "TailModuleRatio": "131111313"
    }
  ],
  "BarcodeReaderTaskSettingOptions": [
    {
      "BarcodeFormatIds": [
        "BF_DEFAULT",
        "BF_NONSTANDARD_BARCODE"
      ],
      "BarcodeFormatSpecificationNameArray": [
        "bfs_0"
      ],
      "Name": "dbr_task_0",
      "SectionArray": [
        {
          "ImageParameterName": "IP_0",
          "Section": "ST_REGION_PREDETECTION",
          "StageArray": [
            {
              "Stage": "SST_PREDETECT_REGIONS"
            }
          ]
        },
        {
          "ImageParameterName": "IP_0",
          "Section": "ST_BARCODE_LOCALIZATION",
          "StageArray": [
            {
              "Stage": "SST_LOCALIZE_CANDIDATE_BARCODES"
            },
            {
              "Stage": "SST_LOCALIZE_BARCODES"
            }
          ]
        },
        {
          "ImageParameterName": "IP_0",
          "Section": "ST_BARCODE_DECODING",
          "StageArray": [
            {
              "Stage": "SST_RESIST_DEFORMATION"
            },
            {
              "Stage": "SST_COMPLEMENT_BARCODE"
            },
            {
              "Stage": "SST_SCALE_BARCODE_IMAGE"
            },
            {
              "Stage": "SST_DECODE_BARCODES"
            }
          ]
        }
      ]
    }
  ],
  "CaptureVisionTemplates": [
    {
      "ImageROIProcessingNameArray": [
        "roi_default"
      ],
      "Name": "CV_0",
      "Timeout": 1000000
    }
  ],
  "ImageParameterOptions": [
    {
      "ApplicableStages": [
        {
          "Stage": "SST_INPUT_COLOR_IMAGE"
        },
        {
          "Stage": "SST_SCALE_IMAGE"
        },
        {
          "Stage": "SST_CONVERT_TO_GRAYSCALE"
        },
        {
          "Stage": "SST_TRANSFORM_GRAYSCALE"
        },
        {
          "Stage": "SST_ENHANCE_GRAYSCALE"
        },
        {
          "Stage": "SST_BINARIZE_IMAGE"
        },
        {
          "Stage": "SST_DETECT_TEXTURE"
        },
        {
          "Stage": "SST_REMOVE_TEXTURE_FROM_GRAYSCALE"
        },
        {
          "Stage": "SST_BINARIZE_TEXTURE_REMOVED_GRAYSCALE"
        },
        {
          "Stage": "SST_FIND_CONTOURS"
        },
        {
          "Stage": "SST_DETECT_SHORTLINES"
        },
        {
          "Stage": "SST_ASSEMBLE_LINES"
        },
        {
          "Stage": "SST_DETECT_TEXT_ZONES"
        },
        {
          "Stage": "SST_REMOVE_TEXT_ZONES_FROM_BINARY"
        }
      ],
      "Name": "IP_0"
    }
  ],
  "TargetROIDefOptions": [
    {
      "Name": "roi_default",
      "TaskSettingNameArray": [
        "dbr_task_0"
      ]
    }
  ]
}

Notes

  • StandardFormat selects the base symbology (BF_CODE_39).
  • HeadModuleRatio and TailModuleRatio define the start and stop characters. From the Code 39 character table:

      131113131 → +, 131111313 → -.
    

Now modify the Python code to read the nonstandard 1D barcodes.

from dynamsoft_capture_vision_bundle import *

json_file = None
 
if special_character == '+':
    json_file = r"template_plus.json"
 
if special_character == '-':
    json_file = r"template_minus.json"
 
if json_file == None:
    return
 

license_key = "LICENSE-KEY" 
cvr_instance = CaptureVisionRouter()
error_code, error_message = LicenseManager.init_license(license_key)

cvr_instance.init_settings_from_file(json_file) 
result = cvr_instance.capture(filename, "") # The empty string means using the default template

if result.get_error_code() != EnumErrorCode.EC_OK:
    print("Error:", result.get_error_code(),
            result.get_error_string())
else:
    items = result.get_items()
    print('Found {} barcodes.'.format(len(items)))
    for item in items:
        format_type = item.get_format_string()
        text = item.get_text()
        print("Barcode Format:", format_type)
        print("Barcode Text:", text)

        location = item.get_location()
        x1 = location.points[0].x
        y1 = location.points[0].y
        x2 = location.points[1].x
        y2 = location.points[1].y
        x3 = location.points[2].x
        y3 = location.points[2].y
        x4 = location.points[3].x
        y4 = location.points[3].y
        print("Location Points:")
        print("({}, {})".format(x1, y1))
        print("({}, {})".format(x2, y2))
        print("({}, {})".format(x3, y3))
        print("({}, {})".format(x4, y4))
        print("-------------------------------------------------")

nonstandard 1D barcode recognition

Source Code

https://github.com/yushulx/python-barcode-qrcode-sdk/tree/main/examples/official/nonstandard_1D_barcode