2.4.1 (2026-10-13)
- BundleAdjust fixed landmarks and pgraph 1.0 Vertex (1467091)
- BundleAdjust fixed landmarks and pgraph 1.0 Vertex (195e895)
- docs: install spatialmath and pgraph with deps=False in JupyterLite (201f234)
- docs: install spatialmath and pgraph with deps=False in JupyterLite (5615b3b)
- don't pass a positional argument to pgraph.UGraph (f5590e0)
- don't pass a positional argument to pgraph.UGraph (6fb62e5)
- estimatePose misaligned ids and corners when other markers are in view (43c5980)
- FiducialCollection.estimatePose() misaligned ids and corners (#52) (c054867)
- remove labeltool console script that points at a module that was never committed (#117) (ef39fa9)
- remove labeltool console script whose module was never committed (30b5c6a)
- add a script and README for the block icons (1185da9)
- add a script and README for the block icons (2206b53)
- add Codacy grade badge to README (f91ed2c)
- add CONTRIBUTING.md (1885fc1)
- note how to use a phone as a camera in WebCam and VideoCamera (76cea5e)
- note how to use a phone as a camera in WebCam and VideoCamera (72ca04b)
2.4.0 (2026-08-25)
- add array protocol to Image and Kernel, ndim to Kernel (e762f57)
- relax opencv pin to support both 4.x and 5.x, add CI matrix axis (2ec69fe), closes #44
- assert hygiene -- unreachable assert, two caller-facing checks (7afe33e)
- CameraBase.plot() unbound call (self=None) crashed instead of working (e2d4600)
- catch cv2.error in points2F(), not just F/mask=None (c4197cb)
- correct stale open3d-python PyPI name, add py3.13 exclusion marker (87c1e8f)
- esttheta() -- broken pickregion() helper and missing theta-sweep body (50b00cc)
- exclude tests/ from Bandit's assert_used (B101) check (e62b116)
- Histogram.plot(type='ncdf') never actually worked, docstring lied (6d4152d)
- idisp() crashes when reuse=True with no title given (a05b13b)
- Image.metadata() missing camera-specific Exif sub-IFD tags (d554ef2)
- Image() drops maxintval when dtype= is also given, silently truncating (15f1d32)
- Image(dtype='float') resolved to float64, not float32 (18c5d85)
- ImageConstantsMixin factories silently downcast explicit dtype requests (977dbf6)
- mvtbtool's %precision line spuriously echoes with --showassign (ed43ca6)
- name2color() colororder reordering returns list, not ndarray (c90e6fb)
- PointCloud.Read() double-joins a caller-supplied "data/" prefix (fff671c)
- printstats() crashes if .stats hasn't been accessed yet (3484224)
- suppress divide-by-zero RuntimeWarning in BagOfWords idf computation (05c85e0)
- visual-odometry robustness -- match() metric, points2F(), BundleAdjust (8691847)
- add AGENTS.md stub linking to rvc-ecosystem conventions (0827291)
- points2F() kwargs -- correct which params apply to which method (6b10d64)
2.3.0 (2026-08-13)
Highlight: Notebooks working in all environments Fixed a number of problems with getting notebooks to execute in desktop Jupyter, Colab, and JupyterLite in browser. Created nice framework to keep the environment-specific import logic in each notebook consistent at commit time. Added CI tests and also CI check that notebooks runs in the pyodide environment. Currently pinning to pyodide 0.6.1 to sidestep the lack of JSPI support in Safari and Firefox required by later pyodide kernels.
- ci: add a real-Pyodide dependency-completeness check for JupyterLite (9072da6)
- notebooks: add shared environment-bootstrap module and drift-check tooling (44242e8)
- notebooks: migrate all notebooks to the generated bootstrap cell (75f230c)
- ci: guard release-please's PyPI-publish trigger against the truthy-string bug (#74) (0d74276)
- ci: pass --repo to gh calls in release-please's PyPI-publish trigger (#73) (6ff01a3)
- docs: pin jupyterlite-pyodide-kernel==0.6.1, matching RTB and bdsim (76bd7e1)
- notebooks: fix JupyterLite bugs found via real-browser testing (3979404)
- release-please never triggered the actual PyPI publish (18cc08b)
- readme: move to standard badge layout (0722f9d)
2.2.0 (2026-08-10)
Highlight: OpenCV 5 compatibility. MVTB now works correctly under both OpenCV 4 and the newly-released OpenCV 5 — aruco/fiducial pose estimation, HoughLinesP line features, BRISK/AKAZE point features, and MSER region features have all been fixed for OpenCV 5's API and shape changes, verified against real OpenCV 4.13.0 and 5.0.0 installs. See #44 for the full compatibility audit.
- add mvtbtool --test smoke test, fix silent Open3D banner skip (6a0bf2c)
- handle HoughLinesP's (N,4) return shape on OpenCV 5 (b54f755)
- handle MSER's empty-tuple bboxes on OpenCV 5, resolve MSER discrepancy (aabaf88)
- normalize aruco ids/matchImagePoints shapes for OpenCV 5 (6ac5ec0)
- replace removed cv2.aruco.estimatePoseSingleMarkers with solvePnP (635225d)
- resolve BRISK/AKAZE via cv2.xfeatures2d on OpenCV 5 (fad7247)
2.1.0 (2026-08-03)
- add interactive tools to imtool and bagtool (b16ab7d)
- mvtbtool: add 'tool' extra for IPython/pygments, fail with clear message when missing (a31655b)
- add missing type annotations, warn on ncdf deprecation (7e8cabe)
- add socket timeout to iread() URL fetches (6ff62b1)
- bring 3 mixins in line with the TYPE_CHECKING _ImageBase pattern (0d31fc5)
- colorplane handling in image i/o (6882967)
- gridify() IndexError from numpy float // int staying float64 (e57597a)
- keep single-blob filter() matches (7b0ab8d), closes #17
- replace 6 bare except: clauses with specific exception types (5a11306)
- un-hide bot-comment notes from HTML comment block (4a4e943)
- use eigh instead of eig for blob orientation/ellipse moments (3a74fdf)
- add build date to footer copyright notice (e7de5bf)
- add example placeholder to Alternatives considered (879f086)
- add PR and issue templates (d081f7e)
- ask for a concrete function signature in feature requests (b25cd12)
- fix docstring convention note, add Codacy heads-up (d68f605)
- fix Image class sidebar, cut over to sphinx-pyrunblock (20c219d)
- fix stale rank() reference in card-algorithms.rst (1e3f6bd)
- fix stale/broken references and add footer build date (c51955b)
- flesh out PR template with a proper checklist (f4db44b)
- forewarn contributors about Dependabot vulnerability comments (acfedab)
- log ci.yml's conda/micromamba setup as tech debt (af09d07)
- log Codacy backlog real numbers to tech-debt (65b3c5e)
- log gridify() IndexError bug found while testing bare-except fix (889d45c)
- log Histogram.plot type= docstring/behavior mismatch (e693eef)
- log mypy-not-in-CI as high-priority tech debt, with fresh audit (1b74ae8)
- log pgraph-python CI gap and conda-migration decision to tech-debt (c5b6aeb)
- log PR #32/#33 Codacy findings (type shadowing, F405, max param) (e0ed8db)
- migrate tech-debt.md to GitHub Issues (tech-debt label) (36aae6a)
- remove reference to nonexistent CentralCamera.decomposeF (c7f1400)
- switch sphinx-codeautolink to released 0.19.0, drop branch pin (594a9a1)
- use %pip magic in notebooks, add tagline to README (843db36)
2.0.0 May 2026
-
Added
- image sources
ROSBagreads images and point clouds from ROS 1/2 bag filesROSTopicreads images and point clouds from live ROS 1/2 systems viarosbridgeImageSequence: a sequence of image objectsPointCloudSequence: a sequence of point cloud objectsTensorStack: reads images from a batch tensorLabelMeReader: returns image and shape data from a LabelMe JSON file
- CLI tools
bagtool: animate images or point clouds from a ROS 1/2 bag fileocrtool: write OCR text to stdout or JSON
- documentation
- ecosystem diagram
- new Sphinx sections for ROS, PyTorch, NumPy integration, and Jupyter
- code copy button for examples (strips
>>>prompts) - top-level of reST documentation now uses sphinx-design and a card-based TOC
- image sources
-
Changed
- CI and packaging
- changed
masterbranch tomain - reworked and renamed CI files
- replaced
flake8withruff - added extras:
jupyter,pytorch,ros,ocr - added
allextra to install all optional extras - consolidated documentation and notebooks into
docs
- changed
- code quality
- tested with Python 3.13
- improved behaviour when Open3D is unavailable
- many more unit tests, with average coverage now > 50%
- consistent and PEP-conformant
repr()andstr()formatting - more consistent handling of lazy imports
- systematic use of
import cv2 - consistent naming of test files
- PEP 8/257-compliant import grouping and module docstrings
- revisited suppression comment tags for validity and currency
- normalized deprecation/warning/docstring language with explicit version tagging
- image I/O and display
ireadnow usescv2.imdecodeinstead of PIL, with internal refactor for corner casesiread_iteris an efficient lazy wildcard iteratoridispnow includes keyboard display and animation controls whenfpsoranimateis specified- fixed
idispissues with Jupyter Matplotlib backend selection (for example%matplotlib widget) idispcan now put text labels on colorbar ticks
Imageclass and core API- image NumPy array for pixel data
- deprecate
.Aproperty, setting.Anow raises an exception - systematic internal use of
._Afor array access .arrayfor user use, provide a read-only view of the pixel data
- deprecate
- uses
_image_typing.pyprotocol to resolveImagetype across mixins - improved color order and type logic
Image(..., dtype=True)forces image dtype to match the ndarray; otherwise the smallest fitting dtype is selectedsizeoption supports turning pixel row/column data into 2D or 3D imagesImage.Tensor()andimg.tensor()for PyTorch import/export- statistics improvements:
sum,min,max,mean,std,medianforward arguments to NumPy (for exampleaxis)img.statsis now a property returning per-plane statisticsimg.printstats()prints formatted per-plane statistics- all are computed lazily
- thresholding improvements:
- native NumPy implementations for
otsuandtrianglethreshold estimators threshold_interactivereworked for Jupyter support
- native NumPy implementations for
- NaN/Inf handling:
img.numnanandimg.numinfpropertiesfixbad()for remediation- reporting in
repr()andstr()
- NumPy ufunc integration (for example
np.ceil(img)returns anImage) %operator stacks images plane-wise (for exampleimg1 % img2,img1 % 0)Image.Random()- supports multi-channel images
- now has a
pdfarugment to create an image with arbitary pixel-value distribution.
img1.sameas(img2)performs scalar equality checks across datatype/planes/pixels (img1 == img2remains element-wise)- image histogram properties
h,pdf,cf,cdfare now computed lazily, and each returns a 2-tuple of ndarays (statistic, x). These property names match those of theHistogramclass. They were formally calledh,cdf, andncdfand return just a single ndarray. __str__now includes image statistics like mean, std, median.- all "constant constructors" like
Zeros,Constant,Randometc. now have a consistent API with keyword argumentssize,dtype,colororder,like. Kernel.Gaussandsmoothwith a half-width butsigma=0will use a rule-of-thumb to estimate a goodsigmavalueshowpixelshas a major improvement in visual appearance, some parameters now gone. The animation window has been refactored intoshowwindow.examples/morphdemoshows this in action.rprintis a variant ofprintthat returns the image object, soimg = Image.Random(size=5).rprint()does an assignment toimgand displays the pixel values to stdout in one line.
- image NumPy array for pixel data
Histogramclass- now has a
pdfproperty for an estimated/empirical probability density function - cumulative frequency is renamed from
cdftocf;ncdfrenamed tocdf - now implemented using NumPy rather than OpenCV for wider dtype support
- works properly in Jupyter
- histogram computation moved to constructor
clipcontrols bin range behaviour- plotting options for
span,log,cursor, andstatsmarkers
- now has a
Blobsclass- major internal refactor;
Blobis now a dataclass - improved handling of runt (single-pixel) blobs
- added
idmethod - new attributes/methods:
MER()/plot_MER(),MEC()/plot_MEC() - added default color and linestyle to all plot functions. These all accept Matplotlib format string or keyword arguments for line styling
- major internal refactor;
- Image sources
- all sources are iterators and context managers, reworked the common abstract base class
- all sources inherit display/animation (
.disp()) and batch tensor (.tensor()) methods - all sources accept keyword arguments forwarded to
convert VideoCamerahas a newlistmethod showing camera name/id mappingVideoFile,WebCam, andEarthVieware unchanged
- CLI
- improved
--helpstrings and option ordering mvtbtoolsupports image preloading into the IPython namespace, autoreload, optional PyTorch import, andMVTB_OPTIONSenvironment variabletagtoolreports ArUco/April tags to stdout or JSON
- improved
- notebook support
- notebooks revamped and extended
threshold_interactiveworks in Jupyter- notebook workflows are unit-testable
- distributed as a ZIP built by GitHub Actions
- distributed in a zero-install JupyterLite environment (WASM + Emscripten)
- CI and packaging
-
Deprecated
iread(..., grey=...)andiread(..., gray=...); usemono=insteadimg.imageandimg.A; useimg.arrayimg.to_int()andimg.to_float(); useimg.array_as()column; useview1dthresh(); usethreshold()- threshold keyword
t; usethreshold - threshold keyword
opt; usemethod ithresh; usethreshold_interactiveadaptive_threshold; usethreshold_adaptive- legacy
Image.Constantpositional size form (for example migrate fromImage.Constant(10, 20, 30)toImage.Constant(30, size=(10, 20))) ImageCollection; useFileCollectionZipArchive; useFileArchiverank; userankfilterImage.Zeros(10)is nowImage.Zeros(size=10)Image.Constant(3,4,5)is nowImage.Constant(5, size=(3,4))Image.Random(10)is nowImage.Random(size=10)
-
Fixed
- resolved many Sphinx warnings
- resolved issues in plot/runblock examples
- improved OpenCV documentation link consistency where intersphinx is not effective
- fixed issues in
idispthat confused Jupyter Matplotlib backend selection
-
Miscellaneous
- generated OpenCV guard functions from OpenCV documentation for input validation
Kernelclass refactored to its own file- ROS synchronization support via
SyncROSStreams
1.0.2 January 2026
-
Imageclass-
warp_affinecan now warp an image into a given output image -
graphic primitives
-
create an ArUco marker
-
save as PDF
-
all the draw_xxx() functions in base now have wrappers as methods of
Image -
draw_xxx() now handle floating point arguments, rounding them to the neares int
-
improvements in name2color to handle image datatypes and colororder
-
-
FiducialCollection class, represent a generalized calibration board with AR tags
-
ArUcoBoard class, represent a generalized ArUco calibration board
-
changed to src folder layout, code is in src/machinevisiontoolbox
-
changed from setuptools to hatch
-
works if Open3D is not installed, it's always well behind in Python version support
-
removed numpy < 2.0 constraint, OpenCV now suppports numpy 2.x
-
working with Python 3.12 (except for Open3D)
-
added command line tools:
imtoolfor displaying images, exploring pixels, picking points, showing metadata etc. Works with your own images or those provided with MVTBtagtoolfor highlighting AR tags in images
1.0.1 March 2025
-
Imageclass.dicemethod, chops an image up into tiles, can be overlapping.Tile(columns=0)will arrange the tiles into a roughly square layout- Constant images, previously many of these could only generate square images, this is now generalized
.Chequerboardcreates a chequerboard pattern- set background color for image warp undefined pixels
- single plane images can have a colorplane name
- deprecate
colordict(), usecolororder2dict()instead Stringnow supports two string formats, can create color images- fixed bug with gamma="sRGB" which always returned a float image, type is now the same as passed
-
Blobs
- new methods for blob aligned box, plot_aligned_box,
plot_perimeteroptionsperimeter_hullconvex hull- fixed bug with runt blobs
-
Kernels
- added
Kernel.HGaussfor Hessian of Gaussian - added
Kernelrepr method,dispmethod ArUcoBoard class
- added
-
Camera models
- Fixed errors in some camera projection models
-
Point clouds
PointCloudnow has a "constructor" for depth images,PointCloud.DepthImage()
-
Miscellaneous
- Lots more code examples and plots
- Move decoratores scalar_result and array_result to machinevisiontoolbox.decorators.py
- improved unit testing
1.0.0 January 2025
-
Kernelmethods now returnKernelinstances rather than NumPy arrays. Methods that accept a kernel can accept aKernelinstance or a NumPy array. Methods exist to stringify or print a kernel. -
The indexing order of an
Imageobject (using square bracket__getitem__access) has changed and is nowimg[u,v]whereuis the column coordinate andvis the row coordinate. This is consistent with the column-first convention used across the Toolbox and is consistent with the$(u,v)$ coordinate system for images. But, this is the opposite order to that used for NumPy index on the underlying array, and to earlier versions of the Toolbox.- a 2-tuple of integers, select this pixel. If the image has multiple planes, the result is a vector over planes.
- a 3-tuple of integers, for a multiplane image select this pixel from the specified plane.
- a 2-tuple of slice objects, select this region. If the image has multiple planes, the result is a 3D array.
- a 3-tuple of slice objects, select this region of uv and planes
- an int, select this plane
- a string, select this named plane or planes
-
added
pixel(u,v)method for faster access to a single pixel value, scalar or vector. -
the children of a
Blobis now given as a list ofBlobobjects, not their indices within the overall list of blobs. This simplies traversing the blob hierarchy tree. Similarly, the parent is a reference to the parentBlobobject rather than an index, and isNoneif the blob has no parent (its parent is the background). -
Documentation overhaul, both in-code docstrings, and the organization of the overall Sphinx document.
-
Additional unit tests
-
Myriad minor bug fixes, see commit history.