MilleVisionNotes

This site focuses on practical examples of controlling Basler industrial cameras
using the pylon SDK and C#, based on real-world development experience.

タグ: WPF

  • Implementing Background Subtraction (Motion Detection) in WPF with Basler pylon SDK + OpenCV (C# / .NET 8)

    Implementing Background Subtraction (Motion Detection) in WPF with Basler pylon SDK + OpenCV (C# / .NET 8)

    Once your live view is working, a natural next step is highlighting only what moved. In this article, we implement a simple background subtraction pipeline to detect motion regions, draw bounding boxes, and display the results in a WPF Image.


    ✅ Environment

    Because this implementation converts between BitmapSource and Mat, install the NuGet package:

    • OpenCvSharp4.WpfExtensions
    Item Details
    Camera Basler acA2500-14gm
    SDK pylon Camera Software Suite
    Language / GUI C# / .NET 8 / WPF
    Libraries OpenCvSharp4 (OpenCvSharp4.Windows, OpenCvSharp4.WpfExtensions)

    Recommended camera settings (for stable subtraction): Set ExposureAuto=Off, GainAuto=Off, and keep illumination stable (reduce flicker).

    Prerequisites from earlier posts (reference):


    Implementation Overview

    We will follow this workflow:

    1. Capture a background frame (a frame with no motion)
    2. Preprocess with Gaussian blur
    3. Compute absolute difference (AbsDiff) → threshold (Threshold) → opening (MorphologyEx(Open))
    4. Extract contours (FindContours) → draw bounding rectangles
    5. Display the processed frame in WPF

    Adding opening after threshold helps remove small speckle noise.


    🧩 XAML (Minimal UI)

    Add one column for a “Set BG” button and sliders for tuning.

    BackgroundSubtraction_View


    🔧 Core Code (Background Subtraction Pipeline)

    This logic ideally belongs in the Model layer, but to keep diffs small from previous articles, it is implemented in the ViewModel.

    The author tested on a Mono8 camera. If you use a color camera, convert to grayscale as needed.

    The ViewModel implements IDisposable to ensure OpenCV Mat resources are released.


    Code-Behind

    Dispose the ViewModel when the window closes.


    Example Run

    1. Click Set BG to capture the background frame.

    BackgroundSubtraction_BG 2. Move an object in the scene → motion regions are detected and boxed. 3. Use sliders to tune sensitivity and minimum area.

    BackgroundSubtraction_Detect


    Tuning Tips

    • Retake background when illumination changes

    • Threshold: increase to suppress sensor noise; decrease to detect subtle motion

    • Morphology iterations: increase if edges are jagged; decrease if boxes “bloat”

    • Min area: simple filter to reduce false positives

    • Speed-ups:

      • Apply camera ROI to reduce the processed area
      • Cv2.Resize to process a smaller image (scale coordinates back)
      • Cache blurred background (as shown) to avoid blurring every frame

    Common Pitfalls

    Symptom Likely Cause Fix
    Nothing detected Threshold too high / changes too small Lower threshold or increase blur kernel
    Entire frame white Auto exposure/gain is fluctuating Set ExposureAuto/GainAuto=Off, stabilize lighting
    Too many speckles Sensor noise / tiny vibration Keep opening (MorphTypes.Open) and tune kernel
    UI freezes Processing too heavy Move processing to another Task, use ROI / resize
    Memory grows Mat.Dispose() missing Use using blocks (as shown) and cache carefully

    Summary

    • Background subtraction highlights only moving regions
    • Fixed exposure/gain + stable lighting improves reliability
    • Tune threshold, minimum area, and morphology to balance sensitivity vs noise
    • ROI and resizing are effective for performance
  • Zoom & Pan for WPF Live View Using TransformGroup (C# / .NET 8)

    Zoom & Pan for WPF Live View Using TransformGroup (C# / .NET 8)

    In the previous article, we built a minimal setup to overlay a HUD (FPS, exposure, gain) on top of live video. As a continuation, this article adds mouse-driven zoom/pan, an ROI rectangle that follows the image, and a crosshair fixed to the screen center.

    We keep the same layer-separated design (Video = zoom/pan, HUD = fixed) to minimize blur and jitter.


    Environment / Prerequisites


    Goals

    • Mouse wheel zoom centered at the cursor (1.1× per step)
    • Shift + drag (or middle button drag) to pan
    • ROI rectangle scales/moves with the image (follows zoom/pan)
    • Crosshair stays fixed in screen coordinates (HUD layer)

    XAML: Two Layers + ROI Layer (Shared Transform)

    Because the implementation has grown, some parts are omitted where appropriate.


    HalfConverter (For Center Crosshair)

    This converter makes it easy to draw lines centered in the HUD layer.


    Code-Behind: Zoom / Pan

    In this article, zoom and pan are implemented purely in code-behind. You can refactor into ViewModel/Model later if needed.


    ROI Handling and Applying It in Real Apps

    In this sample, we assign the same TransformGroup to both the Image and the RoiLayer.

    • Because RoiLayer shares the transform, it naturally follows zoom/pan.
    • In real applications, you typically bind Canvas.Left/Top/Width/Height of RoiRect to a ViewModel, then apply those values to camera ROI parameters.
    • When applying ROI to the camera, remember GenICam constraints such as width/height increments.

    Meanwhile, HUD elements (crosshair, texts) remain transform-free and screen-fixed, preventing blur and keeping interaction intuitive.


    Example Screens

    The UI looks like this:

    ROIZoomDefault.png

    Pan the live view by dragging while holding Shift. The ROI follows; the crosshair stays fixed.

    ROIZoomTrans.png

    Zoom with the mouse wheel. The zoom ratio in the upper area updates as well.

    ROIZoomZoom.png

    Use Fit to fit the image to the window. 1:1 sets the zoom to 1.0, and Reset returns zoom to 1.0 and pan offset to 0.

    ROIZoomFit.png


    Summary

    • Video + ROI share the same transform; HUD stays fixed (layered design)
    • Mouse interaction provides cursor-centered zoom and intuitive pan
    • ROI follows the image while the crosshair remains screen-fixed

  • Overlaying a HUD on Basler Live View in WPF (FPS, Exposure, Gain) — Dual-Layer UI Layout

    Overlaying a HUD on Basler Live View in WPF (FPS, Exposure, Gain) — Dual-Layer UI Layout

    Once you have a working live preview, the next step is showing camera state in a readable way—especially when screen space is limited (embedded displays, lab setups, compact inspection tools).

    In this article, we overlay a HUD (FPS, exposure, gain, crosshair, etc.) on top of a Basler live view in WPF. Instead of drawing text directly onto the image (which can blur or jitter during zoom/pan), we use a layer-separated approach: an image layer for the video and a transparent HUD layer that stays fixed in screen coordinates.

    This structure is also a solid foundation for future features such as:

    • ROI (Region of Interest) editing in the GUI
    • Capturing and saving “image + HUD” using RenderTargetBitmap

    Environment / Assumptions

    • Basler pylon Camera Software Suite (Basler.Pylon referenced)
    • .NET 8 / WPF (Windows desktop)
    • Camera: acA2500-14gm (assume Mono8)

    Goal

    Building on the previous live-view article, we add:

    • A two-layer layout: Video layer (Image) + HUD layer (transparent Grid)
    • The HUD is fixed to screen coordinates (does not follow zoom), so text does not blur/jitter
    • FPS calculated continuously but UI-updated at ~10 Hz, plus exposure/gain display
    • A design that can later evolve into HUD-included capture via RenderTargetBitmap

    XAML: Dual Layer (with Optional ROI Layer)

    Inside the display Grid, we stack multiple layers:

    • Video layer (can be zoomed/panned in future)
    • ROI layer (optional, follows the image)
    • HUD layer (screen-fixed overlay)
    • NearestNeighbor is good when you want pixel-accurate rendering.
    • Set IsHitTestVisible="False" so the HUD doesn’t steal mouse input (important for future zoom/pan).

    ViewModel: Throttled FPS Updates + Exposure/Gain HUD

    We extend the previous live-view ViewModel with:

    • FPS measurement using a Stopwatch
    • HUD updates throttled to ~10 Hz
    • Exposure and gain values displayed alongside FPS

    Connect / Disconnect are omitted here—refer to your earlier WPF snapshot article.


    Example Output

    You’ll see FPS, exposure, and gain values displayed in the upper-left corner of the live preview. Live view makes FPS variations surprisingly fun to watch—feel free to customize your HUD further (movable HUD, crosshair, etc.).

    HUD sample


    Common Pitfalls & Fixes

    • Text looks blurry/jitters → Keep HUD on a separate layer (screen-fixed). Enable UseLayoutRounding, SnapsToDevicePixels, and ClearType settings.

    • UI is sluggish → Update video quickly; throttle HUD updates to ~10 Hz. Do heavy work (saving/analysis) on background threads.

    • Event handler registered twice → Always do -= then += in Start(), and unsubscribe in Stop() / Disconnect().


    Summary

    • Implemented a dual-layer UI: image layer + HUD layer
    • HUD stays fixed in screen coordinates, making it stable during future zoom/pan
    • Displayed FPS, exposure, and gain, with FPS refreshed at ~10 Hz
    • Ready for extensions like ROI overlays and HUD-included capture with RenderTargetBitmap
  • Implementing Live View in a WPF App for Basler Cameras (pylon SDK / C# / .NET 8)

    Implementing Live View in a WPF App for Basler Cameras (pylon SDK / C# / .NET 8)

    In the previous article (Displaying a Basler Camera Snapshot in a WPF App), we captured a single frame and displayed it in a WPF Image. This time, we’ll implement a live camera preview inside a WPF window.

    The live view uses an event-driven approach: we receive frames via ImageGrabbed, convert them to BitmapSource, and update an Image control. The update is performed safely via the Dispatcher to avoid blocking or crashing the UI thread.


    Environment / Assumptions

    • Basler pylon Camera Software Suite (reference Basler.Pylon)
    • .NET 8 / WPF (Windows desktop)
    • Camera: acA2500-14gm (assumed Mono8) If you use a color camera, you must convert based on pixel format such as BGR8packed.

    Goal

    • Live preview controlled by Connect / Start / Stop / Disconnect
    • Smooth updates by continuously refreshing a BitmapSource bound to an Image
    • Safe UI updates (always via the Dispatcher)

    UI (XAML)

    GUILiveSampleXAML

    We add two buttons: Live (start preview) and Stop (stop preview).

    The code-behind is the same as in the previous article (set DataContext to the ViewModel and disconnect on closing).


    Model Side (BaslerCameraSample)

    If we reuse the previous StartGrabbing() implementation, frames keep piling up in ConcurrentQueue<(DateTime, IGrabResult)> _bufferedImageQueue, which is great for async saving but makes live view unnecessarily complex.

    So, we add a simple streaming method dedicated to live display:

    Add/Remove event handlers

    To keep the design flexible, we expose methods to attach/detach ImageGrabbed handlers:


    ViewModel: Event-Driven Preview → Update BitmapSource

    We continue using BaslerCameraSample, but now we update CurrentFrame whenever ImageGrabbed fires.

    If performance becomes an issue, consider using WriteableBitmap rather than creating a new BitmapSource every time.


    Example Run

    Click Connect, then Live to start continuous preview. Click Stop to stop streaming.

    GUILiveSample


    Common Pitfalls & Fixes

    • Colors look wrong (color cameras) Match conversion to the camera’s pixel format (e.g., PixelType.BGR8packed and PixelFormats.Bgr24).

    • Event handler registered twice Remove (-=) once before adding (+=), as shown in Start().

    • Rendering can’t keep up with camera FPS If the camera FPS is high, you often don’t need to render every frame. You can drop frames by using Monitor.TryEnter or Interlocked.Exchange to avoid overlapping UI updates.


    Summary

    • Implemented smooth live view using pylon’s event-driven acquisition
    • Updated WPF UI safely through the Dispatcher
    • The structure is flexible and works well with ROI and resolution changes
    • Combining live preview with triggers is already valuable for many lab/inspection setups

    Next: HUD Overlay

    In the next article, we will overlay a HUD showing values such as FPS, exposure time, and gain on top of the live preview.