fix: Image(dtype='float') resolved to float64, not float32 - #86
Open
petercorke wants to merge 1 commit into
Open
fix: Image(dtype='float') resolved to float64, not float32#86petercorke wants to merge 1 commit into
petercorke wants to merge 1 commit into
Conversation
Two independent, inconsistent dtype-string resolvers existed:
convert() had its own dtype_alias dict ('float'->'float32', 'double'
->'float64', 'int'->'uint8', 'half'->'float16') since NumPy's own
np.dtype('float') means float64, not float32. Image.__init__'s
_infer_dtype had no such table -- it called np.dtype(dtype) raw. Since
dtype is Image.__init__'s own named parameter (not forwarded via
**kwargs to convert()), Image(arr, dtype='float', mono=True) sent
'float' through the unaliased path -> float64, while 'mono' went
through convert()'s correctly-aliased one.
Root-caused via RVC3-python's chap11.ipynb motion-detection example:
VideoFile("...", mono=True, dtype='float') produced float64 frames,
and arithmetic on them stayed float64 all the way to
Image.disp(matplotlib=False), where OpenCV's cvtColor doesn't support
CV_64F -- 'Unsupported depth of input image'.
Fix: hoisted the alias table to a single shared constant,
machinevisiontoolbox.base.types.DTYPE_ALIASES, used by both convert()
and _infer_dtype. Documented the aliases via one Sphinx rst_epilog
substitution (|dtype_aliases|, matching the existing |RVC3| pattern
and bdsim's |BlockOptions| convention) referenced from both
docstrings, rather than duplicating the explanation.
Since every ImageSource (VideoFile, VideoCamera, ImageCollection, ...)
constructs Image instances with a dtype= option, this affects all of
them uniformly, not just VideoFile.
Added tests/test_dtype_resolution.py: a single parametrized matrix
(every DTYPE_ALIASES case x every dtype-resolving entry point) rather
than scattered one-off tests per bug. Three independent, inconsistent
dtype resolvers turned out to exist across this codebase (this one,
plus Image.to()/.array_as()/.astype(), plus the ImageConstantsMixin
factory methods -- both to be fixed on separate follow-up branches);
this module is designed to grow a test method per entry point as each
one is fixed, so the whole class of bug is pinned down in one place
instead of drifting silently again.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Not up to standards ⛔🔴 Issues
|
| Category | Results |
|---|---|
| Security | 2 high |
🟢 Metrics 0 complexity · 0 duplication
Metric Results Complexity 0 Duplication 0
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
This was referenced Aug 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two independent, inconsistent dtype-string resolvers existed:
convert()had its owndtype_aliasdict ('float'->'float32','double'->'float64','int'->'uint8','half'->'float16') since NumPy's ownnp.dtype('float')meansfloat64, notfloat32.Image.__init__'s_infer_dtypehad no such table -- it callednp.dtype(dtype)raw.Since
dtypeisImage.__init__'s own named parameter (not forwarded via**kwargstoconvert()),Image(arr, dtype='float', mono=True)sent'float'through the unaliased path ->float64, while'mono'went throughconvert()'s correctly-aliased one.Root-caused via RVC3-python's chap11.ipynb motion-detection example:
VideoFile("...", mono=True, dtype='float')producedfloat64frames, and arithmetic on them stayedfloat64all the way toImage.disp(matplotlib=False), where OpenCV'scvtColordoesn't supportCV_64F--'Unsupported depth of input image'.Fix: hoisted the alias table to a single shared constant,
machinevisiontoolbox.base.types.DTYPE_ALIASES, used by bothconvert()and_infer_dtype. Documented the aliases via one Sphinxrst_epilogsubstitution (|dtype_aliases|, matching the existing|RVC3|pattern and bdsim's|BlockOptions|convention) referenced from both docstrings, rather than duplicating the explanation.Since every
ImageSource(VideoFile,VideoCamera,ImageCollection, ...) constructsImageinstances with adtype=option, this affects all of them uniformly, not justVideoFile.Note on scope: this uncovered a broader pattern -- three independent, inconsistent dtype resolvers exist across this codebase. This PR fixes the constructor/
convert()pair.Image.to()/.array_as()/.astype()(same alias bug) and theImageConstantsMixinfactory methods (Zeros/Constant/Random/... -- a different bug, they silently downcast even an explicitdtype='float64'request tofloat32since they don't forwarddtype=to the constructor) will be fixed on separate follow-up branches/PRs.Test plan
tests/test_dtype_resolution.py: a single parametrized matrix (everyDTYPE_ALIASEScase x every dtype-resolving entry point fixed so far) rather than scattered one-off tests -- designed to grow a test method per entry point as the follow-up PRs land, so this whole bug class stays pinned down in one placeint64instead ofuint8,float64instead offloat32); pass with the fixtests/test_image_core.py+tests/base/test_io.py+tests/test_dtype_resolution.pysuites pass (220 passed)