<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Computer Vision on Boris Dupoux</title><link>https://borisdupoux.com/categories/computer-vision/</link><description>Recent content in Computer Vision on Boris Dupoux</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Thu, 01 Jan 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://borisdupoux.com/categories/computer-vision/index.xml" rel="self" type="application/rss+xml"/><item><title>Geolocated Video Analysis and Inter-Object Distance Measurement</title><link>https://borisdupoux.com/research/video-geolocation/</link><pubDate>Thu, 01 Jan 2026 00:00:00 +0000</pubDate><guid>https://borisdupoux.com/research/video-geolocation/</guid><description>&lt;h2 id="context"&gt;&lt;a href="#context" class="header-anchor"&gt;&lt;/a&gt;Context
&lt;/h2&gt;&lt;p&gt;Industrial sites are often covered by fixed cameras whose footage is only reviewed after an incident and yields no usable data. The aim was to turn existing cameras, and occasional drone footage, into a measuring instrument: for every detected object, a latitude/longitude position and metric distances rather than a pixel box.&lt;/p&gt;
&lt;p&gt;This is hard for three reasons. A single camera gives no depth, so scene scale must be inferred. The usual georeferencing method, a ground-plane homography, assumes a flat floor and fails silently for raised objects or uneven terrain. And high-resolution video is expensive, while the common shortcut of downscaling to 640 px discards the geometric detail ground positions depend on.&lt;/p&gt;
&lt;h2 id="approach"&gt;&lt;a href="#approach" class="header-anchor"&gt;&lt;/a&gt;Approach
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB
 A["Video source&lt;br/&gt;file · RTSP · drone clip (up to 3840×2160)"] --&gt; B["Object detector at native resolution&lt;br/&gt;detect · segment · pose · OBB"]
 A --&gt; C["Metric monocular depth model&lt;br/&gt;depth map"]
 B --&gt; D["Multi-object tracker&lt;br/&gt;motion model + association"]
 B --&gt; E["Per-object depth&lt;br/&gt;mask pixels, outlier rejection"]
 C --&gt; E
 E --&gt; F["Ray casting&lt;br/&gt;pixel ray + metric depth + camera pose"]
 F --&gt; G["WGS84 position&lt;br/&gt;optional DEM for ground elevation"]
 E --&gt; H["3D distances&lt;br/&gt;between masks · along trajectories"]
 D --&gt; H
 G --&gt; I["SQLite store&lt;br/&gt;detections · tracks · GPS trajectories"]
 H --&gt; I
 I --&gt; J["Analytics&lt;br/&gt;zones · flows · orthophoto overlay"]&lt;/pre&gt;&lt;h2 id="methods"&gt;&lt;a href="#methods" class="header-anchor"&gt;&lt;/a&gt;Methods
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Detection.&lt;/strong&gt; A YOLO-family detector, at several model sizes, in four modes (detect, segment, pose, oriented boxes). Inference runs at native resolution with no forced &lt;code&gt;imgsz&lt;/code&gt;. Segmentation is the default because masks give cleaner depth samples than boxes. PyTorch, ONNX, TensorRT and CoreML weights are accepted (CUDA and Apple MPS).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monocular depth.&lt;/strong&gt; A metric monocular depth model predicts a depth map, which is resampled to the frame size. Each object&amp;rsquo;s depth is a robust estimate over its mask pixels, after outlier rejection. A validation step compares predicted depth with reference zones whose distance is known, to detect calibration drift.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Geolocation by ray casting.&lt;/strong&gt; A ray is cast from the camera centre through the object&amp;rsquo;s pixel and stopped at the object&amp;rsquo;s metric depth. The resulting point is converted from the camera frame to a local North-East-Down frame, then to WGS84. Unlike a homography, this does not assume a flat ground. An optional DEM supplies ground elevation. Positions can be overlaid on a georeferenced orthophoto for visual checks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tracking.&lt;/strong&gt; A custom multi-object tracker with a motion model, confidence-aware association and a track-fusion step that links fragments using gap, heading and speed limits. When depth is available, each track stores a 3D trajectory, from which the distance travelled and the speed in m/s are derived.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inter-object distances.&lt;/strong&gt; Later consolidated into a reusable vision library. Two segmented objects are back-projected into 3D, and the minimum point-to-point distance is reported. Overlapping masks are treated as contact. A Monte Carlo simulation perturbs depth, focal length and pixel positions to give a standard deviation and a 95 % interval. Zone membership uses the share of the mask inside the zone, with hysteresis, rather than a centre-point test.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Engineering.&lt;/strong&gt; The configuration supports a two-GPU split (detection on one device, depth estimation on the other), RTSP discovery and recording, and processing of several cameras in parallel.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="results"&gt;&lt;a href="#results" class="header-anchor"&gt;&lt;/a&gt;Results
&lt;/h2&gt;&lt;p&gt;Measured on a single NVIDIA RTX 5090. The detection benchmark covers detection and tracking only, with depth disabled.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Setting&lt;/th&gt;
					&lt;th&gt;Video&lt;/th&gt;
					&lt;th&gt;Throughput&lt;/th&gt;
					&lt;th&gt;Output&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Largest detector, batch 1&lt;/td&gt;
					&lt;td&gt;3840×2160, 50 fps, 3,301 frames&lt;/td&gt;
					&lt;td&gt;5.1 fps&lt;/td&gt;
					&lt;td&gt;320,217 detections, 1,941 tracks&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Smallest detector, batch 1&lt;/td&gt;
					&lt;td&gt;3840×2160, 50 fps&lt;/td&gt;
					&lt;td&gt;13.0 fps&lt;/td&gt;
					&lt;td&gt;158,989 detections, 908 tracks&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Largest detector, batch 1&lt;/td&gt;
					&lt;td&gt;2304×1296, 15 fps, 5,000 frames&lt;/td&gt;
					&lt;td&gt;17.9 fps&lt;/td&gt;
					&lt;td&gt;73,502 detections, 2,706 tracks&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Smallest detector, batch 1&lt;/td&gt;
					&lt;td&gt;2304×1296, 15 fps&lt;/td&gt;
					&lt;td&gt;39.0 fps&lt;/td&gt;
					&lt;td&gt;51,890 detections, 1,499 tracks&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Full chain (detection + depth + tracking + storage)&lt;/td&gt;
					&lt;td&gt;2304×1296, 300 frames&lt;/td&gt;
					&lt;td&gt;2.02 fps&lt;/td&gt;
					&lt;td&gt;12.3 detections per frame&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In the full-chain run, depth estimation took 117.6 s of the 148.3 s total (about 80 %), and detection took 20.9 s. Depth estimation, not the detector, is the bottleneck. On 4K footage the largest detector runs about ten times slower than real time. That suits the intended use, which is analysis of recorded archives, not live alerting.&lt;/p&gt;
&lt;h2 id="limitations--next-steps"&gt;&lt;a href="#limitations--next-steps" class="header-anchor"&gt;&lt;/a&gt;Limitations &amp;amp; next steps
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;No geolocation accuracy has been measured against surveyed ground truth yet. The ray-casting stage was added after the timing runs above, so its cost is not included in them.&lt;/li&gt;
&lt;li&gt;The metric scale depends on the depth model and on the camera pose and intrinsics. Errors in tilt or focal length propagate directly into ground positions.&lt;/li&gt;
&lt;li&gt;The depth model predicts at its own internal resolution, so fine depth detail is limited even when detection runs in 4K.&lt;/li&gt;
&lt;li&gt;Next steps: an accuracy study with GNSS-surveyed targets, profiling the two-GPU split, and measuring how accurate Monte Carlo distance intervals are on objects at known separations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="stack"&gt;&lt;a href="#stack" class="header-anchor"&gt;&lt;/a&gt;Stack
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Python&lt;/code&gt; · &lt;code&gt;PyTorch&lt;/code&gt; · &lt;code&gt;OpenCV&lt;/code&gt; · &lt;code&gt;NumPy&lt;/code&gt; · &lt;code&gt;SciPy&lt;/code&gt; · &lt;code&gt;pyproj&lt;/code&gt; · &lt;code&gt;rasterio&lt;/code&gt; · &lt;code&gt;SQLite&lt;/code&gt; · &lt;code&gt;CUDA&lt;/code&gt; · &lt;code&gt;Apple MPS&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Sub-Millimetre Crack Detection in Civil Structures</title><link>https://borisdupoux.com/research/crack-detection/</link><pubDate>Fri, 01 Mar 2024 00:00:00 +0000</pubDate><guid>https://borisdupoux.com/research/crack-detection/</guid><description>&lt;h2 id="context"&gt;&lt;a href="#context" class="header-anchor"&gt;&lt;/a&gt;Context
&lt;/h2&gt;&lt;p&gt;Non-destructive structural health monitoring for bridges, buildings and
infrastructure. The challenge is not only to &lt;strong&gt;detect&lt;/strong&gt; cracks, but to
&lt;strong&gt;classify them by width&lt;/strong&gt; — without contact or scaffolding.&lt;/p&gt;
&lt;p&gt;Width is what matters for inspection: depending on how open a crack is, the
&lt;strong&gt;repair (filling) method is not the same&lt;/strong&gt;. An inspection system therefore has
to be very precise, because a wrong width class means a wrong repair
specification.&lt;/p&gt;
&lt;h2 id="four-width-classes"&gt;&lt;a href="#four-width-classes" class="header-anchor"&gt;&lt;/a&gt;Four width classes
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Class&lt;/th&gt;
					&lt;th&gt;Crack width&lt;/th&gt;
					&lt;th&gt;Consequence&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;&amp;lt; 0.3 mm&lt;/td&gt;
					&lt;td&gt;Finest cracks — often narrower than a pixel; dedicated repair approach&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;0.3 – 0.7 mm&lt;/td&gt;
					&lt;td&gt;Different repair approach&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;0.7 – 1 mm&lt;/td&gt;
					&lt;td&gt;Different repair approach&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;4&lt;/td&gt;
					&lt;td&gt;≥ 1 mm&lt;/td&gt;
					&lt;td&gt;Different repair approach&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Each class calls for its own filling/repair approach, so the classification
directly drives the maintenance decision.&lt;/p&gt;
&lt;h2 id="the-sub-pixel-challenge"&gt;&lt;a href="#the-sub-pixel-challenge" class="header-anchor"&gt;&lt;/a&gt;The sub-pixel challenge
&lt;/h2&gt;&lt;p&gt;The key difficulty is to go &lt;strong&gt;below the pixel size&lt;/strong&gt;. A 0.3 mm crack does not
even cover a full pixel at typical inspection resolutions — and the system must
still detect it, even when the ground sampling distance is somewhat coarser than
0.3 mm.&lt;/p&gt;
&lt;p&gt;Why is this possible at all? A crack thinner than a pixel does not vanish: it
still occupies &lt;strong&gt;part&lt;/strong&gt; of the pixels it crosses, and slightly alters their
intensity compared with the surrounding surface. Taken individually, that
partial-pixel signal is weak; but a crack is a &lt;strong&gt;continuous, elongated&lt;/strong&gt; feature,
so the same faint contrast repeats coherently along many adjacent pixels. Exploiting
that contrast and continuity is what allows detection — and width estimation —
beyond the nominal resolution of the image.&lt;/p&gt;
&lt;h2 id="acquisition-drone-and-smartphone"&gt;&lt;a href="#acquisition-drone-and-smartphone" class="header-anchor"&gt;&lt;/a&gt;Acquisition: drone and smartphone
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Drone photography&lt;/strong&gt; — high-resolution UAV capture of structural surfaces,
for large or hard-to-reach structures.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Smartphone photography&lt;/strong&gt; — the approach also works on images taken with a
mobile phone, which I have tested, making close-range inspection possible
with everyday equipment.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="pipeline"&gt;&lt;a href="#pipeline" class="header-anchor"&gt;&lt;/a&gt;Pipeline
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB
 A["Image capture — drone or smartphone"] --&gt; B["Image tiling &amp; calibration"]
 B --&gt; C["Crack segmentation — CV / DL"]
 C --&gt; D["Sub-pixel width estimation"]
 D --&gt; E["Width classification — 4 classes"]
 E --&gt; F["Defect map &amp; inspection report"]&lt;/pre&gt;&lt;h2 id="methods"&gt;&lt;a href="#methods" class="header-anchor"&gt;&lt;/a&gt;Methods
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;High-resolution capture of structural surfaces by drone or smartphone.&lt;/li&gt;
&lt;li&gt;Computer-vision / deep-learning crack segmentation on concrete and masonry.&lt;/li&gt;
&lt;li&gt;Metric calibration and &lt;strong&gt;sub-pixel&lt;/strong&gt; analysis for crack width estimation.&lt;/li&gt;
&lt;li&gt;Classification into four width classes matched to repair methods.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="results"&gt;&lt;a href="#results" class="header-anchor"&gt;&lt;/a&gt;Results
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Non-destructive, repeatable inspection of civil structures.&lt;/li&gt;
&lt;li&gt;Geolocated defect maps supporting maintenance prioritisation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Models and visuals will be added.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="stack"&gt;&lt;a href="#stack" class="header-anchor"&gt;&lt;/a&gt;Stack
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Python&lt;/code&gt; · &lt;code&gt;OpenCV&lt;/code&gt; · deep learning · high-res RGB drone · smartphone imagery · photogrammetry&lt;/p&gt;</description></item></channel></rss>