A large panel or housing often shows no hole, printed mark or fiducial to locate it by: the only reliable feature is a corner. Searching that corner with a corner operator, or reading the extreme pixel of the part silhouette, returns a mark that wanders by tenths of a millimeter, and a rounded corner biases it permanently. The fix is to fit a straight line to the sub-pixel edge points of each face that forms the corner, then use the intersection of the two lines as the positioning mark. Below you get the rectangle placement, the fit and intersection steps, the formula with a worked check, a pixel budget for a real-sized panel, and the acceptance tests to run before production.
Why a corner search fails on a large part
Consider a 400 mm panel imaged at 0.20 mm per pixel. The fastest corner feature is the extreme silhouette pixel: binarize the part region and take its top-right-most point. That is a single sample. It carries the full edge noise of one pixel, a quantization band of ±0.5 px (±0.10 mm at this pixel size), and a systematic bias: every real corner has a fillet radius r, and the extreme point of a rounded 90° corner sits r(√2 − 1) ≈ 0.41 r inside the virtual apex. With a 2 mm fillet the mark lands 0.83 mm short of the true corner, and the error slides along the arc as the part rotates.
A corner or pattern-match operator improves the averaging but samples a window of tens of pixels, stays sensitive to rotation, and learns whatever radius the teach image happened to have.
Fitting a line to each face fixes both problems at once. A least-squares line averages several hundred sub-pixel edge points, and the two fitted lines act as tangent constructions: for a filleted corner they meet at the virtual apex of the sharp corner, whatever the radius. The fillet stops mattering because it is never measured.
| Method | Points averaged | 2 mm fillet bias | 1σ scatter at 0.20 mm/px |
|---|---|---|---|
| Extreme silhouette pixel | 1 | 0.83 mm, drifts with rotation | about 0.10 mm |
| Corner template, small window | tens | follows the taught corner | 0.05–0.20 mm |
| Two fitted lines, intersected | 300–800 | none: tangents meet at the virtual apex | 0.01–0.02 mm |
What you need
A mono, global-shutter camera with locked exposure; a lens whose distortion you have calibrated out or accepted; contrast hard enough for sub-pixel edges; and three library functions: sub-pixel 1D edge extraction, a line fit, and a two-line intersection. Most vision environments bundle the first two as a metrology or line-measure model: you create the model, add two line-measure objects (your two rectangles), apply it to the image, and read back two fitted lines to intersect. If the mark must come out in millimeters or robot coordinates, add the station calibration; the pixel-to-object conversion is the magnification relation in calculating object space pixel size from magnification. Hardware classes and trade-offs live in the machine vision lenses and smart cameras categories; this guide stays on the method.
Fit the lines and intersect them
- Lock the image. Fixed exposure time and gain, manual iris, fixed focus. An auto exposure that floats between frames moves the effective threshold and with it the edge position; the mechanism is explained in automatic iris, exposure and gain control in machine vision.
- Light for a hard edge. Backlight through a diffuser for a silhouette, or a dark-field line for a machined face. Keep the 10–90 % edge transition within about 3 px; wider transitions smear the sub-pixel estimate.
- Place two measure rectangles, one along each face with the long side parallel to the nominal edge. Start each at least 3 times the fillet radius from the apex plus a smoothing margin — with a 2 mm radius at 0.20 mm/px, the first measure row sits 40–50 px out. Make each rectangle 300–400 px long and 10–20 px wide.
- Extract sub-pixel edge points. Project the gray values along each rectangle, smooth with a Gaussian of σ = 1–3 px, then interpolate the gradient maximum. A clean backlit edge lands at 1σ of 0.02–0.05 px; the way to measure your own value from sampled profiles is in estimate edge position accuracy from image sampling.
- Fit each line and reject outliers. Total least squares over the point set, drop points with residuals above 3 times the RMS, refit once, and log the RMS. A healthy line sits under 0.1 px RMS.
- Intersect the two lines with the formula in the next section, and reject any frame whose faces come out nearly parallel.
- Convert to world or robot coordinates through the station calibration, exactly as in camera calibration for length measurement from image markers.
- Verify before production. 30–50 frames with the part clamped give the static scatter; then rotate the part ±5° and confirm the reported apex stays within tolerance.
The intersection formula
Each fitted line comes out of the least-squares step as a point (the centroid of its edge points) and a direction vector. Two point-direction lines intersect where their parameters agree, which is a 2×2 solve:
formula
line 1: point P1 = (x1, y1), direction d1 = (a1, b1)
line 2: point P2 = (x2, y2), direction d2 = (a2, b2)
t = ((x2 - x1) * b2 - (y2 - y1) * a2) / (a1 * b2 - b1 * a2)
xc = x1 + t * a1
yc = y1 + t * b1
With unit direction vectors the denominator is the sine of the angle between the faces: 1.0 at a perfect 90° corner, 0.05 at about 3°. Reject the frame below 0.05, because near-parallel faces produce a confident, meaningless mark.
import numpy as np
# illustrative values for one frame, pixel coordinates
p1 = np.array([800.0, 1492.0]) # centroid of face A edge points
d1 = np.array([1.0, 0.0018]) # face A direction, near horizontal
p2 = np.array([411.0, 1900.0]) # centroid of face B edge points
d2 = np.array([0.002, -1.0]) # face B direction, near vertical
t = np.cross(p2 - p1, d2) / np.cross(d1, d2)
corner = p1 + t * d1
print(np.round(corner, 3)) # [411.817 1491.301]
# test: the result must satisfy both line equations
assert np.linalg.norm(np.cross(corner - p1, d1)) < 1e-6
assert np.linalg.norm(np.cross(corner - p2, d2)) < 1e-6
The printed corner, (411.817, 1491.301), sits 388.18 px from p1 along face A. Check it against face A's equation: at x = 411.82, y = 1492 + 0.0018 × (411.82 − 800) = 1491.30 — the same point the vertical face gives at that height, so the intersection is right. The two asserts test the same property automatically.
Worked example: a 400 × 300 mm panel mark at 0.20 mm per pixel
The case: a 400 × 300 mm cover panel, 90° corners, 2 mm fillet, located by its top-left corner for a placing station. Inputs, all typical for a backlit silhouette set-up:
- Part 400 × 300 mm, fillet radius r = 2 mm.
- Camera 2448 × 2048 px over a 490 mm field: pixel size = 490 / 2448 = 0.20 mm/px.
- Edge noise σe = 0.05 px, the backlit range from step 4.
- Each line: N = 400 points over a span L = 400 px; rectangle center D = 150 px from the apex; included angle θ = 90°.
The 490 mm field holds the 400 mm part with margins; a part that outgrows one field needs the approach in template matching a part larger than the field of view.
Line-angle noise. Least squares over N evenly spread points gives the slope uncertainty σθ ≈ σe √(12/N) / L = 0.05 × √(12/400) / 400 = 0.05 × 0.173 / 400 = 0.000022 rad (0.0012°).
Mark noise from the geometry. A line tilted by σθ moves a point at distance D laterally by D·σθ, and two faces crossing at angle θ divide the position error by sin θ. Per line: 150 × 0.000022 / sin 90° = 0.0033 px. Two independent lines in quadrature: 0.0046 px = 0.001 mm at 0.20 mm/px. The fit-and-intersect arithmetic contributes about a thousandth of a pixel — it is never the limit.
The real floor. Residual lens distortion, edge fuzz and illumination drift put a settled station at 1σ of 0.05–0.1 px overall, so plan the budget around a 3σ mark scatter of 0.03–0.06 mm. This is the same sub-pixel chain walked to micrometer level in subpixel edge measurement of cutting tools to micrometer precision.
Pixel budget. With 3σ ≈ 0.3 px, keeping the pixel size at or below the mark tolerance holds the mark's own noise under 30 % of the tolerance band; a guidance-only mark can run to about 1.5 times that.
Decision. At 0.20 mm/px this is a guidance mark: 3σ ≈ 0.06 mm is 20 % of a ±0.3 mm placing tolerance and passes with margin. As a ±0.05 mm measuring mark it fails the budget, because that needs pixel ≤ 0.05 mm — about 9,800 px across the 490 mm field, i.e. a 65 MP large-format sensor (490 / 9,300 ≈ 0.053 mm/px, 3σ ≈ 0.016 mm) or a smaller field per camera. The extreme-pixel mark on the same image, ±0.10 mm of quantization plus the 0.83 mm fillet bias, fails both budgets.
To turn a pixel budget and a field width into a sensor pixel count, use the calculator below; its button opens the camera finder pre-filtered to cameras with enough pixels.
Camera and lens picks by field size
The pixel budget sorts the hardware into three classes. Guidance marks in the ±0.3 mm class run on 5–12 MP sensors at 0.1–0.2 mm/px over a 400–500 mm field. A ±0.1 mm measuring mark wants a 25 MP sensor at 0.10 mm/px. A ±0.05 mm mark on a part this size needs the 65 MP large-format route or a split field.
Mid-size fields fit a 2/3-inch rig. At a 300 mm working distance a 35 mm lens covers about 75 × 56 mm on a 2/3-inch sensor (8.8 × 6.6 mm active area). The LS-FFL-0679 is a 35 mm, 2/3", 6 MP C-mount lens for exactly this class of field.
- Type
- Machine vision fixed
- Sensor format
- 2/3"
- Mount
- C-mount
- Resolution
- 6-10 MP
For stations that run the fit on the camera itself, pair a C-mount smart camera with a low-distortion fixed focal length lens. The LS-SMC-0017 is an 8.8 MP global-shutter smart camera with a 1" sensor on a C-mount, and its x86 platform runs the fit-and-intersect routine on the device. The LS-FFL-0567 is a 16 mm C-mount lens covering a 1.1" sensor, specified at 20 MP with F2.8-22 and less than 0.3% distortion.
- Interface
- USB 2.0
- Resolution
- 6-10 MP
- Type
- Machine vision fixed
- Sensor format
- 1.1"
Measurement-class marks on meter-scale parts move the camera back and the resolution up. The LS-FFL-1676 is a 60 mm fixed focal length lens for large-format sensors on an M58 mount, rated at 65 MP with a working distance from 214 mm to 1536 mm.
- Type
- Fixed focal length
- Sensor format
- Large format
- Mount
- M58
- Resolution
- Over 25 MP
Checks before you trust the mark
- Static repeatability. 30–50 frames with the part clamped and the lamp warmed up (give it 15 minutes). Report 1σ and 3σ of the mark. Accept 0.1 px 1σ or better for guidance; hold 0.05 px for a measuring mark.
- Rotation. Rotate the part ±5° about the corner. The fitted-line mark should hold the same physical apex within tolerance; an extreme-pixel mark visibly walks along the fillet arc under this test.
- Residual audit. Keep per-line RMS under 0.1 px and reject frames above it. A rising RMS means dirt, burrs or an ageing lamp, not a software problem.
- Height. The intersection is a virtual point in the image plane. If the corner sits nearer the camera than the calibration plane, perspective scales the mark; seat parts at the calibrated height or correct for Z as in pin position measurement at different heights.
- Parallel guard in production. Apply the 0.05 sine threshold from the formula section to every frame; a chipped corner or a slipped rectangle otherwise reports a confident wrong mark.
Common mistakes
- Starting the rectangle inside the fillet transition: the fit bends and the mark slides along the bisector — the warning above, in numbers.
- Spanning one rectangle across both faces: least squares averages the corner into a line with a meaningless slope.
- Leaving auto exposure on: the threshold drifts frame to frame, and the 1σ you measured in the morning is gone by the afternoon.
- Using a color sensor where mono works: demosaicing interpolates pixel values across the very edge you are measuring and softens the gradient. Prefer mono for edge metrology.
- Deriving pixel size from the sensor alone. The budget pairs pixel size with tolerance: 490 mm / 2448 px = 0.20 mm/px passes a ±0.3 mm guidance mark and fails a ±0.05 mm measuring mark on identical hardware.
When two lines are not the answer
Cast or molded parts without a 100 px straight run on either face: fit the fillet as an arc and use the arc center as the mark instead of an intersection. Parts with no trustworthy silhouette — transparent, glossy or stacked — are better served by an area mark such as the grayscale centroid of a dark circle, which needs no edge at all. And when the corner shows in height rather than in silhouette, a 3D profile sensor replaces the edge chain entirely.
Where to go next
Pick the camera from the pixel budget and the lens from the field: the camera finder and lens finder filter by both, and the lights section covers the backlight. More applied walkthroughs sit on the applications topic page, and for a quoted multi-camera station use /quote/ or /contact/.
The configurator matches a camera, lens, light, light controller and cables to each other, step by step, and lists only parts that fit what you already picked.
Questions
How far from the corner should each measurement rectangle start?
Outside the fillet and its transition: at least 3 times the corner radius, plus a margin for the edge operator's smoothing width. With a 2 mm radius at 0.20 mm per pixel, put the first measure row 40–50 px (8–10 mm) from the apex and run the rectangle 300–400 px. A least-squares line weights the middle of the span most, so the exact start row is not critical as long as the fillet is excluded.
Does the two-line intersection still work on corners that are not 90 degrees?
Yes. The formula uses the two fitted directions and never assumes a right angle. What changes is noise amplification: the mark error grows as 1 over the sine of the included angle, so a 30 degree corner roughly doubles the lateral error of the same two line fits. For acute corners, lengthen the rectangles to pull the angular uncertainty down before accepting the budget.
How many edge points does each line fit need?
Treat 100 points per line as the floor and 300–500 as the working range. The angular uncertainty of a least-squares line falls with the square root of the point count, so four times the span halves the angle noise. Beyond about 500 points the optics and edge quality dominate, and more points add little except processing time.
Can the corner mark be sent straight to the robot?
Not directly. The intersection comes out in pixel coordinates, and the robot needs its own frame: pass the pixel result through the hand-eye or camera-to-part calibration first, then add the tool and part-height offsets. If the corner sits at a different height than the calibration plane, apply the perspective correction or re-teach the height, or the mark inherits a scale error.
What if one face is too short or curved to fit a line?
Keep the straight face as the line and pair it with a different second feature: the fitted circle of the fillet arc, or a second line from another edge of the part. Their intersection or tangent point still gives a stable mark. If neither face is straight, switch to an area-based mark such as a grayscale centroid instead of forcing an edge construction.



