Skip to content

Commit a9d28e5

Browse files
kwagyemanclaude
andcommitted
docs: image-chapter audit round 2 -- accuracy, links, de-meta
Page-by-page audit continuing through pixel-math, thresholding, filters, analysis, transforms, finding, decoding, matching, io, and wrap-up. Accuracy fixes verified against firmware: morphology threshold semantics (erode tolerates N background neighbours, dilate needs more than N foreground), AprilTag error correction (uniform 2-bit, per-family Hamming distance), line results are attrtuples passed straight to draw_line, blob threshold auto-learn via histogram percentiles, csi framesize tuples replace stale sensor.B64X64 constants, ulab bridge is to_ndarray/Image(ndarray) copies. Figures: frame-diff box widths aligned across panels, convolution-kernel labels/centering fixed, morphology walkthrough regenerated with exact 3x3 results. Dropped legacy Haar/keypoint sections (ML chapter rewired), closing recaps, and forward references; de-acronymed prose; fixed dead and missing cross references. Library: note that PDF417 is not implemented by the barcode decoder. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 98e8f6c commit a9d28e5

29 files changed

Lines changed: 1057 additions & 1324 deletions

docs/library/omv.image.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,9 @@ returned by :meth:`Image.find_barcodes`.
735735
.. data:: PDF417
736736
:type: int
737737

738-
PDF417 2D stacked barcode.
738+
PDF417 2D stacked barcode. The constant exists for completeness,
739+
but the barcode decoder does not currently implement PDF417 --
740+
`Image.find_barcodes()` will not return detections of this type.
739741

740742
.. data:: CODE93
741743
:type: int

docs/openmvcam/tutorial/image/analysis/histograms-and-statistics.rst

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
11
Histograms and statistics
22
=========================
33

4-
The sections so far have all *operated* on
5-
images: filtering them, thresholding them,
6-
combining them with other images. The remaining
7-
family of operations does something different.
8-
It *measures* the image -- summarises the
9-
distribution of pixel values, returns the
10-
mean and median brightness, finds the optimal
11-
cutoff between dark and bright pixels, reports
12-
the spread of the colour channels. Those
13-
measurements feed back into the operating side
14-
in two ways: as inputs to the algorithm that
15-
decides what threshold to use, what gain to set,
16-
what the scene's tonal profile looks like; and as
17-
diagnostic signals -- "is the scene bright
18-
enough?" -- that the application can act on
19-
without making a decision about any particular
20-
pixel.
4+
Alongside the operations that change an
5+
image's pixels, the :class:`Image` class
6+
carries a family of methods that *measure*
7+
them -- summarise the distribution of pixel
8+
values, return the mean and median brightness,
9+
find the optimal cutoff between dark and
10+
bright pixels, report the spread of the colour
11+
channels. The measurements feed applications
12+
in two ways: as inputs to the code that
13+
decides what threshold to use, what gain to
14+
set, what the scene's tonal profile looks
15+
like; and as diagnostic signals -- "is the
16+
scene bright enough?" -- that an application
17+
can act on without making a decision about any
18+
particular pixel.
2119

2220
The starting point for almost every measurement
2321
is the *histogram*.
@@ -171,8 +169,8 @@ Percentiles and CDF lookups
171169
---------------------------
172170

173171
The :class:`histogram` object exposes a
174-
``get_percentile`` method that turns a
175-
fraction into a pixel value -- the value
172+
:meth:`~image.histogram.get_percentile` method
173+
that turns a fraction into a pixel value -- the value
176174
below which the requested fraction of pixels
177175
lies. ``h.get_percentile(0.5)`` is the
178176
median; ``h.get_percentile(0.05)`` and
@@ -268,14 +266,3 @@ call to produce an image whose only purpose
268266
is to be measured. For a continuously
269267
running motion-detection script, the saving
270268
adds up.
271-
272-
With histograms describing distributions,
273-
statistics summarising them, percentiles for
274-
robust range estimates, and Otsu's method
275-
for the optimal binary split, the
276-
measurement side of the toolkit is ready.
277-
The remaining tonal work is about *acting*
278-
on what the measurements say -- adjusting the
279-
image's contrast, brightness, or colour to
280-
correct for what the histogram revealed
281-
about it.

docs/openmvcam/tutorial/image/analysis/regression-and-similarity.rst

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
Regression and similarity
22
=========================
33

4-
Two measurements on the :class:`Image`
5-
surface do not fit the histogram / statistics
6-
framing of the previous pages, but come up
7-
often enough to deserve a dedicated section.
8-
Linear regression of thresholded pixels gives
9-
an application a *line* it can act on -- the
4+
Two more measurements on the :class:`Image`
5+
class summarise the image as something other
6+
than a distribution of pixel values. Linear
7+
regression of thresholded pixels gives an
8+
application a *line* it can act on -- the
109
classical input to a line-following robot.
1110
Similarity measurement gives an application a
1211
single number describing how alike two images
@@ -197,12 +196,3 @@ reference image. It is the cheap way to
197196
build a tracker that searches a parameter
198197
space and reports which transform of the
199198
reference best matches the current frame.
200-
201-
With linear regression for line extraction
202-
and SSIM for image comparison, the
203-
measurement side of the toolkit is complete.
204-
What follows turns to geometric work --
205-
scaling, flipping, cropping, correcting
206-
lens distortion, and re-projecting into
207-
the polar coordinate system the Foundations
208-
introduced.

docs/openmvcam/tutorial/image/analysis/tonal-corrections.rst

Lines changed: 22 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
Tonal corrections
22
=================
33

4-
The previous page introduced the histogram as
5-
the *description* of how brightness is
6-
distributed in an image. This page is about the
7-
operations that *change* that distribution --
8-
the corrections an application applies when the
9-
captured image is too dark, too bright, too
10-
flat, or skewed toward the wrong colour.
4+
Tonal corrections change how brightness and
5+
colour are distributed in a captured image --
6+
the fixes an application applies when a frame
7+
is too dark, too bright, too flat, or skewed
8+
toward the wrong colour.
119

1210
The corrections belong to two families:
1311
brightness-and-contrast adjustments that
14-
reshape the distribution of brightness, and
15-
colour adjustments that change which colour
16-
each pixel reads as. Both have analogues in
17-
the sensor's ISP that Vision Sensors covered;
18-
this page is about applying them to an
19-
already-captured :class:`Image`, after the
20-
fact, when the post-capture state needs more
21-
correction than the ISP already provided.
12+
redistribute brightness, and colour
13+
adjustments that change which colour each
14+
pixel reads as. Both have analogues in the
15+
sensor's :doc:`ISP
16+
</openmvcam/tutorial/vision/color/isp-pipeline>`,
17+
which corrects each frame on its way in; the
18+
methods here apply to an already-captured
19+
:class:`Image`, after the fact, for the cases
20+
where the frame needs more correction than the
21+
ISP provided.
2222

2323
Histogram equalisation
2424
----------------------
@@ -41,7 +41,7 @@ equalisation:
4141
img.histeq()
4242

4343
The mechanic is direct. The cumulative
44-
distribution function of the source's
44+
distribution function (CDF) of the source's
4545
histogram is computed; each input pixel value
4646
is mapped to its position in the CDF, scaled
4747
to the output range. Where pixels were
@@ -238,36 +238,9 @@ Combined with a per-channel offset, the
238238
3-by-4 form lets the application also
239239
re-zero each channel.
240240

241-
Vision Sensors covers the *why* of colour
242-
correction matrices in detail. The
243-
post-capture form on the :class:`Image` is
244-
just the same operation, applied after the
245-
fact.
246-
247-
Where this leaves the application
248-
---------------------------------
249-
250-
With histogram equalisation and CLAHE for
251-
data-driven contrast adjustment, gamma /
252-
contrast / brightness for parameter-driven
253-
tone curves, auto white balance for the
254-
common colour correction, and the colour
255-
correction matrix for the more general case,
256-
the tonal toolkit covers the corrections that
257-
classical image processing applies *after*
258-
the capture is already done. Some of them
259-
overlap with what the ISP already did during
260-
capture, and the right place to make the
261-
correction depends on whether the captured
262-
frame is what needs the help or whether the
263-
capture itself needs to be different. When
264-
the answer is the latter, Vision Sensors'
265-
material is where the ISP-side knobs live;
266-
when the answer is the former, this page is
267-
where the post-capture knobs are.
268-
269-
The remaining measurement-side operations are
270-
the ones that do not fit the histogram /
271-
statistics framing: linear regression of
272-
thresholded pixels, and image-to-image
273-
similarity comparison.
241+
The :doc:`ISP pipeline
242+
</openmvcam/tutorial/vision/color/isp-pipeline>`
243+
material covers the *why* of colour correction
244+
matrices. The post-capture form on the
245+
:class:`Image` is just the same operation,
246+
applied after the fact.

docs/openmvcam/tutorial/image/decoding/barcodes-and-datamatrix.rst

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
Barcodes and Data Matrix codes
22
==============================
33

4-
QR codes and AprilTags are recent
5-
inventions, born in the era of dense
6-
two-dimensional symbols and cheap
7-
smartphone cameras. The codes printed on
8-
the side of a cereal box, the wrist band a
9-
hospital patient wears, the maker mark
10-
laser-etched onto a circuit board predate
11-
all of that. They are *one-dimensional*
12-
*barcodes* and small high-density
13-
*Data Matrix* codes, and the image module
14-
has dedicated decoders for both. The
15-
applications they fit are the industrial,
16-
retail, and inventory ones the consumer
17-
2D codes never quite covered.
4+
Two more code families round out the
5+
camera's decoders. *One-dimensional
6+
barcodes* -- the stripes on the side of a
7+
cereal box, a hospital wrist band, a
8+
shipping label -- are the oldest
9+
machine-readable symbols still in everyday
10+
use. *Data Matrix* codes are
11+
two-dimensional like QR codes, but denser
12+
at the same payload size and aimed at
13+
industrial marking -- the maker mark
14+
laser-etched onto a circuit board rather
15+
than the poster on a wall. The image module
16+
has a dedicated decoder for each, covering
17+
the industrial, retail, and inventory
18+
applications the consumer 2D codes never
19+
quite reached.
1820

1921
1D barcodes
2022
-----------
@@ -71,9 +73,7 @@ libraries and blood banks),
7173
:data:`image.CODE39`, :data:`image.CODE93`,
7274
and :data:`image.CODE128` (variable-length
7375
alphanumeric symbologies for arbitrary
74-
text). The high-density two-row symbology
75-
:data:`image.PDF417` decodes too, and the
76-
shelf-edge family
76+
text). The shelf-edge family
7777
:data:`image.DATABAR` (RSS-14) and
7878
:data:`image.DATABAR_EXP` (RSS-Expanded)
7979
round out the list.
@@ -248,15 +248,3 @@ adds, so applications that do this
248248
typically narrow each pass with an
249249
appropriate ``roi`` rather than searching
250250
the full frame for every kind of code.
251-
252-
With 1D barcodes, Data Matrix codes, QR
253-
codes, and AprilTags, the camera reads
254-
the four families of printed and etched
255-
symbols an application is likely to
256-
encounter. The remaining detectors do not
257-
decode symbols at all but instead measure
258-
similarity: how closely two patches of
259-
the same captured frame, or two frames at
260-
different times, line up with each other.
261-
That is the work of the matching methods,
262-
and they come next.

docs/openmvcam/tutorial/image/decoding/qr-apriltag.rst

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ objects:
5353
The detector takes a single optional ``roi``
5454
to restrict the search. It needs grayscale
5555
input -- a colour frame is converted
56-
internally before decoding -- and it works
57-
on every supported board except the M4.
56+
internally before decoding.
5857

5958
Each detection carries the bounding box
6059
(``x``, ``y``, ``w``, ``h``, ``rect``), the
@@ -153,12 +152,25 @@ families are :data:`image.TAG16H5`,
153152
:data:`image.TAGCUSTOM48H12`,
154153
:data:`image.TAGSTANDARD41H12`, and
155154
:data:`image.TAGSTANDARD52H13`. Each family
156-
trades off ID count against
157-
error-correction strength: ``TAG16H5`` has
158-
30 IDs and 0 bit errors tolerated;
159-
``TAG25H9`` has 35 IDs and 3 bit errors;
155+
trades off ID count against robustness. The
156+
``H`` number in the name is the minimum
157+
*Hamming distance* between any two codes in
158+
the family -- how many bits must flip before
159+
one valid code turns into another --
160+
``TAG16H5`` has 30 IDs at distance 5,
161+
``TAG25H9`` has 35 IDs at distance 9, and
160162
``TAG36H11`` (the default and the most
161-
common) has 587 IDs and 4 bit errors.
163+
common) has 587 IDs at distance 11. The
164+
detector corrects up to two bit errors no
165+
matter the family, so the distance decides
166+
how risky that correction is: a random
167+
pattern in a noisy frame only has to land
168+
within two bits of a valid code to decode as
169+
a false detection, and the higher-distance
170+
families spread their codes so much more
171+
sparsely that such collisions become rare --
172+
the reason ``TAG36H11`` is the recommended
173+
choice.
162174
Detection time scales with the number of
163175
enabled families, so an application enables
164176
only what it actually prints. The bitmask
@@ -282,13 +294,3 @@ The two detectors run independently on the
282294
same frame and the application correlates
283295
their bounding boxes to match each tag to
284296
its companion code.
285-
286-
With QR codes for arbitrary payloads and
287-
AprilTags for IDs and pose, the cam can
288-
read the two most common 2D codes the
289-
camera will ever see. Older code families
290-
the camera also handles -- the 1D barcodes
291-
printed on consumer goods and the
292-
high-density Data Matrix codes printed on
293-
industrial parts -- have their own
294-
detectors, and those come next.

docs/openmvcam/tutorial/image/figures/convolution-kernel.svg

Lines changed: 14 additions & 10 deletions
Loading

0 commit comments

Comments
 (0)