| ⬜ Q1 |
Deconvolution family |
The same KernelZeroMagnitudeThreshold ε is compared against |H| by Inverse but against the |H|²-carrying denominator by Tikhonov/Wiener — "regularization → 0 equals inverse" fails in the band ε ≤ |H| < √ε. |
| ⬜ Q2 |
DiscreteGaussianDerivativeImageFilter |
Never calls FlipAxes(), unlike DerivativeImageFilter/GradientImageFilter (which do) — odd-order derivatives carry the opposite sign vs. its siblings. Also the inter-axis intermediate is Image<OutputPixelType>, so integer outputs truncate per axis pass (the local comments say "real to real"). |
| ⬜ Q3 |
ThresholdSegmentationLevelSetImageFilter |
The class doc (.h:63-65) states positive = inside — the opposite of the convention its own base class documents (itkSegmentationLevelSetImageFilter.h:82-84: negative inside). |
| ⬜ Q4 |
Segmentation level-set functions |
CurvatureSpeed is overridden to PropagationSpeed only by GeodesicActiveContour and ShapeDetection; Threshold/Laplacian/Canny keep the base-class constant 1 — an undocumented asymmetry across siblings. |
| ⬜ Q5 |
BinaryContourImageFilter |
Non-foreground pixels keep their original values verbatim (.hxx:164-179) — they are not normalized to BackgroundValue, so several distinct non-foreground input values all survive into the output. |
| ⬜ Q6 |
SimpleContourExtractorImageFilter |
InputForegroundValue == InputBackgroundValue marks every foreground pixel as contour (the neighborhood scan includes the center pixel, .hxx:84). |
| ⬜ Q7 |
BinaryReconstructionByErosionImageFilter |
Built on the complement via BinaryNot; BackgroundValue is consumed only as a self-consistent internal sentinel — the parameter has no effect on the output. |
| ⬜ Q8 |
AnisotropicDiffusionImageFilter |
An unstable time step warns and proceeds; the clamp is present but commented out (.hxx:68). |
| ⬜ Q9 |
ThresholdMaximumConnectedComponentsImageFilter |
m_LowerBoundary is written once in the constructor and read only by PrintSelf — dead configuration with no setter. |
| ⬜ Q10 |
MinMaxCurvatureFlowFunction |
SetStencilRadius clamps to ≥ 1 (.hxx:43), making the radius == 0 early-outs (.hxx:217-220, 276-279) unreachable dead code. |
| ⬜ Q11 |
ScalarImageKmeansImageFilter |
Overrides the estimator's defaults in GenerateData (SetMaximumIteration(200), threshold 0.0, .hxx:91-92), invisibly to users; and KdTreeBasedKmeansEstimator's loop tests the limit pre-increment after the refinement pass (.hxx:327-347) — MaximumIteration = n runs n+1 passes while GetCurrentIteration() reports n. |
| ⬜ Q12 |
SLICImageFilter |
Enforce-connectivity relabels an undersized component to the previously-encountered label, whatever it is (.hxx:544-546); there is no final relabel/compaction pass; per-pixel distances accumulate in float. |
| ⬜ Q13 |
BoxMean/BoxSigmaImageFilter |
The window crops at the image border and divides by the cropped count (itkBoxUtilities.h:322-324, 499-501) — border statistics use fewer samples. A ZeroFluxNeumannBoundaryCondition is declared (L215/389) but never used, suggesting replication was once intended. |
| ⬜ Q14 |
BinShrinkImageFilter |
Throws when a shrink factor exceeds the axis size where ShrinkImageFilter silently clamps to 1 (.hxx:289-296 vs itkShrinkImageFilter.hxx:265-267); integer outputs round half-up while float outputs truncate (RoundIfInteger, .h:135-149). |
| ⬜ Q15 |
AntiAliasBinaryImageFilter |
A constant input (even all-maximum) shifts to 0 under the max − (max−min)/2 iso-value and the strict > 0 sign test (.hxx:109; base .hxx:605) — the output is uniformly negative, i.e. "all inside". |
| ⬜ Q16 |
ReinitializeLevelSetImageFilter |
Narrow-band mode pre-fills the whole output with ±NumericTraits<PixelType>::max() and only overwrites band points (.hxx:206-225) — far-field pixels keep ±max rather than a distance-like magnitude. |
| ⬜ Q17 |
FastMarchingUpwindGradientImageFilter |
m_TargetValue is overwritten at every accepted point in NoTargets mode; in Some/AllTargets modes the reached test is sticky, so every later accepted point — target or not — keeps advancing it; OneTarget reports the last reached target, not the first (.hxx:154-227). |
| ⬜ Q18 |
CollidingFrontsImageFilter |
ApplyConnectivity's flood fill is seeded on SeedPoints1 alone (.hxx:114-122), so the forced −1e-6 at every SeedPoints2 seed (.hxx:92-97) is dropped from the output unless that seed is face-connected to front 1's region. |
| ⬜ Q19 |
itk::watershed::Segmenter |
Edge lists are sorted with a height-only operator< (itkWatershedSegmentTable.h:73-82); a NaN height compares "equivalent" to everything — a strict-weak-ordering violation (formal UB; benign merge-equal in libstdc++). |
| ⬜ Q20 |
itkMath.h FloatAlmostEqual |
The absolute-difference test (default 0.1 · epsilon) returns equal before the signbit check (itkMath.h:334-352) — 0.0 == -0.0, and near-zero pairs millions of ULPs apart compare equal, partially defeating the documented ULP semantics. |
| ⬜ Q21 |
MultiphaseDenseFiniteDifferenceImageFilter |
Computes the CFL time step then discards it: timeStep = 0.08; // FIXME !!! After all this work, assign a constant !!! Why ?? (.hxx:153-154). |
| ⬜ Q22 |
Chan-Vese UseImageSpacing |
Builds m_ScaleCoefficients that nothing in the Chan-Vese chain reads; the PDE divides by m_InvSpacing from the feature image unconditionally while the re-distancing Maurer map inherits the level-set image's spacing — the flag's only live effect is maurer->SetUseImageSpacing (.hxx:227). Two images with different spacings drive the PDE and the re-distancing with different metrics. |
| ⬜ Q23 |
ScalarChanAndVeseDenseLevelSet RMS/labeling |
m_ReinitializeCounter defaults to 1, so the reinit branch runs every iteration, zeroes the RMS accumulator, and refills it with the re-distancing residual (.hxx:214-248) — MaximumRMSError halting compares against the wrong quantity. CopyInputToOutput labels phi < 0 strictly (.hxx:69), so exactly-zero boundary pixels are excluded from the label. |
| ⬜ Q24 |
ObjectMorphologyImageFilter |
BeforeThreadedGenerateData's fill-then-conditional-copy always reduces to output := input (the fill sentinel is constructed to differ from ObjectValue, .hxx:87-113); UseBoundaryCondition is dead configuration (installed but never enabled, .h:145 even warns "Don't forget to set UseBoundaryCondition to true!"); boundary detection is a hard-coded 3^dim box decoupled from the kernel radius (.hxx:130-198) — dilation is unaffected, erosion diverges substantially from true erosion (the header caveats this). |
| 🔄 Q25 |
IterativeInverseDisplacementFieldImageFilter |
the coordinate-descent probe step is axis 0's spacing on every axis |
| 🔄 Q26 |
DisplacementFieldJacobianDeterminantFilter |
SetDerivativeWeights silently flips UseImageSpacing off — precedence between the two is last-writer-wins, while the class doc describes only one ordering |
| 🔄 Q27 |
WarpImageFilter |
m_OutputSize[0] == 0 alone keys "size unset"; output-grid defaults are unit/zero/identity from neither input; the field is sampled with edge replication, never out-of-domain |
| 🔄 Q28 |
VectorConnectedComponentImageFilter |
zero vectors join anything under the default threshold (no special case); concept macro name typo InputValyeTypeIsFloatingCheck |
| 🔄 Q29 |
MahalanobisDistanceMembershipFunction |
the det < 0 exception branch is unreachable; GetCovariance() never reflects the singular-case substitute |
| 🔄 Q30 |
FastSymmetricForcesDemonsRegistrationFilter |
its difference function is ESMDemonsRegistrationFunction; the identically-named FastSymmetricForcesDemonsRegistrationFunction class is orphaned from its own filter |
| 🔄 Q31 |
ExponentialDisplacementFieldImageFilter |
"take the ceil" comment vs + 1.0-then-truncate code (integral values overshoot by 1); a zero field still runs one squaring iteration |
| 🔄 Q32 |
WarpVectorImageFilter (as wired by DiffeomorphicDemonsRegistrationFilter) |
under the nearest-neighbor-extrapolating interpolator, IsInsideBuffer is always true and m_EdgePaddingValue is dead code |
| 🔄 Q33 |
ESMDemonsRegistrationFunction |
the WarpedMoving and MappedMoving gradient options coincide exactly at a zero displacement field (interior pixels, default linear interpolation, coincident grids) |
| 🔄 Q34 |
LevelSetMotionRegistrationFilter/Function |
dt = 1/maxL1 makes the applied step at the governing pixel exactly Alpha-independent; thresholded pixels count toward the metric while out-of-buffer pixels don't; Halt adds an RMS==0 clause the base can never fire |
| 🔄 Q35 |
LevelSetMotionRegistrationFunction |
one-sided difference steps add index-axis spacing to a physical coordinate — wrong direction and step under non-identity direction cosines |
| 🔄 Q36 |
demons family |
zero-iteration runs report GetRMSChange() == 0 but GetMetric() == NumericTraits<double>::max() in the two filters that don't override GetRMSChange |
| 🔄 Q37 |
LevelSetMotionRegistrationFunction smoothing |
the smoothed moving image is re-quantized to the moving image's own pixel type (u8 in → u8 smoothed) before the gradient; and any axis shorter than 4 pixels is a hard error for this family member only |
| 🔄 Q38 |
FastMarchingImageFilterBase::IsChangeWellComposed3D |
builds its neighborhood iterator over GetRequestedRegion() (empty, never set) where the 2-D sibling and the strict-topology check use GetBufferedRegion() — harmless (only SetLocation+GetPixel are used) but inconsistent (.hxx:779 vs :583/:619) |
| ⬜ Q39 |
LabelToRGBImageFilter |
background is always fixed black (m_BackgroundColor zero-filled at construction); the functor comment promising a "gray pixel matching the background intensity" describes LabelOverlayFunctor, not this class (itkLabelToRGBFunctor.h:93-98) |
| ⬜ Q40 |
LabelToRGB/LabelOverlay palette |
the 0–255 palette constants are rescaled by NumericTraits<output RGB component>::max() rather than a fixed 255 (itkLabelToRGBFunctor.h:110-117) — a double RGB output scales the palette into [0, ≈1.8e308] |
| ⬜ Q41 |
HessianToObjectnessMeasureImageFilter |
eigenvalues are sorted by |λ| with unstable std::sort (equal-magnitude order unspecified, .hxx:78-79); alpha == 0 skips only the R_A factor while beta == 0 (or a zero denominator) zeroes the whole measure (.hxx:111-151) — asymmetric parameter semantics |
| ⬜ Q42 |
ComplexToModulusImageFilter |
computes sqrt(re*re + im*im) in the component type (.h:46-50): ComplexFloat32 overflows to inf above |component| ≈ 1.8e19 and flushes to 0 near denormals, where std::hypot would not |
| ⬜ Q43 |
RelabelLabelMapFilter |
class doc says objects are reassigned via PushLabelObject; the inherited implementation uses SetLabel + AddLabelObject against a counter from 0 (itkAttributeRelabelLabelMapFilter.hxx:64-79) |
| ⬜ Q44 |
LabelMap::HasLabel |
doc says the background label also returns true; the implementation is a plain find(label) != end(), which returns false for background (.hxx:151-153) |
| ⬜ Q45 |
StatisticsLabelMapFilter weighted moments |
adds spacing²/12 (the pixel's own second moment) to every central-moment diagonal (.hxx:224-228) while ShapeLabelMapFilter does not — WeightedPrincipalMoments exceed PrincipalMoments by 1/12 per eigenvalue even on a constant feature image |
| ⬜ Q46 |
StatisticsLabelMapFilter extremum indices |
min/max index updates are non-strict (v <= min, v >= max, .hxx:118-127) — on ties the recorded index is the last tie in raster order |
| ⬜ Q47 |
itk::Statistics::Histogram::Initialize |
computes the bin interval and every non-final bin bound in float (itkHistogram.hxx:225-236) — a Histogram<double> gets float-quantized bin edges, which StatisticsLabelMapFilter's Median inherits |
| ⬜ Q48 |
ImageBase::IsCongruentImageGeometry |
scales the coordinate tolerance by this->GetSpacing()[0] only (itkImageBase.hxx:400-405) — the predicate is asymmetric when the two images differ in axis-0 spacing, and axes 1+ are judged against axis 0's scale |
| ⬜ Q49 |
DivideImageFilter::Div |
a near-zero divisor returns NumericTraits<TOutput>::max() regardless of the numerator's sign or magnitude (itkArithmeticOpsFunctors.h:142-151); through NormalizeToConstantImageFilter a zero-sum input sends the entire output to the type maximum |
| ⬜ Q50 |
VotingBinaryHoleFillingImageFilter |
the else-branch stamps it.Set(foregroundValue) for any center value other than backgroundValue (.hxx:138-141) — a third pixel value is silently promoted to foreground without counting toward GetNumberOfPixelsChanged(); the iterative sibling inherits this |
| ⬜ Q51 |
ExtractImageFilter |
the output origin ignores a collapsed axis's start index (and the collapsed↔retained direction coupling), so extracting slice k of an oblique volume reports slice 0's origin (.hxx:74-85, :162-179) |
| ⬜ Q52 |
CenteredVersorTransformInitializer::ComputeRotation |
uses R = M·Fᵀ (.hxx:47), which does not satisfy the covariance-aligning identity R·Cov_f·Rᵀ = Cov_m (that requires Mᵀ·F); with per-image independent eigenvector sign canonicalization the initializer can 180°-flip an axis |
| ⬜ Q53 |
CompositeTransform |
Get/SetParameters, Get/SetFixedParameters, and UpdateTransformParameters all flatten sub-transforms in reverse queue order (last-added first, .hxx:613,665-687,703,734,847) while GetNthTransform(n) indexes forward — two orderings in one class |
| ⬜ Q54 |
FFTPadImageFilter |
SizeGreatestPrimeFactor == 1 pads each axis to an even size (.hxx:64-68) while the class doc says "1 or less … disable the extra padding" (.h:90) — only 0 disables |
| ⬜ Q55 |
MaskedFFTNormalizedCorrelationImageFilter |
pads FFT sizes using only factors 2/3/5 (.hxx:528-545) while FFTConvolutionImageFilter uses the backend's greatest prime factor (11 under PocketFFT) — identical inputs get different padded sizes across the two FFT-based filters |
| ⬜ Q56 |
RegistrationParameterScalesFromIndexShift |
the step scale is computed in continuous-index (voxel) units while MaximumStepSizeInPhysicalUnits defaults to the minimum virtual spacing (mm) — the gradient-descent learning rate divides mm by voxels, dimensionally mixed on anisotropic spacing (.hxx:66-79; itkGradientDescentOptimizerv4.hxx:272) |
| ⬜ Q57 |
RegistrationParameterScalesEstimator CentralRegionRadius |
consulted only by CentralRegionSampling, which is selected only for displacement-field/B-spline transforms (.hxx:346-367, :203-211); linear/affine transforms take Corner/Random sampling and never read it, and for displacement fields the scales estimate is radius-independent |
| ⬜ Q58 |
ObjectToObjectOptimizerBase weights |
optimizer weights within 1e-4 of 1.0 are flagged identity and never multiplied into the gradient (strict >, so exactly 1e-4 is also discarded, itkObjectToObjectOptimizerBase.cxx:154-164); the sibling scales-identity test uses a 100× looser 0.01 |
| ⬜ Q59 |
v4 optimizer weights application |
every v4 optimizer validates the weights-array length in the base StartOptimization, but the vnl-based LBFGS/LBFGSB and Amoeba optimizers then apply only scales and silently ignore well-sized weights (itkSingleValuedNonLinearVnlOptimizerv4.cxx:53-58); LBFGS2Optimizerv4, by contrast, does apply them |
| ⬜ Q60 |
NiftiImageIO |
ITK_InputFilterName is encapsulated (:1102) and then wiped six lines later by SetImageIOMetadataFromNIfTI, whose first act is thisDic.Clear() (:630) |
| ⬜ Q61 |
NiftiImageIO |
the "original file was non-orthogonal" warning is dead: stored under ITK_sform_corrected (:632), looked up under nifti_sform_corrected (:2038) |
| ⬜ Q62 |
NiftiImageIO |
getQFormCodeFromDictionary/getSFormCodeFromDictionary results are unconditionally overwritten with NIFTI_XFORM_SCANNER_ANAT (:2077-2078) — yet their StringToInt32 still throws on a non-numeric dictionary value that would have been discarded anyway |
| ⬜ Q63 |
NiftiImageIO |
IMG.NII passes CanWriteFile (extension check lowercases) but WriteImageInformation compares the raw uppercase extension against lowercase spellings only and throws "Bad Nifti file name" (:1173-1202) |
| ⬜ Q64 |
niftilib (vendored) |
a magic-less (Analyze-7.5) header in a single .nii reports nifti_type == 1: convert_nhdr2nim sets ANALYZE, then nifti_set_type_from_names forces NIFTI1_1 whenever fname == iname — true for every single-file case (nifti1_io.c:3730, :3453-3454) |
| ⬜ Q65 |
GiplImageIO |
the magic number is validated only in CanReadFile; ReadImageInformation re-reads the same 4 bytes and discards them, so a file supplied via SetImageIO gets no magic check (:566-584) |
| ⬜ Q66 |
GiplImageIO |
NDims is a population count of non-trivial dims — a 2-D image round-trips as 3-D [nx, ny, 1], and malformed dims like [4, 0, 5, 1] give NDims == 2 with the 5 silently dropped (:294-312) |
| ⬜ Q67 |
GiplImageIO |
image_type is byte-swapped only in the BigEndian arm and min/max are never swapped — unobservable, since the constructor pins BigEndian and all these header fields are read then discarded (:78, :325-328, :443-461) |
| ⬜ Q68 |
GiplImageIO |
registers no read/write extensions (constructor omits AddSupported*Extension) and its real gate is a case-sensitive suffix test — IMAGE.GIPL is not recognized (:1079-1090) |
| ⬜ Q69 |
GiplImageIO |
the compressed path uses gzopen/gzread throughout, which transparently pass through a non-gzip stream — a .gipl.gz containing a plain GIPL file is accepted and read verbatim |
| ⬜ Q70 |
VTKImageIO::GetNextLine |
tolerates 5 consecutive empty lines and throws on the 6th, while its message says "consecutive 5 empty lines" — off by one from its own text (:44-46) |
| ⬜ Q71 |
VTKImageIO::GetNextLine |
tests eof() before using the line, so a header whose final line lacks a trailing newline throws "Premature EOF" even though getline delivered the content (:50-56) |
| ⬜ Q72 |
VTKImageIO |
the 2-D/3-D test is written twice and the first copy is dead — the surviving rule is "2-D iff dims[2] <= 1", so DIMENSIONS 4 1 3 is a one-row-tall 3-D volume (:210-221) |
| ⬜ Q73 |
VTKImageIO |
a round-trip collapses ComplexFloat32 to a 2-component VectorFloat32, and a 1-component vector image to a scalar — the legacy format cannot express either distinction (:701-709, :311-329) |
| ⬜ Q74 |
VTKImageIO |
the component count is never range-checked on either side (writer carries a // todo this should be asserted, :705) — COLOR_SCALARS c 7 reads as a 7-component VectorUInt8 |
| ⬜ Q75 |
ImageIOBase ASCII read |
is >> temp with an integer PrintType: a negative literal for an unsigned pixel type wraps rather than failing, and out-of-range 8-bit values narrow silently (−1 → 255, 300 → 44) (itkImageIOBase.cxx:804-811) |
| ⬜ Q76 |
MetaImageIO |
complex pixels cannot round-trip: ElementNumberOfChannels == 2 is indistinguishable from a 2-vector, and the reader forces VECTOR for any channels > 1 (itkMetaImageIO.cxx:241-244, in-source // BUG: 8732) |
| ⬜ Q77 |
MetaIO (vendored) |
MetaImage::CanRead re-tests the suffix case-sensitively against .mha/.mhd while the ITK factory and CanWriteFile match case-insensitively — IMG.MHA is writable but not readable (metaImage.cxx:1184-1199) |
| ⬜ Q78 |
MetaIO (vendored) |
booleans test only value[0] == 'T'|'t'|'1' — trash parses as true, yes as false (metaObject.cxx:1605-1642) |
| ⬜ Q79 |
MetaIO (vendored) |
header-alias precedence is M_Read's apply order, not file order: Origin > Position > Offset, TransformMatrix > Rotation > Orientation, BinaryDataByteOrderMSB > ElementByteOrderMSB — a trailing ElementByteOrderMSB = False loses to an earlier BinaryDataByteOrderMSB = True (metaObject.cxx:1618-1707) |
| ⬜ Q80 |
MetaIO (vendored) |
writes a zlib (RFC-1950) stream but reads zlib or gzip (inflateInit2(…, 47)) — the reader accepts a superset of what the writer produces (metaUtils.cxx:808, :862) |
| ⬜ Q81 |
vendored gzip readers |
NrrdIO's gzio and zlib's gz_look fall back to a byte-for-byte copy when the gzip magic is absent, while niftilib's nifti_is_gzfile is a pure name test — a genuine gzip stream named .nii is never inflated, and a .nii.gz holding raw bytes reads via the copy fallback (gzio.c:501-519; nifti1_io.c:2656-2668) — reviewed, no change (see below) |
| 🔄 Q82 |
NrrdImageIO |
only RAS/LAS/LPS are converted to LPS; every other space value (scanner-xyz, right-up, …) has its geometry used verbatim through an empty default: with no warning (itkNrrdImageIO.cxx:766-786) — fix: branch bug-nrrdio-6575 |
| ⬜ Q83 |
NrrdIO (vendored) |
data file: LIST reads filenames until EOF, so a blank line becomes an empty filename that later fails fopen("") — there is no in-band list terminator (parseNrrd.c:1347-1400) — reviewed, no change (see below) |
| 🔄 Q84 |
NrrdIO (vendored) |
formatNRRD_write emits comments and key/value pairs after the data file: field, defeating the writer's own "data file must be last" ordering — latent header corruption for LIST-form writes with comments (formatNRRD.c:783-857; cf. write.c:724-728) — fix: teem branch bug-nrrd-datafile-last (pushed to sourceforge; regenerates into ITK NrrdIO) + ITK-side bug-nrrdio-6575 |
| ⬜ Q85 |
TxtTransformIO |
Parameters: lines are parsed by vnl read_ascii, which stops at the first unparseable token and reports success — Parameters: 1 2 oops 4 silently yields [1, 2] (itkTxtTransformIO.cxx:183-186) |
| ⬜ Q86 |
TxtTransformIO |
one transform local is reassigned per Transform: line and buffered parameters apply only once both Parameters and FixedParameters have been seen — unpaired lines bind one transform's parameters to a different transform, silently (:168-232) |
| ⬜ Q87 |
TxtTransformIO |
the #Insight Transform File V1.0 header is swallowed by the #-comment skip and never validated; CanReadFile checks only the .txt/.tfm extension (:148, :39-46) |
| ⬜ Q88 |
TxtTransformIO |
an empty FixedParameters vector writes the line FixedParameters: with a trailing space (:238-250, :303-305) |
| ⬜ Q89 |
HDF5TransformIO |
CanWriteFile claims .hdf/.h4/.hdf4/.he4 — HDF4 container names — though Write always creates an HDF5 file, and the lowercase extension table rejects .H5/.HDF5 (itkHDF5TransformIO.cxx:83-84, :424) |
| ⬜ Q90 |
PNGImageIO::ReadImageInformation is a bare return; on a wrong PNG signature (:334-338) where Read throws "File is not png type: …" for the identical png_sig_cmp (:139-143) — a caller reaching it via SetImageIO (bypassing CanReadFile) gets a fabricated success with m_Dimensions unset. A missing file pointer returns silently the same way (:321-324) |
|
| ⬜ Q91 |
PNGImageIO::CanWriteFile passes ignoreCase = false to HasSupportedWriteExtension (:497), unlike the trait's own case-insensitive default; .png and .PNG are both registered (:281-287), so foo.PNG is claimed but foo.PnG is not |
|
| ⬜ Q92 |
m_ExpandRGBPalette's in-class initializer is false (itkImageIOBase.h:853) but ImageIOBase's constructor calls Reset(false), which unconditionally sets it true (itkImageIOBase.cxx:28,45) — PNGImageIO never touches the flag, so the header default is dead and every instance starts with palette expansion on |
|
| ⬜ Q93 |
HDF5TransformIO's ReadParameters/ReadFixedParameters emit "Wrong data type for " << DataSetName << "in HDF5 File" — no space before in, so the dataset name runs into the word (itkHDF5TransformIO.cxx:171, :217) |
|
| ⬜ Q94 |
the rank-1 check in both of those readers raises "Wrong # of dims for TransformType in HDF5 File" (:176, :222) — TransformType is the one dataset the check never covers |
|
| ⬜ Q95 |
HDF5TransformIO::Read loops i < transformGroup.getNumObjs() and then openGroup(GetTransformName(i)) (:297-302); getNumObjs counts every link, so one stray dataset beside the 0, 1, … subgroups makes the loop ask for a group N that was never written and the read dies inside libhdf5 rather than reporting an extra object |
|
| ⬜ Q96 |
HDF5TransformIO::CanReadFile is h5file.exists("/TransformGroup") (:59-66), i.e. H5Lexists — a dataset of that name passes, the factory hands the file over, and Read's openGroup (:295) throws an H5::Exception instead of the factory's clean "could not create Transform IO object" |
|
| ⬜ Q97 |
HDF5ImageIO stores three axis conventions in one group: Dimension/Origin/Spacing in ITK order, fastest-moving first (:1151-1161); only VoxelData's dataspace is reversed (:1170-1182); and Directions writes m_Direction[i] as its row i (:490-510) while that is column i of the direction matrix — so a 4×3 2-D image writes Dimension = [4, 3] and a VoxelData of shape [3, 4], and the Directions dataset is the matrix transpose |
|
| ⬜ Q98 |
HDF5ImageIO's ReadScalar (:410) and ReadVector (:479) both raise "Wrong # of dims for TransformType in HDF5 File" — the transform IO's message (Q94), verbatim, in a file that holds no transform. ReadDirections (:521) at least names the image directions |
|
| ⬜ Q99 |
VoxelType is written on every Write (:1163-1166) and read on no Read: m_ComponentType is derived from imageSet.getDataType() (:752-753). A file whose VoxelType reads FLOAT over int16 voxels loads as Int16; a file with no VoxelType at all loads fine. The class comment (itkHDF5ImageIO.h:68-71) says it exists to make the file "user friendly with respect to HDF5 viewers", so this is by design — worth stating, since it looks authoritative |
|
| ⬜ Q100 |
HDF5ImageIO::CanReadFile is h5file.exists("/ITKImage") (:647-654) — same H5Lexists shape as Q96, so a dataset named /ITKImage is claimed and ReadImageInformation's first openDataSet throws |
|
| ⬜ Q101 |
three of ReadImageInformation's meta-data branches are unreachable: WriteScalar(unsigned long) stores NATIVE_UINT tagged isUnsignedLong (:322-342), so no ITK-written dataset is ever NATIVE_INT + isUnsignedLong as :801-805 expects; and on every LP64 platform H5Tequal(NATIVE_LONG, NATIVE_LLONG) and H5Tequal(NATIVE_ULONG, NATIVE_ULLONG) are true, so the arms at :874-897 swallow every 64-bit integer and those at :898-905 never run (the isLLong/isULLong tags inside the surviving arms are what actually distinguish the two) |
|
| ⬜ Q102 |
a meta-data dataset of rank > 1 is skipped by continue (:785-789), and the if/else if chain over the fourteen NATIVE_* types ends in an else that tests only metaDataType == strType with no else of its own (:914-922) — so a compound, enum, array or variable-length-sequence dataset leaves no dictionary entry and raises nothing. A subgroup under MetaData, by contrast, is fatal: the loop opens every link with openDataSet (:776-782) |
|
| ⬜ Q103 |
HDF5ImageIO's constructor registers .hdf, .h4, .hdf4, .he4 — HDF4 container names — for both reading and writing alongside the HDF5 ones (:36-43), the same eight-name list already noted on the transform side (Q89). Here CanWriteFile is HasSupportedWriteExtension(name) with ignoreCase = true (itkImageIOBase.h:788), so IMAGE.H5 is claimed for writing where the transform IO's case-sensitive CanWriteFile declines it |
|
| ⬜ Q104 |
JPEGImageIO::Write throws "JPEG Writer can only write 2-dimensional images" before opening anything (:459-462), where PNGImageIO::WriteSlice silently writes only the first slice (B71) — the two sibling IOs disagree on whether a 3-D source is an error |
|
| ⬜ Q105 |
JPEGImageIO::CanReadFile is markedly stricter than PNG's: case-sensitive extension (:102, ignoreCase = false), then the 0xFFD8 magic (:117-130), then a full jpeg_read_header parse (:152) — where PNGImageIO::CanReadFile stops at the 8-byte signature |
|
| ⬜ Q106 |
JPEGImageIO::CanWriteFile passes ignoreCase = false (:449) against four registered spellings (:308-314) — .jpg, .JPG, .jpeg, .JPEG are claimed, .Jpg is not. Same shape as PNG's (Q91) |
|
| ⬜ Q107 |
m_UseCompression is assigned false in the constructor (:299) and never read: jpeg_set_quality is called unconditionally (:537), so only Quality/CompressionLevel has any effect and UseCompressionOn() is silently inert for this IO |
|
| ⬜ Q108 |
Two quirks of the TIFF resolution tags. (a) Spacing survives a round-trip only to float precision: WriteImageInformation stores 25.4 / m_Spacing[i] (:587, :794) into XRESOLUTION, which libtiff holds as a float (tif_dir.h:98; TIFF_RATIONAL/TIFF_SETGET_FLOAT, tif_dirinfo.c:90) and m_XResolution mirrors as float — so a spacing of 1.0 reads back as 1.0000000150…. (b) TIFFReaderInternal::Initialize reads XRESOLUTION with the non-defaulted TIFFGetField (:202) over Clean()'s seed of 1, while the read guard is only unit > 0 && m_XResolution > 0 (:375-385) — so a page with RESOLUTIONUNIT = 2 (inch) and no XRESOLUTION tag yields a spacing of 25.4 rather than the default 1.0. (An absent RESOLUTIONUNIT seeds unit = 1, which takes neither branch, so the plain case is safe.) |
|
| ⬜ Q109 |
FastChamferDistanceImageFilter |
the anti-raster sweep is for (it.GoToEnd(), --it; !it.IsAtBegin(); --it) (.hxx:194), so flat index 0 is never the center of the backward pass — harmless, because the pass writes to lower-index neighbours and flat index 1 still updates it. The 3-D weights are the float literals 0.92644, 1.34065, 1.65849 (.hxx:38, :41, :44) |
| ⬜ Q110 |
IsolatedConnectedImageFilter |
the bisection bounds and midpoint are typed NumericTraits<InputPixelType>::AccumulateType (.hxx:147, :178-180, :243-245), which for unsigned int is unsigned int — no widening (itkNumericTraits.h:1027). guess = (upper + lower) / 2 (.hxx:231, :296) can therefore overflow for thresholds near UINT_MAX |
| ⬜ Q111 |
STAPLEImageFilter |
contrary to the common description of the algorithm, there is no p = q = 0.99999 seeding: W is seeded from the rater mean (.hxx:116), the prior g_t is computed once before the loop (:123), per-rater convergence is (dp)² , (dq)² ≤ 1e-14 (:51, :215-220), and the foreground test is a two-sided ε-window with ε = 1e-10 (:94). Worth stating because implementations that copy the papers' seeding will not reproduce ITK |
| ⬜ Q112 |
BinaryMedianImageFilter |
the majority rule is strict > against neighborhoodSize / 2 (.hxx:121, :136-143), so a tie goes to background; and the output is always exactly ForegroundValue or BackgroundValue — a pixel whose value matches neither is not passed through |
| ⬜ Q113 |
ChangeLabelImageFilter |
the change map is std::map<InputPixelType, OutputPixelType> (.h:57), so keys are quantized through the pixel type and a repeated key is last-wins (.h:77); operator() performs a single lookup (.h:92-101), so a→b together with b→c is not transitive — a maps to b |
| ⬜ Q114 |
BSplineDecompositionImageFilter |
the causal-coefficient initialization switches between an accelerated truncated sum and the exact mirror-boundary sum on horizon < dataLength, where `horizon = ceil(log(tol)/log( |
| ⬜ Q115 |
PatchBasedDenoisingImageFilter noise-model fidelity |
on the first iteration the output equals the input, so GAUSSIAN's 2·(in − out) (.hxx:2015) and POISSON's (in − out)/(out + 1e-5) (:2049) are both identically zero. With SimpleITK's default NumberOfIterations = 1, neither noise model contributes anything; RICIAN's Bessel-ratio term (:2031-2032) is nonzero and is unaffected |
| ⬜ Q116 |
PatchBasedDenoisingImageFilter internals |
three of a kind: ResolveSigmaUpdate writes m_KernelBandwidthSigma (.hxx:1854, :1860) before returning, and the caller then compares |sigmaUpdate| against the already-updated sigma (:1427); m_MinProbability = 2.2e-306 (:43) is added to the entropy probability and to its first and second derivatives (:1734-1738); and on the skipped-query path the subsampler's offset keeps its zero initialization rather than being recomputed by ComputeOffset (itkSpatialNeighborSubsampler.hxx:140, :147-151) |
| ⬜ Q117 |
JoinSeriesImageFilter size mismatch |
asymmetric and undocumented. Each input's requested region is derived from the primary input's size (.hxx:209-216), so a subsequent input that is smaller throws InvalidRequestedRegionError from region propagation, while one that is larger is silently corner-cropped to [0, primary_size). (Physical congruency is checked separately, with coordinateTol = m_CoordinateTolerance · spacing[0] — the first dimension's spacing for every axis, itkImageToImageFilter.hxx:184-185) |
| ⬜ Q118 |
TransformToDisplacementFieldFilter linear fast path |
the scan-line endpoints are the continuous indices idx[0] and idx[0] + size[0] — one past the last pixel — with alpha = i / size[0] (.hxx:239, :245, :255-256). This is exact rather than off-by-one, because for a linear transform T(p) − p is affine, so interpolating between those two endpoints reproduces the displacement at every interior pixel. Recorded because it reads like an off-by-one and is not |
Following up on #6569: while porting SimpleITK's filter surface to another language, I kept a ledger of everything in the ITK sources that looked wrong or surprising. It has grown to 83 suspected bugs and 118 quirks (originally 30 and 24; follow-up batches B31–B83 and Q25–Q118 are merged into the tables below) — too many to file individually without flooding the tracker, so I am reporting them together here for triage. Happy to split any subset into standalone issues if that is more useful; I am not planning PRs for all of these, so please treat this as raw material.
PR status (maintainer triage — updated 2026-07-11 by @hjmjohnson)
bug-displacement-field-batch2-6575bug-fastmarching-alltargets-6575bug-nrrdio-6575+ 4 teem branches on sourceforgeAll six draft PRs carry a single commit authored by @physwkim; each regression test was verified locally to fail on the pre-fix code and pass on the fix. Remaining items B1–B9, B11–B17, B20–B24, B26–B30 and the 24 quirks are unclaimed.
How these were found, and what was checked before filing
Each filter was reimplemented from the
.hxxsources and the two implementations compared on synthetic inputs; every divergence was traced back to the ITK code path that caused it. Before filing, every item was re-checked againstmainate46eb723a5: the cited lines re-read in context, declared types and constructor defaults verified, and each claimed consequence re-derived from the quoted code. Items whose original analysis did not survive that re-check were corrected or dropped — some of my own earlier conclusions turned out to be wrong, so I would not be surprised if a few of the remaining ones are too. Corrections welcome.One item is flagged inline as source-analysis only (B28: non-termination identified from the loop structure, not run to a live hang).
Suspected bugs — wrong results, NaN, or UB in live code paths
Row status: ✅ completed (merged) · 🔄 in progress (open PR or prepared branch) · ⬜ not started.
Per-item detail blocks live in the collapsed comments below: B1–B30 in a dedicated comment, B31–B83 and Q25–Q118 in the follow-up batch comments.
ProjectionImageFilterunsigned; axis 0 wraps to a ~2³¹·spacing shiftN4BiasFieldCorrectionImageFilter::SharpenImage0.0/0.0 = NaN→ NaN→int cast (UB) → unchecked histogram index — fix: #6589SLICImageFilter0/0NaN centroid → NaN→integer index cast (UB) — fix: #6589WienerDeconvolutionImageFilterPf == Pn→ complex division by zero → NaN output (guard passes on inf) — fix: #6589CannySegmentationLevelSetFunctionGridImageSourceMinMaxCurvatureFlowFunction(3-D)acostaken on a gradient rescaled to length r, not 1 — wrong polar angle for radius ≥ 2MinMaxCurvatureFlowFunctionAdaptiveHistogramEqualizationiscale == 0→ NaN everywhere — fix: #6589MultiLabelSTAPLEImageFilterSTAPLEImageFilterp_denom == 0→ NaN, unguarded — fix: #6589LabelOverlapMeasuresImageFilterfalse_positive_errorguard tests the wrong quantity — NaN reachable — fix: #6589ThresholdMaximumConnectedComponentsImageFilter(upper−lower)/2; unsigned wrap when it lands belowlowerScalarImageKmeansImageFilterUseNonContiguousLabelsinterval underflows to0xFFFFFFFFfor > 255 classesLabelVotingImageFiltermax_label+1wraps to 0 for a UInt8 image using all 256 labelsMaskedFFTNormalizedCorrelationImageFilterIterativeDeconvolutionImageFilterPadInput/CropOutputread them —OutputRegionModesilently ignoredFastApproximateRankImageFilter::SetRankAttributeMorphologyBaseImageFilterstable_sortend iterator off by one — last raster pixel never sorted — fix: #6581 (merged)BoxSigmaImageFilter0.0/0.0→ NaN for every pixel — fix: #6589LevelSetNeighborhoodExtractorStructureTensorImageFilter(AnisotropicDiffusionLBR)K_ρapplied along axis 0 only (single-direction filter,SetDirectionnever called)CoherenceEnhancingDiffusionImageFilterFastMarchingUpwindGradientImageFilterAllTargetstermination unreachable — fix: branchbug-fastmarching-alltargets-6575Transform::ApplyToImageMetadataGetInverseTransform()(singular or non-linear transform) dereferenced without a check — fix: #6583 (merged)PatchBasedDenoisingImageFilter(POISSON)static_cast<PixelValueType>(0.99999)is 0 for integer types — step size collapses to 1e-5 alwaysPatchBasedDenoisingImageFilterUniformRandomSpatialNeighborSubsamplerSearchloops forever when the search box is exactly the query point (kernel-bandwidth path)GaussianRandomSpatialNeighborSubsamplerunsigned int— UB; rejection loop relies on the wrap — fix: #6589RegionBasedLevelSetFunctionCurvatureWeight == 0IterativeInverseDisplacementFieldImageFiltersmallestErrorcarries over from the previous pixel when the mapped point starts outside the buffer — output depends on raster order — fix: #6576 (merged)InverseDisplacementFieldImageFilterVectorConfidenceConnectedImageFilterWarpImageFilterExponentialDisplacementFieldImageFilter1 << numiter— UB whennumiter >= 31; unreachable by default (cap 20, clamped), but an explicitSetMaximumNumberOfIterations(>= 31)makes it liveFastMarchingImageFilterBase::UpdateNeighborsFastMarchingImageFilterBase(NoHandles)NoHandlesdegenerates toStrictFastMarchingImageFilterBase::SolveScalarToRGBColormapImageFilter/ColormapFunctionNumericTraits<float/double>::min()(smallest positive) used as a "most negative" seed in two places — wrong rescale for non-positive float images, and a ≈FLT_MAXdefault input rangeMergeLabelMapFilter(KEEP)LabelObjectends up aliased under two label keys — fix: #6590LabelMapContourOverlayImageFilter(SLICE_CONTOUR)m_SliceDimensionwhere it means the read index —SliceDimension == 0draws no contour at all — fix: #6590LabelMapMaskImageFilter(Crop)AttributeUniqueLabelMapFilterwhile (it.IsAtEnd())— inverted, never executes — fix: #6590LabelMap::PushLabelObjectSetLabel, and silently overwrites the entry at the object's own label instead of throwing "map is full" — fix: #6590StatisticsLabelMapFilterratio > 0check — an indefinite weighted covariance yields NaN whereShapeLabelMapFilteryields 0 — fix: #6590NormalizedCorrelationImageFilterTransformIOBaseTemplate::CorrectTransformPrecisionTypefind("float")result used unchecked — a transform-type string naming neither precision throwsstd::out_of_rangepast every ITK handlerNiftiImageIO::Readscl_slope/scl_interNiftiImageIO::ReadRescaleFunctionis given the voxel count — only the firstnumEltsof a multi-component/complex buffer are rescaledNiftiImageIO::ReadNiftiImageIOdim[1]— a 2-D vector image one row tall reads back as 1-Dnifti_read_buffer(vendored)isfiniteis a macro (glibc: always) — NaN/±Inf pixels silently destroyedGiplImageIO::WriteGiplImageIO::Read!bad(); a short pixel block setsfailbit/eofbit, neverbadbit— truncated file reads as success over an uninitialized tailGiplImageIO::Read(compressed)p != nullptron the caller's always-non-null output buffer —gzread's byte count is never inspectedGiplImageIO::Writeimage_typeis derived from the component type alone while the byte count multiplies by components — a vector image writes a scalar header plus N× the bytes, reading back as garbageVTKImageIO::ReadReadBufferAsBinary'sbool(false on short read) is discarded — truncated BINARY file reads as successVTKImageIO::InternalReadImageInformationsscanfreturn is discarded over uninitialized locals — an under-filledDIMENSIONS/SPACING/ORIGINline sizes the image from indeterminate values (UB)VTKImageIO::InternalReadImageInformationSCALARS vector_field floatmatches thevectorarm and is misparsed as a 3-component VECTORS lineVTKImageIOASCII writeprecision(16)is set on a throwaway header stream; pixel data is emitted through a second stream at the default 6 significant digits — silent precision lossImageIOBase::ReadBuffer(ASCII)5 99999 7 8asshortreads[5, 32767, 32767, 32767])VTKImageIO::CanReadFileGetNextLinecalls outside the try block — a.vtkshorter than four lines throws "Premature EOF" through the factory instead of returning falseNrrdImageIO::Writemetadata dispatchNRRD_-prefixed keys are matched bystrncmpof the candidate's length —NRRD_space directionsis swallowed by thespacehandler, and unmatchedNRRD_keys (including the reader's ownNRRD_pixel_original_axis) are silently dropped — fix: branchbug-nrrdio-6575ElementDataFile = LIST(vendored)m_DimSize[-1]/m_SubQuantity[-1]OOB reads;== NDims→ zero-length slice reads, still successM_ReadElements(vendored)LOCALcompressed header withoutCompressedDataSizeseeks to file start and inflates its own header text over the uninitialized pixel buffer — success, garbage pixelsMET_PerformUncompression(vendored)return true— truncated/corrupt/wrong-container streams and short output all report successsizes/spacings/thicknesses/axis mins/axis maxsparsedim + 1values into aNRRD_DIM_MAX(16)-element stack array — a 16-D header with a 17th token is a stack buffer overflow — fix: teem branchbug-nrrd-parse-axis-overflow(pushed to sourceforge; regenerates into ITK NrrdIO) + ITK-sidebug-nrrdio-6575nrrdOriginCalculate(vendored)gotMinloop testsaxis[0]->minfor every axis (literal 0, not the loop variable) — origins computed from NaN mins, or usable mins ignored — fix: teem branchbug-nrrd-origin-calculate(pushed to sourceforge; regenerates into ITK NrrdIO) + ITK-sidebug-nrrdio-6575rnParse_kinds(vendored)nonetoken arm assigns the axis's centering, not its kind —kinds: none …clobbers a previously parsedcenters:value — fix: teem branchbug-nrrd-kinds-none-centering(pushed to sourceforge; regenerates into ITK NrrdIO) + ITK-sidebug-nrrdio-6575PNGImageIO::WriteSlice"wb"— truncating it — before the component-type switch whosedefault:throws; writing anint16image destroys any existing.pngand leaves it zero-bytePNGImageIO::WriteSliceheightcomes fromGetDimensions(1)alone, no axis beyond it is consulted — a 3-D image writes only its first slice, with no errorPNGImageIO::WriteSlicePNG_COLOR_TYPE_RGB_ALPHA) while row pointers advance by the actual count — each row's trailing components are silently droppedHDF5ImageIO::WriteImageInformationconstCstringObj->GetMetaDataObjectValue()under a guard that admitsconstCstringObj == nullptr— null dereference for aMetaDataObject<char *>HDF5ImageIO::ReadImageInformationspacing[i]/Dims[i]are indexed tonumDimsregardless of the file's actual dataset length, reading past the end of a heap vector before any pixel is touchedHDF5ImageIO::ReadH5Dread's memory type, making the conversion the identity — aVoxelDatastoredSTD_I16BEis copied without a byte swap and read back byte-swapped, silentlyJPEGImageIO::WriteSlicedensity_unit = 0("aspect ratio only") while storing real dots-per-cm values — the reader's owndensity_unit > 0guard then discards them, so the spacing is lost on a round-trip through ITKJPEGImageIO::ReadTIFFImageIO::ReadVolumem_SubFiles— one ignored or untagged page before aSUBFILETYPE == 0page and the last slice is written past the end of the bufferTIFFImageIO::ReadGenericImagewidth/SamplesPerPixel/BitsPerSamplestay pinned to directory 0 — a multi-page file whose later pages are narrower over-reads the bufferTIFFImageIO::ReadImageInformationdefault:, andCanReadnever constrainsSampleFormat— a 32-bitSAMPLEFORMAT_VOIDpage is read as whateverm_ComponentTypealready heldTIFFImageIO::ReadGenericImagePHOTOMETRIC_MINISWHITEis read out un-inverted — the// check invertedcomment above the plain-copy grayscale arm never grew a bodyTIFFImageIO::GetFormatMINISBLACK/MINISWHITEmap toGRAYSCALEregardless ofSamplesPerPixel, so a 2-sample grey+alpha page is declared 1-component and each row keeps only its first halfTIFFImageIO::InternalWritePHOTOMETRIC_RGBis written for every component count other than 1 — a 2-component image becomes an RGB-tagged file withSamplesPerPixel = 2and noEXTRASAMPLESReproduced quirks and inconsistencies
These were verified the same way but may be judged intended, historical, or not worth changing — listed for the record, one line each, citations available on request (I have exact file:line and analysis for every row).
Verified quirks Q1–Q118 (table)
KernelZeroMagnitudeThresholdε is compared against |H| by Inverse but against the |H|²-carrying denominator by Tikhonov/Wiener — "regularization → 0 equals inverse" fails in the band ε ≤ |H| < √ε.DiscreteGaussianDerivativeImageFilterFlipAxes(), unlikeDerivativeImageFilter/GradientImageFilter(which do) — odd-order derivatives carry the opposite sign vs. its siblings. Also the inter-axis intermediate isImage<OutputPixelType>, so integer outputs truncate per axis pass (the local comments say "real to real").ThresholdSegmentationLevelSetImageFilter.h:63-65) states positive = inside — the opposite of the convention its own base class documents (itkSegmentationLevelSetImageFilter.h:82-84: negative inside).CurvatureSpeedis overridden toPropagationSpeedonly by GeodesicActiveContour and ShapeDetection; Threshold/Laplacian/Canny keep the base-class constant 1 — an undocumented asymmetry across siblings.BinaryContourImageFilter.hxx:164-179) — they are not normalized toBackgroundValue, so several distinct non-foreground input values all survive into the output.SimpleContourExtractorImageFilterInputForegroundValue == InputBackgroundValuemarks every foreground pixel as contour (the neighborhood scan includes the center pixel,.hxx:84).BinaryReconstructionByErosionImageFilterBinaryNot;BackgroundValueis consumed only as a self-consistent internal sentinel — the parameter has no effect on the output.AnisotropicDiffusionImageFilter.hxx:68).ThresholdMaximumConnectedComponentsImageFilterm_LowerBoundaryis written once in the constructor and read only byPrintSelf— dead configuration with no setter.MinMaxCurvatureFlowFunctionSetStencilRadiusclamps to ≥ 1 (.hxx:43), making theradius == 0early-outs (.hxx:217-220,276-279) unreachable dead code.ScalarImageKmeansImageFilterGenerateData(SetMaximumIteration(200), threshold 0.0,.hxx:91-92), invisibly to users; andKdTreeBasedKmeansEstimator's loop tests the limit pre-increment after the refinement pass (.hxx:327-347) —MaximumIteration = nruns n+1 passes whileGetCurrentIteration()reports n.SLICImageFilter.hxx:544-546); there is no final relabel/compaction pass; per-pixel distances accumulate infloat.BoxMean/BoxSigmaImageFilteritkBoxUtilities.h:322-324,499-501) — border statistics use fewer samples. AZeroFluxNeumannBoundaryConditionis declared (L215/389) but never used, suggesting replication was once intended.BinShrinkImageFilterShrinkImageFiltersilently clamps to 1 (.hxx:289-296vsitkShrinkImageFilter.hxx:265-267); integer outputs round half-up while float outputs truncate (RoundIfInteger,.h:135-149).AntiAliasBinaryImageFiltermax − (max−min)/2iso-value and the strict> 0sign test (.hxx:109; base.hxx:605) — the output is uniformly negative, i.e. "all inside".ReinitializeLevelSetImageFilter±NumericTraits<PixelType>::max()and only overwrites band points (.hxx:206-225) — far-field pixels keep ±max rather than a distance-like magnitude.FastMarchingUpwindGradientImageFilterm_TargetValueis overwritten at every accepted point in NoTargets mode; in Some/AllTargets modes the reached test is sticky, so every later accepted point — target or not — keeps advancing it; OneTarget reports the last reached target, not the first (.hxx:154-227).CollidingFrontsImageFilterApplyConnectivity's flood fill is seeded onSeedPoints1alone (.hxx:114-122), so the forced −1e-6 at everySeedPoints2seed (.hxx:92-97) is dropped from the output unless that seed is face-connected to front 1's region.itk::watershed::Segmenteroperator<(itkWatershedSegmentTable.h:73-82); a NaN height compares "equivalent" to everything — a strict-weak-ordering violation (formal UB; benign merge-equal in libstdc++).itkMath.h FloatAlmostEqual0.1 · epsilon) returns equal before the signbit check (itkMath.h:334-352) —0.0 == -0.0, and near-zero pairs millions of ULPs apart compare equal, partially defeating the documented ULP semantics.MultiphaseDenseFiniteDifferenceImageFiltertimeStep = 0.08; // FIXME !!! After all this work, assign a constant !!! Why ??(.hxx:153-154).UseImageSpacingm_ScaleCoefficientsthat nothing in the Chan-Vese chain reads; the PDE divides bym_InvSpacingfrom the feature image unconditionally while the re-distancing Maurer map inherits the level-set image's spacing — the flag's only live effect ismaurer->SetUseImageSpacing(.hxx:227). Two images with different spacings drive the PDE and the re-distancing with different metrics.ScalarChanAndVeseDenseLevelSetRMS/labelingm_ReinitializeCounterdefaults to 1, so the reinit branch runs every iteration, zeroes the RMS accumulator, and refills it with the re-distancing residual (.hxx:214-248) —MaximumRMSErrorhalting compares against the wrong quantity.CopyInputToOutputlabelsphi < 0strictly (.hxx:69), so exactly-zero boundary pixels are excluded from the label.ObjectMorphologyImageFilterBeforeThreadedGenerateData's fill-then-conditional-copy always reduces tooutput := input(the fill sentinel is constructed to differ fromObjectValue,.hxx:87-113);UseBoundaryConditionis dead configuration (installed but never enabled,.h:145even warns "Don't forget to set UseBoundaryCondition to true!"); boundary detection is a hard-coded 3^dim box decoupled from the kernel radius (.hxx:130-198) — dilation is unaffected, erosion diverges substantially from true erosion (the header caveats this).IterativeInverseDisplacementFieldImageFilterDisplacementFieldJacobianDeterminantFilterSetDerivativeWeightssilently flipsUseImageSpacingoff — precedence between the two is last-writer-wins, while the class doc describes only one orderingWarpImageFilterm_OutputSize[0] == 0alone keys "size unset"; output-grid defaults are unit/zero/identity from neither input; the field is sampled with edge replication, never out-of-domainVectorConnectedComponentImageFilterInputValyeTypeIsFloatingCheckMahalanobisDistanceMembershipFunctiondet < 0exception branch is unreachable;GetCovariance()never reflects the singular-case substituteFastSymmetricForcesDemonsRegistrationFilterESMDemonsRegistrationFunction; the identically-namedFastSymmetricForcesDemonsRegistrationFunctionclass is orphaned from its own filterExponentialDisplacementFieldImageFilter+ 1.0-then-truncate code (integral values overshoot by 1); a zero field still runs one squaring iterationWarpVectorImageFilter(as wired byDiffeomorphicDemonsRegistrationFilter)IsInsideBufferis always true andm_EdgePaddingValueis dead codeESMDemonsRegistrationFunctionWarpedMovingandMappedMovinggradient options coincide exactly at a zero displacement field (interior pixels, default linear interpolation, coincident grids)LevelSetMotionRegistrationFilter/Functiondt = 1/maxL1makes the applied step at the governing pixel exactlyAlpha-independent; thresholded pixels count toward the metric while out-of-buffer pixels don't;Haltadds an RMS==0 clause the base can never fireLevelSetMotionRegistrationFunctionGetRMSChange() == 0butGetMetric() == NumericTraits<double>::max()in the two filters that don't overrideGetRMSChangeLevelSetMotionRegistrationFunctionsmoothingu8in →u8smoothed) before the gradient; and any axis shorter than 4 pixels is a hard error for this family member onlyFastMarchingImageFilterBase::IsChangeWellComposed3DGetRequestedRegion()(empty, never set) where the 2-D sibling and the strict-topology check useGetBufferedRegion()— harmless (onlySetLocation+GetPixelare used) but inconsistent (.hxx:779vs:583/:619)LabelToRGBImageFilterm_BackgroundColorzero-filled at construction); the functor comment promising a "gray pixel matching the background intensity" describesLabelOverlayFunctor, not this class (itkLabelToRGBFunctor.h:93-98)LabelToRGB/LabelOverlaypaletteNumericTraits<output RGB component>::max()rather than a fixed 255 (itkLabelToRGBFunctor.h:110-117) — adoubleRGB output scales the palette into[0, ≈1.8e308]HessianToObjectnessMeasureImageFilterstd::sort(equal-magnitude order unspecified,.hxx:78-79);alpha == 0skips only the R_A factor whilebeta == 0(or a zero denominator) zeroes the whole measure (.hxx:111-151) — asymmetric parameter semanticsComplexToModulusImageFiltersqrt(re*re + im*im)in the component type (.h:46-50):ComplexFloat32overflows to inf above |component| ≈ 1.8e19 and flushes to 0 near denormals, wherestd::hypotwould notRelabelLabelMapFilterPushLabelObject; the inherited implementation usesSetLabel+AddLabelObjectagainst a counter from 0 (itkAttributeRelabelLabelMapFilter.hxx:64-79)LabelMap::HasLabelfind(label) != end(), which returns false for background (.hxx:151-153)StatisticsLabelMapFilterweighted momentsspacing²/12(the pixel's own second moment) to every central-moment diagonal (.hxx:224-228) whileShapeLabelMapFilterdoes not —WeightedPrincipalMomentsexceedPrincipalMomentsby 1/12 per eigenvalue even on a constant feature imageStatisticsLabelMapFilterextremum indicesv <= min,v >= max,.hxx:118-127) — on ties the recorded index is the last tie in raster orderitk::Statistics::Histogram::Initializefloat(itkHistogram.hxx:225-236) — aHistogram<double>gets float-quantized bin edges, whichStatisticsLabelMapFilter'sMedianinheritsImageBase::IsCongruentImageGeometrythis->GetSpacing()[0]only (itkImageBase.hxx:400-405) — the predicate is asymmetric when the two images differ in axis-0 spacing, and axes 1+ are judged against axis 0's scaleDivideImageFilter::DivNumericTraits<TOutput>::max()regardless of the numerator's sign or magnitude (itkArithmeticOpsFunctors.h:142-151); throughNormalizeToConstantImageFiltera zero-sum input sends the entire output to the type maximumVotingBinaryHoleFillingImageFilterit.Set(foregroundValue)for any center value other thanbackgroundValue(.hxx:138-141) — a third pixel value is silently promoted to foreground without counting towardGetNumberOfPixelsChanged(); the iterative sibling inherits thisExtractImageFilter.hxx:74-85,:162-179)CenteredVersorTransformInitializer::ComputeRotationR = M·Fᵀ(.hxx:47), which does not satisfy the covariance-aligning identityR·Cov_f·Rᵀ = Cov_m(that requiresMᵀ·F); with per-image independent eigenvector sign canonicalization the initializer can 180°-flip an axisCompositeTransformGet/SetParameters,Get/SetFixedParameters, andUpdateTransformParametersall flatten sub-transforms in reverse queue order (last-added first,.hxx:613,665-687,703,734,847) whileGetNthTransform(n)indexes forward — two orderings in one classFFTPadImageFilterSizeGreatestPrimeFactor == 1pads each axis to an even size (.hxx:64-68) while the class doc says "1 or less … disable the extra padding" (.h:90) — only 0 disablesMaskedFFTNormalizedCorrelationImageFilter.hxx:528-545) whileFFTConvolutionImageFilteruses the backend's greatest prime factor (11 under PocketFFT) — identical inputs get different padded sizes across the two FFT-based filtersRegistrationParameterScalesFromIndexShiftMaximumStepSizeInPhysicalUnitsdefaults to the minimum virtual spacing (mm) — the gradient-descent learning rate divides mm by voxels, dimensionally mixed on anisotropic spacing (.hxx:66-79;itkGradientDescentOptimizerv4.hxx:272)RegistrationParameterScalesEstimatorCentralRegionRadiusCentralRegionSampling, which is selected only for displacement-field/B-spline transforms (.hxx:346-367,:203-211); linear/affine transforms take Corner/Random sampling and never read it, and for displacement fields the scales estimate is radius-independentObjectToObjectOptimizerBaseweights1e-4of 1.0 are flagged identity and never multiplied into the gradient (strict>, so exactly1e-4is also discarded,itkObjectToObjectOptimizerBase.cxx:154-164); the sibling scales-identity test uses a 100× looser0.01StartOptimization, but the vnl-based LBFGS/LBFGSB and Amoeba optimizers then apply only scales and silently ignore well-sized weights (itkSingleValuedNonLinearVnlOptimizerv4.cxx:53-58);LBFGS2Optimizerv4, by contrast, does apply themNiftiImageIOITK_InputFilterNameis encapsulated (:1102) and then wiped six lines later bySetImageIOMetadataFromNIfTI, whose first act isthisDic.Clear()(:630)NiftiImageIOITK_sform_corrected(:632), looked up undernifti_sform_corrected(:2038)NiftiImageIOgetQFormCodeFromDictionary/getSFormCodeFromDictionaryresults are unconditionally overwritten withNIFTI_XFORM_SCANNER_ANAT(:2077-2078) — yet theirStringToInt32still throws on a non-numeric dictionary value that would have been discarded anywayNiftiImageIOIMG.NIIpassesCanWriteFile(extension check lowercases) butWriteImageInformationcompares the raw uppercase extension against lowercase spellings only and throws "Bad Nifti file name" (:1173-1202).niireportsnifti_type == 1:convert_nhdr2nimsets ANALYZE, thennifti_set_type_from_namesforces NIFTI1_1 wheneverfname == iname— true for every single-file case (nifti1_io.c:3730,:3453-3454)GiplImageIOCanReadFile;ReadImageInformationre-reads the same 4 bytes and discards them, so a file supplied viaSetImageIOgets no magic check (:566-584)GiplImageIONDimsis a population count of non-trivial dims — a 2-D image round-trips as 3-D[nx, ny, 1], and malformed dims like[4, 0, 5, 1]giveNDims == 2with the 5 silently dropped (:294-312)GiplImageIOimage_typeis byte-swapped only in the BigEndian arm andmin/maxare never swapped — unobservable, since the constructor pins BigEndian and all these header fields are read then discarded (:78,:325-328,:443-461)GiplImageIOAddSupported*Extension) and its real gate is a case-sensitive suffix test —IMAGE.GIPLis not recognized (:1079-1090)GiplImageIOgzopen/gzreadthroughout, which transparently pass through a non-gzip stream — a.gipl.gzcontaining a plain GIPL file is accepted and read verbatimVTKImageIO::GetNextLine:44-46)VTKImageIO::GetNextLineeof()before using the line, so a header whose final line lacks a trailing newline throws "Premature EOF" even thoughgetlinedelivered the content (:50-56)VTKImageIOdims[2] <= 1", soDIMENSIONS 4 1 3is a one-row-tall 3-D volume (:210-221)VTKImageIOComplexFloat32to a 2-componentVectorFloat32, and a 1-component vector image to a scalar — the legacy format cannot express either distinction (:701-709,:311-329)VTKImageIO// todo this should be asserted,:705) —COLOR_SCALARS c 7reads as a 7-componentVectorUInt8ImageIOBaseASCII readis >> tempwith an integerPrintType: a negative literal for an unsigned pixel type wraps rather than failing, and out-of-range 8-bit values narrow silently (−1 → 255, 300 → 44) (itkImageIOBase.cxx:804-811)MetaImageIOElementNumberOfChannels == 2is indistinguishable from a 2-vector, and the reader forcesVECTORfor any channels > 1 (itkMetaImageIO.cxx:241-244, in-source// BUG: 8732)MetaImage::CanReadre-tests the suffix case-sensitively against.mha/.mhdwhile the ITK factory andCanWriteFilematch case-insensitively —IMG.MHAis writable but not readable (metaImage.cxx:1184-1199)value[0] == 'T'|'t'|'1'—trashparses as true,yesas false (metaObject.cxx:1605-1642)M_Read's apply order, not file order:Origin>Position>Offset,TransformMatrix>Rotation>Orientation,BinaryDataByteOrderMSB>ElementByteOrderMSB— a trailingElementByteOrderMSB = Falseloses to an earlierBinaryDataByteOrderMSB = True(metaObject.cxx:1618-1707)inflateInit2(…, 47)) — the reader accepts a superset of what the writer produces (metaUtils.cxx:808,:862)gz_lookfall back to a byte-for-byte copy when the gzip magic is absent, while niftilib'snifti_is_gzfileis a pure name test — a genuine gzip stream named.niiis never inflated, and a.nii.gzholding raw bytes reads via the copy fallback (gzio.c:501-519;nifti1_io.c:2656-2668) — reviewed, no change (see below)NrrdImageIORAS/LAS/LPSare converted to LPS; every otherspacevalue (scanner-xyz, right-up, …) has its geometry used verbatim through an emptydefault:with no warning (itkNrrdImageIO.cxx:766-786) — fix: branchbug-nrrdio-6575data file: LISTreads filenames until EOF, so a blank line becomes an empty filename that later failsfopen("")— there is no in-band list terminator (parseNrrd.c:1347-1400) — reviewed, no change (see below)formatNRRD_writeemits comments and key/value pairs after thedata file:field, defeating the writer's own "data file must be last" ordering — latent header corruption forLIST-form writes with comments (formatNRRD.c:783-857; cf.write.c:724-728) — fix: teem branchbug-nrrd-datafile-last(pushed to sourceforge; regenerates into ITK NrrdIO) + ITK-sidebug-nrrdio-6575TxtTransformIOParameters:lines are parsed by vnlread_ascii, which stops at the first unparseable token and reports success —Parameters: 1 2 oops 4silently yields[1, 2](itkTxtTransformIO.cxx:183-186)TxtTransformIOtransformlocal is reassigned perTransform:line and buffered parameters apply only once bothParametersandFixedParametershave been seen — unpaired lines bind one transform's parameters to a different transform, silently (:168-232)TxtTransformIO#Insight Transform File V1.0header is swallowed by the#-comment skip and never validated;CanReadFilechecks only the.txt/.tfmextension (:148,:39-46)TxtTransformIOFixedParametersvector writes the lineFixedParameters:with a trailing space (:238-250,:303-305)HDF5TransformIOCanWriteFileclaims.hdf/.h4/.hdf4/.he4— HDF4 container names — thoughWritealways creates an HDF5 file, and the lowercase extension table rejects.H5/.HDF5(itkHDF5TransformIO.cxx:83-84,:424)PNGImageIO::ReadImageInformationis a barereturn;on a wrong PNG signature (:334-338) whereReadthrows"File is not png type: …"for the identicalpng_sig_cmp(:139-143) — a caller reaching it viaSetImageIO(bypassingCanReadFile) gets a fabricated success withm_Dimensionsunset. A missing file pointer returns silently the same way (:321-324)PNGImageIO::CanWriteFilepassesignoreCase = falsetoHasSupportedWriteExtension(:497), unlike the trait's own case-insensitive default;.pngand.PNGare both registered (:281-287), sofoo.PNGis claimed butfoo.PnGis notm_ExpandRGBPalette's in-class initializer isfalse(itkImageIOBase.h:853) butImageIOBase's constructor callsReset(false), which unconditionally sets ittrue(itkImageIOBase.cxx:28,45) —PNGImageIOnever touches the flag, so the header default is dead and every instance starts with palette expansion onHDF5TransformIO'sReadParameters/ReadFixedParametersemit"Wrong data type for " << DataSetName << "in HDF5 File"— no space beforein, so the dataset name runs into the word (itkHDF5TransformIO.cxx:171,:217)"Wrong # of dims for TransformType in HDF5 File"(:176,:222) —TransformTypeis the one dataset the check never coversHDF5TransformIO::Readloopsi < transformGroup.getNumObjs()and thenopenGroup(GetTransformName(i))(:297-302);getNumObjscounts every link, so one stray dataset beside the0,1, … subgroups makes the loop ask for a groupNthat was never written and the read dies inside libhdf5 rather than reporting an extra objectHDF5TransformIO::CanReadFileish5file.exists("/TransformGroup")(:59-66), i.e.H5Lexists— a dataset of that name passes, the factory hands the file over, andRead'sopenGroup(:295) throws anH5::Exceptioninstead of the factory's clean "could not create Transform IO object"HDF5ImageIOstores three axis conventions in one group:Dimension/Origin/Spacingin ITK order, fastest-moving first (:1151-1161); onlyVoxelData's dataspace is reversed (:1170-1182); andDirectionswritesm_Direction[i]as its rowi(:490-510) while that is columniof the direction matrix — so a 4×3 2-D image writesDimension = [4, 3]and aVoxelDataof shape[3, 4], and theDirectionsdataset is the matrix transposeHDF5ImageIO'sReadScalar(:410) andReadVector(:479) both raise"Wrong # of dims for TransformType in HDF5 File"— the transform IO's message (Q94), verbatim, in a file that holds no transform.ReadDirections(:521) at least names the image directionsVoxelTypeis written on everyWrite(:1163-1166) and read on noRead:m_ComponentTypeis derived fromimageSet.getDataType()(:752-753). A file whoseVoxelTypereadsFLOAToverint16voxels loads asInt16; a file with noVoxelTypeat all loads fine. The class comment (itkHDF5ImageIO.h:68-71) says it exists to make the file "user friendly with respect to HDF5 viewers", so this is by design — worth stating, since it looks authoritativeHDF5ImageIO::CanReadFileish5file.exists("/ITKImage")(:647-654) — sameH5Lexistsshape as Q96, so a dataset named/ITKImageis claimed andReadImageInformation's firstopenDataSetthrowsReadImageInformation's meta-data branches are unreachable:WriteScalar(unsigned long)storesNATIVE_UINTtaggedisUnsignedLong(:322-342), so no ITK-written dataset is everNATIVE_INT+isUnsignedLongas:801-805expects; and on every LP64 platformH5Tequal(NATIVE_LONG, NATIVE_LLONG)andH5Tequal(NATIVE_ULONG, NATIVE_ULLONG)are true, so the arms at:874-897swallow every 64-bit integer and those at:898-905never run (theisLLong/isULLongtags inside the surviving arms are what actually distinguish the two)continue(:785-789), and theif/else ifchain over the fourteenNATIVE_*types ends in anelsethat tests onlymetaDataType == strTypewith noelseof its own (:914-922) — so a compound, enum, array or variable-length-sequence dataset leaves no dictionary entry and raises nothing. A subgroup underMetaData, by contrast, is fatal: the loop opens every link withopenDataSet(:776-782)HDF5ImageIO's constructor registers.hdf,.h4,.hdf4,.he4— HDF4 container names — for both reading and writing alongside the HDF5 ones (:36-43), the same eight-name list already noted on the transform side (Q89). HereCanWriteFileisHasSupportedWriteExtension(name)withignoreCase = true(itkImageIOBase.h:788), soIMAGE.H5is claimed for writing where the transform IO's case-sensitiveCanWriteFiledeclines itJPEGImageIO::Writethrows"JPEG Writer can only write 2-dimensional images"before opening anything (:459-462), wherePNGImageIO::WriteSlicesilently writes only the first slice (B71) — the two sibling IOs disagree on whether a 3-D source is an errorJPEGImageIO::CanReadFileis markedly stricter than PNG's: case-sensitive extension (:102,ignoreCase = false), then the0xFFD8magic (:117-130), then a fulljpeg_read_headerparse (:152) — wherePNGImageIO::CanReadFilestops at the 8-byte signatureJPEGImageIO::CanWriteFilepassesignoreCase = false(:449) against four registered spellings (:308-314) —.jpg,.JPG,.jpeg,.JPEGare claimed,.Jpgis not. Same shape as PNG's (Q91)m_UseCompressionis assignedfalsein the constructor (:299) and never read:jpeg_set_qualityis called unconditionally (:537), so onlyQuality/CompressionLevelhas any effect andUseCompressionOn()is silently inert for this IOfloatprecision:WriteImageInformationstores25.4 / m_Spacing[i](:587,:794) intoXRESOLUTION, which libtiff holds as afloat(tif_dir.h:98;TIFF_RATIONAL/TIFF_SETGET_FLOAT,tif_dirinfo.c:90) andm_XResolutionmirrors asfloat— so a spacing of1.0reads back as1.0000000150…. (b)TIFFReaderInternal::InitializereadsXRESOLUTIONwith the non-defaultedTIFFGetField(:202) overClean()'s seed of1, while the read guard is onlyunit > 0 && m_XResolution > 0(:375-385) — so a page withRESOLUTIONUNIT = 2(inch) and noXRESOLUTIONtag yields a spacing of25.4rather than the default1.0. (An absentRESOLUTIONUNITseedsunit = 1, which takes neither branch, so the plain case is safe.)FastChamferDistanceImageFilterfor (it.GoToEnd(), --it; !it.IsAtBegin(); --it)(.hxx:194), so flat index 0 is never the center of the backward pass — harmless, because the pass writes to lower-index neighbours and flat index 1 still updates it. The 3-D weights are the float literals0.92644,1.34065,1.65849(.hxx:38,:41,:44)IsolatedConnectedImageFilterNumericTraits<InputPixelType>::AccumulateType(.hxx:147,:178-180,:243-245), which forunsigned intisunsigned int— no widening (itkNumericTraits.h:1027).guess = (upper + lower) / 2(.hxx:231,:296) can therefore overflow for thresholds nearUINT_MAXSTAPLEImageFilterp = q = 0.99999seeding:Wis seeded from the rater mean (.hxx:116), the priorg_tis computed once before the loop (:123), per-rater convergence is(dp)² , (dq)² ≤ 1e-14(:51,:215-220), and the foreground test is a two-sided ε-window withε = 1e-10(:94). Worth stating because implementations that copy the papers' seeding will not reproduce ITKBinaryMedianImageFilter>againstneighborhoodSize / 2(.hxx:121,:136-143), so a tie goes to background; and the output is always exactlyForegroundValueorBackgroundValue— a pixel whose value matches neither is not passed throughChangeLabelImageFilterstd::map<InputPixelType, OutputPixelType>(.h:57), so keys are quantized through the pixel type and a repeated key is last-wins (.h:77);operator()performs a single lookup (.h:92-101), soa→btogether withb→cis not transitive —amaps tobBSplineDecompositionImageFilterhorizon < dataLength, where `horizon = ceil(log(tol)/log(PatchBasedDenoisingImageFilternoise-model fidelity2·(in − out)(.hxx:2015) and POISSON's(in − out)/(out + 1e-5)(:2049) are both identically zero. With SimpleITK's defaultNumberOfIterations = 1, neither noise model contributes anything; RICIAN's Bessel-ratio term (:2031-2032) is nonzero and is unaffectedPatchBasedDenoisingImageFilterinternalsResolveSigmaUpdatewritesm_KernelBandwidthSigma(.hxx:1854,:1860) before returning, and the caller then compares|sigmaUpdate|against the already-updated sigma (:1427);m_MinProbability = 2.2e-306(:43) is added to the entropy probability and to its first and second derivatives (:1734-1738); and on the skipped-query path the subsampler'soffsetkeeps its zero initialization rather than being recomputed byComputeOffset(itkSpatialNeighborSubsampler.hxx:140,:147-151)JoinSeriesImageFiltersize mismatch.hxx:209-216), so a subsequent input that is smaller throwsInvalidRequestedRegionErrorfrom region propagation, while one that is larger is silently corner-cropped to[0, primary_size). (Physical congruency is checked separately, withcoordinateTol = m_CoordinateTolerance · spacing[0]— the first dimension's spacing for every axis,itkImageToImageFilter.hxx:184-185)TransformToDisplacementFieldFilterlinear fast pathidx[0]andidx[0] + size[0]— one past the last pixel — withalpha = i / size[0](.hxx:239,:245,:255-256). This is exact rather than off-by-one, because for a linear transformT(p) − pis affine, so interpolating between those two endpoints reproduces the displacement at every interior pixel. Recorded because it reads like an off-by-one and is notAlso:
LinearAnisotropicDiffusionLBRImageFilter's Selling decomposition bails out after 200 superbase flips by printing"Warning: Selling's algorithm not stabilized."tostd::cerrand continuing with a possibly non-obtuse superbase — which can yield negative stencil weights. The 2-D branch guards obtuseness with a debug-onlyassert; the 3-D branch has no check at all (.hxx:185-263).AI assistance
mainate46eb723a5, checking declared types and constructor defaults, re-deriving each consequence)e46eb723a5; behavioral claims cross-checked against the independent reimplementation's pinned tests. B28 is source analysis only (not run to a live hang) and is labeled as such inline.