Vision Systems & Engineering

Industrial Machine Vision

The system engineering of vision on the factory floor, covering machine-vision cameras and their interfaces, GenICam, triggering from encoders and line-scan acquisition, strobed lighting and optics selection, integration with PLCs and robots, gauging and measurement uncertainty in production, and smart cameras against PC-based systems.

intermediate

Industrial machine vision is the engineering of camera systems that work inside a production line: they take an image when a part is in place, judge or measure it within the time before the next part arrives, and pass the result to the machine that sorts, rejects or picks the part. Industrial visual inspection describes what such a system decides, from defect detection to anomaly models and their escape and false-reject rates. This article is about the system around those decisions: the camera and its interface, the trigger that ties each image to a position on the line, the light pulse that freezes motion, the I/O and networks that connect the station to programmable logic controllers (PLCs) and robots, the calibration that turns pixels into millimetres, and the evidence that a measurement is good enough for the tolerance it checks.

Much of this is set by standards: GenICam, from the European Machine Vision Association (EMVA), names the triggers, encoders, timers and I/O lines that a factory system wires together (SFNC 2.8), EMVA 1288 fixes how camera sensitivity and noise are reported, and metrology’s guides govern uncertainty and gauge studies (JCGM 100:2008; NIST/SEMATECH e-Handbook, Section 2.4).

Problem

A factory vision station has to produce a correct result for every part, at line rate, for years. Three requirements separate it from a model running on stored images:

  • Time and position. Each image must show the part at a known place on the conveyor, and the result must reach the reject gate or robot before the part has moved past it, so the camera is triggered by the line and each result is tied to its part.
  • Integration. The station receives triggers and recipe changes from a PLC, returns pass or fail signals, measurements and positions, and in robot cells gives pick positions in the robot’s own coordinates.
  • Measurement quality. A station that measures is used like a calliper, so it needs a known scale, a known uncertainty and evidence that it repeats from shift to shift.

Designing a computer vision system gives the general method from requirements to sensor, optics, lighting, compute and model, including the arithmetic that turns a tolerance into a pixel size and an object speed into an exposure time; the sections below follow the decisions specific to factory systems.

Visual Data

The images are designed rather than found: frames from a fixed camera under controlled light, a continuous image built line by line, or height maps from triangulation sensors. The engineer chooses the camera class, its interface, and the lighting and optics as parts of a timed system.

Cameras

Machine-vision cameras let the system fix exposure, gain and processing, start frames on an external signal and attach metadata to each frame; the digital camera article describes these features and the shutter modes, and the image sensor and exposure articles the trade-offs of short exposures on moving parts.

Two choices are structural. An area-scan camera captures a frame of W×HW \times H pixels per trigger. A line-scan camera has one row of pixels (or a few) and builds the image as the part moves past it; GenICam keeps the notion of a frame but performs the exposure and readout for each line of this virtual frame, with a separate LineStart trigger per line (SFNC 2.8, Section 5.1). Line-scan suits webs such as film and textiles, long parts and rotated cylinders, since the image can be as long as the part and every line is seen under the same light and angle.

Camera datasheets that claim EMVA 1288 compliance report quantum efficiency, system gain, temporal dark noise, maximum signal-to-noise ratio, absolute sensitivity threshold, saturation capacity, dynamic range, dark-signal and photo-response nonuniformity, non-linearity and dark current, measured by one procedure (EMVA 1288, Table 2 and Section 10.2). The standard describes itself as particularly useful to those who compare cameras or calculate system performance from a sensor’s or camera’s specifications (EMVA 1288, About this Standard), and it treats line-scan sensors like area-scan ones, by acquiring at least 100 lines into one image (Section 5).

Interfaces

The interface sets bandwidth, cable length, whether a frame grabber is needed and how triggers reach the camera. GenICam lists five interface technologies as transport layers a device can report: GigE Vision, Camera Link, Camera Link HS, CoaXPress and USB3 Vision (SFNC 2.8, Section 3.24). The table gives what each standard’s public descriptions state, as dated; a dash means that none of the sources used here states it.

Interface Physical link As stated in public sources
GigE Vision Gigabit Ethernet Transmission up to 100 m and multi-camera systems on a standard PC interface; standardization managed by AIA (JIIA, accessed October 2026). A draft of SFNC 1.5.2 (January 2012) added support for GigE Vision 2.0, including link aggregation, IEEE 1588 and scheduled action commands (SFNC 2.8, document history)
USB3 Vision USB 3.0 Uses the 5 Gbps transfer rate of a standard PC interface; support for newer USB standards is under consideration (JIIA, accessed October 2026)
Camera Link Cable to a frame grabber Described by JIIA as the first digital interface standard designed for machine vision, maintained and administered by A3; JIIA’s working group added Power over Camera Link (PoCL) and PoCL-Lite, and version 2.1 fixed a connector problem (JIIA, accessed October 2026). Camera control lines CC1 to CC4 map lines on the frame grabber to the camera and can serve as trigger sources (SFNC 2.8, Section 5.6.4)
Camera Link HS — Named by JIIA among the high-speed interfaces proposed through the coordination of AIA, EMVA and JIIA (accessed October 2026)
CoaXPress Coaxial cable between camera and frame grabber One coaxial cable carries image data at up to 12.5 Gbps and camera control at the same time; a CoaXPress-over-fibre protocol option; specifications drafted by JIIA’s CoaXPress Working Group (JIIA, accessed October 2026). SFNC release 2.0 (October 2012) added CoaXPress-specific features (SFNC 2.8, document history)

The table summarizes scope; it does not rank. Bandwidth, cable count and length, the need for a frame grabber and host load all enter the choice. JIIA describes GigE Vision and USB3 Vision as using standard PC interfaces; it follows (reasoning, not a statement of the standards) that their frames arrive through the host’s own network or USB stack, while a frame-grabber interface uses a point-to-point cable into a dedicated card, which bears on how predictable delivery is.

GenICam sits above all of them. Besides GenApi’s self-describing device files, the SFNC and the GenTL transport-layer interface, which the digital camera article introduces, the EMVA lists GenDC, a data container for 2D, 3D, multispectral and metadata payloads; GenCP, a control-packet format that interface standards can reuse; and CLProtocol, which adds GenICam to Camera Link (EMVA, GenICam Introduction). Station software written against SFNC names such as TriggerSource or ExposureTime can move between cameras and interfaces with fewer changes, as far as the cameras implement the same features.

Lighting and optics as system decisions

The physics and the catalogue of lighting geometries (bright field, dark field, back light, coaxial, dome) and of telecentric lenses are in industrial visual inspection. At the system level, three further decisions follow from them:

  • Continuous or strobed. A light pulse shorter than the exposure freezes motion as well as a short exposure does, and lets the light be driven harder. The SFNC notes that lights pulsed briefly can be overdriven, in some cases to more than ten times their continuous brightness, provided a minimum delay between pulses protects them (SFNC 2.8, Section 22.2). The camera can fire the light by routing its exposure signal, or a timer started by the trigger, to an output line (SFNC 2.8, Sections 9.1 and 22.1). A bright, short pulse also makes changing ambient light a smaller share of each exposure (reasoning, not a cited result).
  • Which optics the measurement needs. For gauging, the choice between an ordinary and a telecentric lens decides whether a part’s height on the fixture changes its measured size; Designing a Computer Vision System works through how large that error is for an ordinary lens. Lens distortion that remains is removed by calibration.
  • Settings as a recipe. Light level, exposure and gain stay fixed. GenICam’s user sets save a camera configuration to the device’s non-volatile memory and load it on reset (SFNC 2.8, Section 2.14), tying the settings to the recipe.

Vision Tasks Involved

  • Inspection. Presence, assembly and surface-defect checks (industrial visual inspection).
  • Gauging and metrology. Widths, diameters, hole positions and gaps from sub-pixel edge detection on calibrated images, compared with tolerances.
  • Identification. Reading printed codes and text with optical character recognition and decoding 1D and 2D codes, for traceability.
  • Robot guidance. Locating parts in a plane or in 3D and passing their position and orientation to a robot for picking, placing or assembly.
  • Sorting and counting. Classifying parts by type, colour or size for routing.

Common Methods

Triggering

The SFNC models acquisition as a hierarchy of acquisitions, bursts, frames and lines, each with start and end signals. A trigger is selected for one of these events (FrameStart, LineStart, ExposureStart and others) and given a source: software, an input line, a timer, a counter, an encoder or an action signal (SFNC 2.8, Sections 5.1 and 5.6). TriggerDelay lets a camera fire when a part that tripped a sensor upstream reaches the field of view, and TriggerDivider and TriggerMultiplier change the ratio of accepted triggers (Section 5.6).

A camera can only start a new frame or line when its sensor is ready. TriggerOverlap defines when the next trigger is accepted: not before the previous frame has ended, during the readout of the previous one, or at any time after its start; a trigger that arrives earlier is discarded as a missed trigger, which the SFNC calls an over-triggering situation, typically treated as an error that can raise an event (SFNC 2.8, Section 5.6). Each missed trigger is a part or a line not imaged.

Encoders and line-scan acquisition

A free-running line-scan camera takes lines at a fixed rate, AcquisitionLineRate in GenICam (SFNC 2.8, Section 5.2), so a change of belt speed stretches or compresses the image along the motion. The remedy is to take lines at equal steps of distance. A quadrature encoder on the conveyor or a roller produces two phase-shifted signals, A and B; GenICam’s encoder control drives a position counter with them that counts up or down with the direction of motion, and outputs a pulse every EncoderDivider counts, which becomes the line trigger (SFNC 2.8, Section 11.1). Its output modes decide what happens when the belt briefly runs backwards: in Position mode no lines are taken until the belt has passed the point where the reversal started, so the image looks as though the motion had only gone forward; Direction mode triggers only on motion in one direction; Motion mode triggers in both (SFNC 2.8, Section 11.1). A four-phase mode filters jitter between encoder states by counting once per A–B cycle; a high-resolution mode counts every transition, unfiltered.

The encoder fixes the line pitch along the motion; the optics fix the pixel pitch across it. Matching the two, so that pixels are square on the part, is a configuration step: with an encoder step of 0.025 mm and a divider of 4, a line is taken every 0.1 mm, and the lens should then image 0.1 mm onto one pixel. The exposure of each line must also end before the next line starts, so the shortest line period at the fastest belt speed caps the exposure time (reasoning from the acquisition model, which starts each line’s exposure on its trigger).

Synchronizing several devices

Several cameras, or a camera and a strobe, can share a hardware trigger line. GenICam’s action signals trigger several devices at once through a protocol message, on most transport layers a broadcast, filtered by a device key, a group key and a group mask, for example to start a frame on every camera of a group (SFNC 2.8, Section 14.1); the same mechanism can start a timer that generates a strobe pulse on an output line. Real-time vision pipelines explains timestamps and clock synchronization with the Precision Time Protocol, and how to measure the delays they reveal.

Integration with PLCs and robots

A station exchanges results with the line in three ways, often together:

  • Digital I/O. Each camera line can be an input or an output, with its source chosen among the exposure signal, timers, counters, encoder outputs and user-set output bits, and its electrical format declared as, for example, TTL, LVDS, RS422, opto-coupled or open drain (SFNC 2.8, Sections 9.1 and 9.2). A pass/fail output to the PLC or a reject gate is the simplest integration.
  • Industrial Ethernet and fieldbus. PLCs exchange cyclic data with devices over industrial networks such as PROFINET and EtherNet/IP. ODVA describes EtherNet/IP as standard Ethernet and TCP/IP with the Common Industrial Protocol (CIP) on top, using UDP for real-time cyclic data (ODVA, EtherNet/IP); PROFIBUS & PROFINET International publishes PROFINET (PI, PROFINET technology).
  • Information models. OPC UA for Machine Vision (OPC 40100-1, 2019), published by the OPC Foundation, specifies an information model for a machine vision system so that it can exchange information with another vision system, a station PLC, a line controller, or manufacturing execution, SCADA and enterprise systems; its title lists control, configuration management, recipe management and result management (OPC 40100-1, Scope).

Robot guidance adds geometry. For parts lying on a plane, a homography between the image and the robot’s work plane, estimated from points the robot has touched or from a calibrated target, turns image positions into robot coordinates. For parts in 3D, the part’s pose is estimated from 2D–3D correspondences with perspective-n-point or from a height map or point cloud, for example by iterative closest point against the part’s model, and then expressed in the robot’s frame.

That last step needs the transform between the camera and the robot. When the camera rides on the robot’s hand, hand–eye calibration estimates the fixed transform XX between the hand frame and the camera frame. Moving the robot between two positions gives the hand motion BB from the robot’s kinematics and the camera motion AA from images of a fixed calibration target, and the three are related by

AX=XB,AX = XB,

where all three are 4×44 \times 4 rigid transforms (Horaud & Dornaika, 1995, Section 2.1). Early solutions, among them those of Shiu and Ahmad (1989) and Tsai and Lenz (1989), split it into an equation in the rotation alone and one in the rotation and translation, as Horaud and Dornaika (1995, Section 3) summarize them; Horaud and Dornaika note that these authors found at least three robot positions, two independent motions, necessary for a unique solution. They also proposed a formulation using the camera’s 3×43 \times 4 projection matrices directly, and found non-linear optimization of rotation and translation together the most accurate in their stability analysis and experiments, with the Tsai–Lenz linear method and their closed-form method comparable to each other; with real data the linear and closed-form methods sometimes estimated rotation better, because they estimate it independently of the robot’s translations, which carry the errors of its imperfect kinematic calibration (Horaud & Dornaika, 1995, Sections 6–8). The camera’s intrinsics come first, from camera calibration. Closing the loop on image measurements during the motion itself is visual servoing.

Gauging and calibration in production

A gauge measures a feature in pixels and converts it to millimetres. The pixels come from sub-pixel edge positions: the edge is located where the image gradient across it peaks, refined between pixels by fitting a parabola to the gradient around the peak, as in the Canny edge detector, or by fitting an edge model. Lines fitted through edge points of many rows average the noise and absorb a small tilt.

The millimetres come from calibration. With a telecentric lens, a single scale factor from a reference part of certified size may be enough; with an ordinary lens, a full camera calibration with lens distortion correction maps image points to a known plane. In production the reference is measured again at intervals, so drift is corrected rather than accumulated. The NIST/SEMATECH e-Handbook defines bias as the difference between the measurement result and its unknown true value, which can often be estimated or removed by calibration to a reference standard, and warns that a calibration made in an ideal environment does not ensure that the gauge behaves the same way in its working environment, where temperature, humidity, operator, wear and other factors can bias it (Section 2.4.5).

Smart cameras and PC-based systems

Vision hardware for the line comes in three broad classes. A smart camera puts the sensor, a processor, the I/O and often the lighting control in one housing, configured from a tool and running one inspection program; the EMVA’s GenICam page describes processing the image, appending results to the image data stream, controlling external hardware and doing the real-time part of an application as common tasks of machine-vision cameras (EMVA, GenICam). A vision controller or embedded box serves several cameras from one industrial computer. A PC-based system connects cameras over GigE Vision or USB3 Vision, or through a frame grabber for Camera Link and CoaXPress, to a general-purpose computer, often with a GPU.

Reasoning from their structure rather than from a published comparison: a smart camera needs no host and has few parts to fail, but fixed compute and memory; a PC runs larger models and combines many cameras, at the cost of an operating system, drivers and a link between sensor and decision. Edge inference describes the hardware classes for running learned models near the sensor.

Example

Line-scan acquisition with and without an encoder

The first script simulates a line-scan camera with a 0.1 mm pixel pitch imaging a part with ten 3 mm dots printed every 5 mm along the motion. A free-running camera runs at 5 kHz, the rate that gives a 0.1 mm line pitch at the nominal 500 mm/s; an encoder triggers a line every 0.1 mm of travel, and a trigger that arrives before the camera is ready (above 6 kHz) is missed. The belt runs at constant speeds from 0.8 to 1.3 times nominal and with a ±20% sinusoidal swing. The script converts lines to millimetres at the nominal pitch and reports the dot spacing and each dot’s aspect ratio from intensity-weighted second moments.

import numpy as np
from scipy import ndimage as ndi

PITCH = 0.1                         # mm: pixel pitch across the belt, and the intended line pitch along it
V_NOM = 500.0                       # mm/s: nominal conveyor speed
F_FREE = V_NOM / PITCH              # free-running line rate, set for the nominal speed: 5 kHz
F_MAX = 6000.0                      # Hz: the camera's maximum line rate
ENC_STEP, ENC_DIV = 0.025, 4        # mm per encoder count; one line every 4 counts = 0.1 mm
T_EXP = 50e-6                       # s: exposure time of each line
DOTS = 10.0 + 5.0 * np.arange(10)   # dark printed dots every 5 mm along the part, radius 1.5 mm
NPIX = 160                          # pixels across the belt (16 mm)

def scene(x, y):
    """Reflectance at belt coordinates (mm): white part, dark dots centred at x = 8 mm."""
    r = np.ones((len(y), len(x)))
    for yc in DOTS:
        r[(x[None, :] - 8.0) ** 2 + (y[:, None] - yc) ** 2 < 1.5 ** 2] = 0.1
    return r

def belt(speed, t_max=0.2):
    """Belt position (mm) on a fine time grid, integrated from a speed profile v(t) in mm/s."""
    tt = np.linspace(0, t_max, 400001)
    return tt, np.concatenate([[0], np.cumsum(speed(tt[1:]) * np.diff(tt))])

def line_starts(speed, mode, length=65.0):
    """Start time of every line: a free-running clock, or encoder pulses limited by the max line rate."""
    tt, pos = belt(speed)
    if mode == "free":
        return np.arange(0, np.interp(length, pos, tt), 1 / F_FREE), 0
    trig = np.interp(np.arange(0, length, ENC_STEP * ENC_DIV), pos, tt)   # every 4 counts
    starts, last, missed = [], -1.0, 0
    for t in trig:                  # a trigger arriving before the camera is ready is missed
        if t - last >= 1 / F_MAX - 1e-12:
            starts.append(t); last = t
        else:
            missed += 1
    return np.array(starts), missed

def acquire(speed, mode):
    """Line-scan image: each line averages the scene over its exposure and its pixel height."""
    t0, missed = line_starts(speed, mode)
    tt, pos = belt(speed)
    ts = t0[:, None] + np.linspace(0, T_EXP, 5)[None, :]                     # sub-exposure instants
    ys = np.interp(ts, tt, pos)[:, :, None] + np.linspace(0, PITCH, 4, endpoint=False)
    xs = (np.arange(NPIX * 4) + 0.5) * PITCH / 4                              # 4 subsamples per pixel
    lines = scene(xs, ys.ravel()).reshape(len(t0), -1, len(xs)).mean(1)
    return lines.reshape(len(t0), NPIX, 4).mean(2), missed

def measure(img):
    """Dot spacing along the motion (mm, assuming the nominal 0.1 mm line pitch) and dot aspect ratios."""
    lab, n = ndi.label(img < 0.55)
    cy, aspect = [], []
    for k in range(1, n + 1):
        yy, xx = np.nonzero(lab == k)
        w = 1 - img[yy, xx]                                                    # darkness as weight
        my, mx = np.average(yy, weights=w), np.average(xx, weights=w)
        vy, vx = np.average((yy - my) ** 2, weights=w), np.average((xx - mx) ** 2, weights=w)
        cy.append(my * PITCH); aspect.append(np.sqrt(vy / vx))
    return np.diff(np.sort(cy)), np.array(aspect), n

profiles = {
    "constant 0.8 v": lambda t: 0.8 * V_NOM + 0 * t,
    "constant 1.0 v": lambda t: 1.0 * V_NOM + 0 * t,
    "constant 1.2 v": lambda t: 1.2 * V_NOM + 0 * t,
    "constant 1.3 v": lambda t: 1.3 * V_NOM + 0 * t,
    "sine 1 +/- 0.2": lambda t: V_NOM * (1 + 0.2 * np.sin(2 * np.pi * t / 0.05)),
}
print("speed profile  trigger | lines missed dots | spacing (mm) min..max | aspect min..max")
for name, v in profiles.items():
    for mode in ("free", "encoder"):
        img, missed = acquire(v, mode)
        sp, asp, n = measure(img)
        print(f"{name:14s} {mode:7s} | {len(img):5d} {missed:6d} {n:4d} |"
              f"   {sp.min():6.3f} .. {sp.max():6.3f}   |  {asp.min():5.3f} .. {asp.max():5.3f}")

Output (NumPy 2.3.5, SciPy 1.16.3; the simulation is deterministic, and two runs gave identical output):

speed profile  trigger | lines missed dots | spacing (mm) min..max | aspect min..max
constant 0.8 v free    |   813      0   10 |    6.244 ..  6.256   |  1.244 .. 1.247
constant 0.8 v encoder |   650      0   10 |    5.000 ..  5.000   |  0.998 .. 0.998
constant 1.0 v free    |   650      0   10 |    5.000 ..  5.000   |  0.999 .. 0.999
constant 1.0 v encoder |   650      0   10 |    5.000 ..  5.000   |  0.999 .. 0.999
constant 1.2 v free    |   542      0   10 |    4.166 ..  4.168   |  0.826 .. 0.833
constant 1.2 v encoder |   650      0   10 |    5.000 ..  5.000   |  1.001 .. 1.001
constant 1.3 v free    |   500      0   10 |    3.842 ..  3.852   |  0.760 .. 0.771
constant 1.3 v encoder |   325    325   10 |    2.500 ..  2.500   |  0.501 .. 0.501
sine 1 +/- 0.2 free    |   635      0   10 |    4.229 ..  5.820   |  0.843 .. 1.228
sine 1 +/- 0.2 encoder |   650      0   10 |    4.997 ..  5.003   |  0.998 .. 1.001
  • A free-running camera measures time, not distance. At constant speed the image scales along the motion by the inverse of the speed ratio: at 0.8 times nominal the 5 mm spacing reads as 6.25 mm and round dots become ellipses with an aspect ratio of 1.25; at 1.2 times nominal they shrink to 4.17 mm and 0.83. A constant error could be calibrated out, a varying one cannot: under the ±20% swing the same spacing reads from 4.23 to 5.82 mm within one image.
  • Encoder triggering makes the image a map of the belt. Lines are taken at the same belt positions whatever the speed, so line count, spacing and aspect ratio stay nominal. The small rise of the aspect ratio with speed comes from the exposure: in 50 µs the belt moves 20 µm at 0.8 times nominal and 30 µm at 1.2 times, against a 100 µm pixel.
  • Above the camera’s maximum line rate, the encoder fails worse than the clock. At 1.3 times nominal the encoder asks for 6.5 kHz: each trigger arrives 154 µs after the last, before the camera is ready at 167 µs, so every second one is missed and the image is half as long. The free-running camera degrades only in proportion to the speed. The missed-trigger count, which a camera can report as an event, is the signal that the line has outrun its vision system.

Repeatability and reproducibility of a gauge

The second script gauges a back-lit part 10.012 mm wide. The optics’ true scale, 0.0502 mm per pixel, is unknown to the gauge, which calibrates on a reference block certified at 15.000 mm. The images are area-sampled, blurred and given noise of 1% of full scale. Following the two-level nested design of the NIST/SEMATECH e-Handbook (Sections 2.4.3 and 2.4.4), each of five days starts with a recalibration, then the part is placed once (shift up to ±3 pixels, tilt up to ±0.5°, lighting ±10%) and imaged ten times. One gauge counts dark pixels on the centre row; the other locates both edges to sub-pixel precision in every row, fits a line to each and measures between them. The script reports the bias, the repeatability s1s_1 (pooled within-day standard deviation), the day-to-day component sdayss_{\text{days}} and the standard deviation of a single measurement, sR=sdays2+s12s_R = \sqrt{s_{\text{days}}^2 + s_1^2}, for five seeds.

import numpy as np
from scipy import ndimage as ndi

P_TRUE = 0.0502            # mm per pixel on the part: the optics' true scale, unknown to the gauge
W_REF = 15.000             # mm: certified width of the reference block used for calibration
H, W = 48, 400             # image rows and columns (back-lit: dark part on a bright background)

def render(rng, width, shift, tilt_deg, light, noise=0.01, blur=1.2, ss=8):
    """Back-lit silhouette of a part of the given width (mm), centred, shifted (px) and tilted."""
    y = (np.arange(H * ss) + 0.5) / ss - H / 2                      # supersampled pixel grid
    x = (np.arange(W * ss) + 0.5) / ss - W / 2
    th = np.radians(tilt_deg)
    u = (x[None, :] - shift) * np.cos(th) + y[:, None] * np.sin(th)  # coordinate across the part
    inside = np.abs(u) < width / P_TRUE / 2
    img = np.where(inside, 0.1, 0.9) * light
    img = img.reshape(H, ss, W, ss).mean((1, 3))                    # area sampling by each pixel
    img = ndi.gaussian_filter(img, blur)                            # optics and sensor blur
    return img + rng.normal(0, noise, img.shape)

def edges_subpixel(row):
    """Left and right edge positions (px) at the extreme gradients, refined by a parabola."""
    g = np.gradient(ndi.gaussian_filter1d(row, 1.0))
    out = []
    for i in (np.argmin(g), np.argmax(g)):                          # falling edge, rising edge
        a, b, c = g[i - 1], g[i], g[i + 1]
        out.append(i + 0.5 * (a - c) / (a - 2 * b + c))
    return out

def width_px(img, method):
    """Part width in pixels, perpendicular to the edges, from per-row edges and two fitted lines."""
    rows = np.arange(4, H - 4)                                      # skip rows touched by border effects
    if method == "pixel":                                           # count dark pixels on the centre row
        return np.sum(img[H // 2] < 0.5 * (img.max() + img.min()))
    el, er = np.array([edges_subpixel(img[r]) for r in rows]).T
    ml, cl = np.polyfit(rows, el, 1)
    mr, cr = np.polyfit(rows, er, 1)
    m = 0.5 * (ml + mr)
    return (np.polyval([mr, cr], H / 2) - np.polyval([ml, cl], H / 2)) / np.sqrt(1 + m * m)

def fixture(rng):
    """One placement of a part: random shift (px), tilt (deg) and lighting level."""
    return dict(shift=rng.uniform(-3, 3), tilt_deg=rng.uniform(-0.5, 0.5), light=rng.uniform(0.9, 1.1))

TRUE_W = 10.012                                                     # mm: the part under test
K, J = 5, 10                                                        # days, repeats per day
print("method   seed | mean (mm)  bias (mm) | s1 repeat  s_days    s_R (mm)")
for seed in range(5):
    for method in ("pixel", "subpixel"):
        rng = np.random.default_rng(seed)
        daily = []
        for day in range(K):
            f = fixture(rng)                                        # each day: recalibrate, refixture
            scale = W_REF / width_px(render(rng, W_REF, **f), method)   # mm per pixel from the block
            f = fixture(rng)
            daily.append([scale * width_px(render(rng, TRUE_W, **f), method) for _ in range(J)])
        Y = np.array(daily)                                         # K x J measurements (mm)
        s1 = np.sqrt(np.mean(Y.var(1, ddof=1)))                     # repeatability (level 1)
        s2 = Y.mean(1).std(ddof=1)                                  # std of daily averages (level 2)
        s_days = np.sqrt(max(s2 ** 2 - s1 ** 2 / J, 0))
        s_R = np.sqrt(s_days ** 2 + s1 ** 2)                        # one measurement (NIST 2.4.4)
        print(f"{method:8s} s{seed}  | {Y.mean():8.4f}  {Y.mean() - TRUE_W:+.4f}   |"
              f"  {s1:.4f}    {s_days:.4f}    {s_R:.4f}")

Output (NumPy 2.3.5, SciPy 1.16.3; two runs gave identical output):

method   seed | mean (mm)  bias (mm) | s1 repeat  s_days    s_R (mm)
pixel    s0  |  10.0033  -0.0087   |  0.0000    0.0275    0.0275
subpixel s0  |  10.0123  +0.0003   |  0.0005    0.0005    0.0007
pixel    s1  |  10.0198  +0.0078   |  0.0109    0.0360    0.0376
subpixel s1  |  10.0132  +0.0012   |  0.0005    0.0013    0.0014
pixel    s2  |  10.0100  -0.0020   |  0.0000    0.0254    0.0254
subpixel s2  |  10.0124  +0.0004   |  0.0005    0.0012    0.0013
pixel    s3  |  10.0372  +0.0252   |  0.0108    0.0176    0.0207
subpixel s3  |  10.0115  -0.0005   |  0.0005    0.0012    0.0013
pixel    s4  |  10.0224  +0.0104   |  0.0071    0.0219    0.0230
subpixel s4  |  10.0119  -0.0001   |  0.0005    0.0009    0.0010
  • Perfect repeatability can hide a poor gauge. In two of the five seeds the pixel-counting gauge returns the same count in all ten repeats, a repeatability of zero, because such low noise rarely moves a pixel across the threshold. Its day-to-day component is 0.018–0.036 mm, about a third to three-quarters of a pixel, because each placement and recalibration moves the edges relative to the pixel grid and the count jumps by whole pixels. A study of repeats alone would have passed it. The NIST e-Handbook warns that a study of a gauge whose resolution is poor relative to the measurement’s needs yields no useful information, and that the number of digits an instrument displays does not indicate its resolution (Section 2.4.5.1).
  • Sub-pixel edges and line fits remove the grid. The sub-pixel gauge’s sRs_R is 0.0007–0.0014 mm, about 1–3% of a pixel and 16 to 39 times smaller than the pixel gauge’s in the same seed, with a mean within 0.0012 mm of the true width. Fitting lines through 40 rows averages the noise of single edge points, and measuring perpendicular to them removes the tilt.
  • For the good gauge too, the day-to-day term is at least as large as repeatability. Its within-day repeatability is 0.0005 mm in every seed, while the day-to-day component is 0.0005–0.0013 mm. The script changes placement, tilt, lighting and the calibration image together each day, so it does not say which dominates; one candidate (reasoning, not tested here) is that a parabola fitted to a sampled gradient has a small error that depends on where the edge falls between pixel centres, which every new placement changes.

The simulation leaves out lens distortion and perspective, as with an ideal telecentric lens, the edge diffraction and translucency of real parts, and the uncertainty of the reference block’s own certificate; each would add a term to the uncertainty budget below.

Challenges

  • Speed and timing. Exposure, light pulse, readout, transfer and processing must fit between parts, with the reject signal timed to the part’s position; on the line, a dropped frame is an uninspected part.
  • Mechanics. Encoders slip on belts, parts move between trigger and exposure, fixtures wear and vibration moves the camera.
  • Optical and thermal drift. LEDs dim with age and temperature, lenses collect dirt, and the camera’s mounting expands with the hall’s temperature, changing the scale.
  • Heterogeneous equipment. Cameras, lights, frame grabbers, PLCs and robots come from different vendors; the standards reduce, but do not remove, the differences between implementations.
  • Changeovers. Each product needs its recipe of camera settings, light levels, inspection parameters and tolerances, switched by the line controller.

Evaluation

Gauge studies. The NIST/SEMATECH e-Handbook describes gauge R&R studies as a way to characterize gauges used in production by the errors that affect their measurements: repeatability, reproducibility, stability and bias (Sections 2.4 and 2.4.1). A study uses more than two check standards, trained operators and all gauges or a random sample of them, and separates short-term repeatability from day-to-day reproducibility and, where needed, stability over months in a nested design (Sections 2.4.2–2.4.4). For a vision gauge, the sources that play the operator’s role are placement in the fixture, recalibration, lighting and the station itself when several stations measure the same feature (reasoning by analogy, not a statement of the handbook). Bias is studied separately, against reference standards across the measurement range, which also tests the gauge’s linearity (Sections 2.4.5 and 2.4.5.2). The handbook draws its definition of resolution from the Measurement Systems Analysis reference manual of Chrysler, Ford and General Motors (2nd edition, 1995).

Measurement uncertainty. The GUM defines the standard uncertainty of a result as its uncertainty expressed as a standard deviation (JCGM 100:2008, 2.3.1). Components evaluated by statistical analysis of repeated observations, such as s1s_1 and sdayss_{\text{days}} in the example, are Type A evaluations; components evaluated by other means, such as the certificate of the reference block, a thermal expansion coefficient or the resolution of the gauge, are Type B (2.3.2, 2.3.3). They combine, weighted by how the result depends on each, into the combined standard uncertainty ucu_c (2.3.4), and an expanded uncertainty U=k ucU = k\,u_c defines an interval expected to contain a large fraction of the values that could reasonably be attributed to the measured quantity, with a coverage factor kk typically between 2 and 3 (2.3.5, 2.3.6). For independent inputs and a result y=f(x1,…,xN)y = f(x_1, \ldots, x_N),

uc2(y)=∑i=1N(∂f∂xi)2u2(xi),u_c^2(y) = \sum_{i=1}^{N} \left(\frac{\partial f}{\partial x_i}\right)^2 u^2(x_i),

the GUM’s law of propagation of uncertainty for uncorrelated inputs (5.1.2, Equation 10). When a bound ±a\pm a is all that is known about an input, with no reason to prefer any value within it, the GUM takes a rectangular distribution, whose standard uncertainty is a/3a/\sqrt{3} (4.3.7). In the example the width is the product of a pixel measurement and a scale factor, so it follows from Equation 10 that their relative uncertainties add in quadrature, and the scale factor brings in the reference block’s own uncertainty.

Inspection performance. For accept and reject decisions, the escape and false-reject rates, and the test-set sizes needed to bound a low escape rate, are given in industrial visual inspection.

Failure Modes and Risks

  • Missed triggers. A line running faster than specified, or a trigger-overlap setting that is too strict, silently skips parts or lines, as the example’s 1.3-times-nominal row shows. Missed-trigger events and frame counters compared with the PLC’s part count reveal it.
  • Wrong part, right result. If a result is matched to the wrong part, for example after a dropped frame, rejects hit good parts while bad ones pass. Part identifiers or encoder positions carried with each result guard against it.
  • Scale drift. Without periodic checks against a reference, a bias grows unseen while repeatability still looks perfect.
  • Configuration drift. A camera setting changed during troubleshooting and never restored changes every image. Saving settings with the recipe and verifying them at start-up protects against it.
  • Lighting failure. A failed LED segment or a strobe out of time with the exposure produces dark or uneven images that a classifier may still score confidently; image-statistics checks, such as mean brightness on a reference region, catch it before the decisions do.

Deployment Considerations

  • Commissioning. Measure the line’s real speed range, the camera’s maximum frame or line rate, and every delay from sensor trigger to reject gate. Choose the trigger mode, trigger delay and overlap rule from these, and record the configuration as a recipe.
  • Calibration schedule. Set recalibration intervals from measured drift, log the scale factor, and repeat the gauge study after any change to optics, mounting or software.
  • Integration testing. Test the exchange with the PLC, including what the line does when the station is offline, restarting or late.
  • Maintenance. Clean optics, replace lights before they dim below the recipe’s level, and keep spares configured from saved user sets.
  • Hardware choice. By the reasoning above, smart cameras suit single, stable inspections and PC-based systems many cameras, high data rates or large learned models; deploying vision models covers the software side.

Related

  • Designing a Computer Vision System

    How a working vision system is designed from its requirements, through the choice of sensor, optics, lighting, compute and model, to the data it is trained on, its validation in the field and its maintenance once deployed, with the requirement arithmetic for a measurement station worked through in code.

  • Camera Calibration

    Estimating a camera's intrinsic parameters, lens distortion, and pose from images of a target with known geometry, usually by a closed-form initialization followed by minimizing reprojection error.

  • Real-Time Vision Pipelines

    How a vision system turns a stream of camera frames into timely decisions, covering frame budgets, latency against throughput, pipelining and threads, queues and dropped frames, timestamps and clock synchronization, and how end-to-end latency is measured.

  • Edge Detection

    Locating the pixels where image intensity changes sharply, from derivative filters and the Canny detector to learned boundary detectors evaluated against human annotations.

  • Image Sensor

    How the chip behind a camera lens turns light into numbers, from photosites and quantum efficiency to CCD and CMOS readout, full-well capacity, noise, gain and the ADC, colour filters, rolling and global shutters, and EMVA 1288 measurements.

  • Edge Inference

    Running a vision model on the device that captures the images, such as a phone, camera, robot or microcontroller, instead of in a data centre, covering why it is done, the limits of compute, memory, power and heat, the classes of hardware and runtimes, the roofline model for finding memory-bound layers, split and offloaded computation, and how latency and energy are measured.

References

  1. European Machine Vision Association (2026). GenICam Standard Features Naming Convention (SFNC), Version 2.8.
  2. European Machine Vision Association. GenICam Introduction (official page, accessed October 2026).
  3. European Machine Vision Association. GenICam (official page, accessed October 2026).
  4. European Machine Vision Association (2021). EMVA Standard 1288: Standard for Characterization of Image Sensors and Cameras, Release 4.0 Linear.
  5. Japan Industrial Imaging Association. Standardization Committee (official page, accessed October 2026).
  6. OPC Foundation (2019). OPC 40100-1: OPC UA for Machine Vision, Part 1: Control, configuration management, recipe management, result management, Release 1.0 (Scope, online reference, accessed October 2026).
  7. ODVA. EtherNet/IP (official technology page, accessed October 2026).
  8. PROFIBUS & PROFINET International. PROFINET technology (official page, accessed October 2026).
  9. Horaud, R. & Dornaika, F. (1995). Hand-Eye Calibration. The International Journal of Robotics Research, 14(3), 195–210 (read in the authors' copy, arXiv:2311.12655v2).
  10. Tsai, R. Y. & Lenz, R. K. (1989). A New Technique for Fully Autonomous and Efficient 3D Robotics Hand/Eye Calibration. IEEE Transactions on Robotics and Automation, 5(3), 345–358.
  11. Shiu, Y. C. & Ahmad, S. (1989). Calibration of Wrist-Mounted Robotic Sensors by Solving Homogeneous Transform Equations of the Form AX=XB. IEEE Transactions on Robotics and Automation, 5(1), 16–29.
  12. Joint Committee for Guides in Metrology (2008). JCGM 100:2008, Evaluation of Measurement Data: Guide to the Expression of Uncertainty in Measurement (GUM 1995 with minor corrections).
  13. NIST/SEMATECH. e-Handbook of Statistical Methods, Section 2.4: Gauge R & R studies (accessed October 2026).