How to Scan Barcodes in Jupyter Notebook Using Python and OpenCV

Jupyter Notebook is a web-based interactive computing environment that lets you combine live code, equations, visualizations, and narrative text in a single document. If you have Anaconda installed, Jupyter Notebook is included by default. This tutorial walks you through building a Python barcode scanner inside a Jupyter Notebook — upload an image, decode every barcode in it, and display the annotated results inline.

What you’ll build: An interactive Jupyter Notebook that accepts image uploads via a widget button, scans all barcodes and QR codes using Dynamsoft Barcode Reader and OpenCV, and renders annotated results side-by-side with Matplotlib.

Key Takeaways

  • Dynamsoft Barcode Reader’s Python SDK can decode 1D/2D barcodes from image files inside a Jupyter Notebook in a single API call via CaptureVisionRouter.
  • The ipywidgets.FileUpload widget provides a zero-JavaScript way to accept image uploads directly in a notebook cell.
  • OpenCV handles image decoding and barcode-location overlay drawing, while Matplotlib renders the before/after comparison inline.
  • This approach works in both classic Jupyter Notebook and JupyterLab with no extra frontend extensions required.

Common Developer Questions

  • How do I scan barcodes from an uploaded image in Jupyter Notebook using Python?
  • What Python library can decode QR codes and 1D barcodes inside a Jupyter Notebook cell?
  • How do I display barcode detection results with bounding boxes in Jupyter Notebook?

Prerequisites

Build a Barcode Scanner in Jupyter Notebook

  1. Run Jupyter notebook:

    Jupyter notebook

  2. Open http://localhost:8888/ in your browser to create a barcode_scanning.ipynb file.

    new Jupyter notebook

  3. Insert a new cell to install Dynamsoft Barcode Reader, OpenCV, and Matplotlib:

     %pip install dynamsoft-barcode-reader-bundle opencv-python matplotlib
    
  4. Initialize the license of barcode SDK and barcode reader object:

     from dynamsoft_capture_vision_bundle import *
     license_key = "LICENSE-KEY"
     error_code, error_message = LicenseManager.init_license(license_key)
     cvr_instance = CaptureVisionRouter()
    
  5. Create an image upload button in Jupyter notebook:

     from ipywidgets import FileUpload
     def on_upload_change(change):
         if change.name != "value":
             return
         if not change.new:
             return
        
         up = change.owner
         files_obj = change.new
        
         records = list(_flatten_records(files_obj))
        
         for rec in records:
             try:
                 content = _get_bytes(rec)  
             except Exception as e:
                 print("Skip unsupported record:", e)
                 continue
        
             buf = np.frombuffer(content, dtype=np.uint8)
             img = cv.imdecode(buf, cv.IMREAD_COLOR)
             if img is None:
                 print("Failed to decode image.")
                 continue
        
             new_img = img.copy()
             try:
                 decode(new_img)
             except Exception as e:
                 print("Decode error:", e)
        
             img_rgb = cv.cvtColor(img, cv.COLOR_BGR2RGB)
             new_rgb = cv.cvtColor(new_img, cv.COLOR_BGR2RGB)
             show_image(img_rgb, new_rgb)
        
         try:
             up.unobserve(on_upload_change, names="value")
         except Exception:
             pass
        
         reset_done = False
         for val in ((), [], None):
             try:
                 up.value = val
                 reset_done = True
                 break
             except Exception:
                 continue
         if not reset_done:
             try:
                 up.value.clear()
                 reset_done = True
             except Exception:
                 pass
        
         try:
             up.observe(on_upload_change, names="value")
         except Exception:
             pass
        
     uploader = FileUpload(accept='image/*', multiple=True) 
     uploader.observe(on_upload_change, names="value")
     uploader
    
  6. Convert the image data to numpy array and then decode the image with OpenCV API:

     import cv2 as cv
     import numpy as np
    
     for rec in records:
         try:
             content = _get_bytes(rec)  
         except Exception as e:
             print("Skip unsupported record:", e)
             continue
    
         buf = np.frombuffer(content, dtype=np.uint8)
         img = cv.imdecode(buf, cv.IMREAD_COLOR)
    
  7. Scan barcodes with Dynamsoft Barcode Reader API:

     def decode(frame):
         before = time.time()
         result = cvr_instance.capture(frame, EnumPresetTemplate.PT_READ_BARCODES.value)
         after = time.time()
        
         COLOR_RED = (0, 0, 255)
         thickness = 2
         text_x, text_y = 10, 20
        
         if result.get_error_code() != EnumErrorCode.EC_OK:
             print("Error:", result.get_error_code(), result.get_error_string())
             cv.putText(frame, f'{after - before:.2f} s, barcode found: 0', (text_x, text_y),
                        cv.FONT_HERSHEY_SIMPLEX, 0.5, COLOR_RED)
             return
        
         items = result.get_items()
         found = len(items)
         for item in items:
             format_type = item.get_format()
             text = item.get_text()
             print(f'Format: {format_type}, Text: {text}')
             loc = item.get_location()
             pts = np.array([[p.x, p.y] for p in loc.points], dtype=np.int32)
             cv.drawContours(image=frame, contours=[pts], contourIdx=-1,
                             color=COLOR_RED, thickness=thickness, lineType=cv.LINE_AA)
             cv.putText(frame, f'{format_type}', (pts[0][0], pts[0][1] - 10),
                        cv.FONT_HERSHEY_SIMPLEX, 0.5, COLOR_RED)
             cv.putText(frame, f'{text}', (pts[0][0], pts[0][1] - 30),
                        cv.FONT_HERSHEY_SIMPLEX, 0.5, COLOR_RED)
         cv.putText(frame, f'{after - before:.2f} s, barcode found: {found}', (text_x, text_y),
                    cv.FONT_HERSHEY_SIMPLEX, 0.5, COLOR_RED)
            
     new_img = img.copy()
     decode(new_img)
    
  8. Display the barcode recognition results with Matplotlib:

     import matplotlib.pyplot as plt
    
     def show_image(img1, img2):
         fig = plt.figure(figsize=(18, 8))
         ax1 = fig.add_subplot(1, 2, 1)
         ax1.set_title('Input image', fontsize=14)
         ax1.axis('off')
         ax2 = fig.add_subplot(1, 2, 2)
         ax2.set_title('Barcode Recognition', fontsize=14)
         ax2.axis('off')
         ax1.imshow(img1)
         ax2.imshow(img2)
         plt.show()
    

    Scan barcodes in Jupyter Notebook

Common Issues and Edge Cases

  • “License has expired” or “License invalid” error: Ensure you have replaced "LICENSE-KEY" with a valid trial or purchased license key. Trial keys expire after 30 days — request a new one from the Dynamsoft License Portal.
  • FileUpload widget does not appear: The ipywidgets package must be installed and the Jupyter Notebook extension enabled. Run %pip install ipywidgets and restart the kernel. In JupyterLab, you may also need jupyter labextension install @jupyter-widgets/jupyterlab-manager.
  • cv.imdecode returns None: This typically means the uploaded file is not a valid image or is corrupted. Verify the file format (JPEG, PNG, BMP are supported) and ensure the file is not zero-length.

Source Code

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