ENH: Add Image Reader/Writer that depend on Tiff and Stb libraries.#1585
Open
imikejackson wants to merge 16 commits intoBlueQuartzSoftware:developfrom
Open
ENH: Add Image Reader/Writer that depend on Tiff and Stb libraries.#1585imikejackson wants to merge 16 commits intoBlueQuartzSoftware:developfrom
imikejackson wants to merge 16 commits intoBlueQuartzSoftware:developfrom
Conversation
These new filters use libTiff and Stb libraries to read and write images. The main utility classes IImageIO is placed into the simplnx library itself so any code can utilize it.
…skeleton The skeleton references cxItkImageReaderFilter::OriginSpacingProcessingTiming which is an ITK plugin type not available in SimplnxCore. Commented out until ReadImageStackFilter implementation replaces it with a local enum. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduces a strategy-pattern image I/O layer under Utilities/ImageIO/ that decouples image file reading/writing from simplnx data structures. Includes ImageMetadata struct, IImageIO abstract interface, factory function for backend selection by extension, and two concrete backends: StbImageIO (PNG/JPEG/BMP via stb_image/stb_image_write) and TiffImageIO (TIFF via libtiff with scanline and tiled image support). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add IImageIO, ImageMetadata, ImageIOFactory, StbImageIO, TiffImageIO to SIMPLNX_HDRS and SIMPLNX_SRCS in root CMakeLists.txt - Move STB_IMAGE_IMPLEMENTATION from ReadImageFilter.cpp to StbImageIO.cpp - Use uint16_t/uint32_t/int32_t for TIFF-interacting variables to avoid collision with libtiff's deprecated typedef names Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ReadImage algorithm reads single 2D images via IImageIO into DataArrays. ReadImageFilter provides preflight with geometry/array creation and origin/spacing override support. Data type conversion with ratio scaling. Removes direct Stb/TIFF dependencies from SimplnxCore CMakeLists since those are now handled by the ImageIO abstraction layer. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
WriteImage extracts 2D slices along XY/XZ/YZ planes from 3D ImageGeometry and writes individual image files via IImageIO. Uses AtomicFile for safe writes. Temp buffers are one slice only. WriteImageFilter validates parameters and delegates to algorithm. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reads numbered image sequences into 3D ImageGeometry via IImageIO. Uses ReadImageFilter as sub-filter for per-slice reading. Supports resampling, grayscale conversion, flip transforms, origin/spacing overrides, and Z-slice cropping. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests mirror the ITK test patterns for ReadImageFilter, WriteImageFilter, and ReadImageStackFilter. Use same test data archives as the ITK tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ConvertImageToDataStoreAsType in ReadImageUtils.hpp was only converting the first channel of multi-component (vector) images (e.g. RGB, RGBA) because std::transform was bounded by pixelContainer->Size(), which returns the number of pixels rather than the number of underlying scalar elements. For an N-component image this caused (N-1)/N of the destination buffer to be left uninitialized (zeros). Multiply pixelContainer->Size() by the number of components per pixel (derived from sizeof(PixelT)/sizeof(T)) so all channels are scaled. The itk_image_reader_test exemplar archive was regenerated with the correct conversion for the DataType_Conversion, Interaction_Crop_DataType, and Interaction_Crop_OriginSpacing_Preprocessed_DataType datasets. It is now published as itk_image_reader_test_v2.tar.gz with an updated SHA512. Both ITKImageReaderTest and ReadImageTest reference the v2 archive. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This reverts commit 04b4944.
Applies voxel and physical bounds cropping to 2D images. Uses CropImageGeomFilter in preflight to compute cropped dimensions, origin, and spacing. Execute extracts the cropped subvolume from the temp buffer before copying to DataStore. Respects pre/post- processed timing for origin/spacing overrides. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The ReadImageStackFilter preflight creates the resampled image geometry at a temporary "_resampled" path in the main DataStructure and renames it back to the original path via a deferred action that runs AFTER executeImpl completes. Similarly, when grayscale conversion is enabled, the preflight creates the output array with a "grayscale_" prefix and renames it back via a deferred action. The algorithm was writing to the ORIGINAL (un-resampled, un-prefixed) paths during execute, which pointed to stale arrays that still had the original un-resampled dimensions and/or RGB component count. This caused dimension mismatch errors (resample tests) and component count mismatch errors (grayscale tests) when copying slice data into the destination. Match the ITK version of ReadImageStack by updating destImageGeomPath to the "_resampled" path after running the resample sub-filter, and by using the "grayscale_" prefixed array name for the destination path when grayscale conversion is requested. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ConvertImageToDataStoreAsType in ReadImageUtils.hpp was only converting the first 1/N of the scalar buffer for multi-component (vector) images like RGB or RGBA. The std::transform range used pixelContainer->Size(), which returns the number of pixels in the container, not the number of underlying scalar elements. For an itk::Vector<uint8, 3> image, Size() returned width*height while the raw buffer cast to uint8* actually held width*height*3 elements, leaving two-thirds of the destination buffer uninitialized. Multiply by itk::NumericTraits<PixelT>::GetLength() (the canonical ITK component count) so every scalar in the buffer is converted. This breaks the DataType_Conversion, Interaction_Crop_DataType, and Interaction_All test exemplars in itk_image_reader_test.tar.gz, which were generated by the buggy code. The exemplar archive must be regenerated before those tests will pass. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Change TestFileSentinel construction in all ten ITKImageReaderFilter test cases to pass decompressFiles=false and removeTemp=false. This matches the pattern already used by the new SimplnxCore ReadImageFilter tests: the sentinel no longer decompresses the archive on construction (which would overwrite a freshly-regenerated exemplar with the stale archive contents) and no longer deletes the extracted directory on teardown. This allows the regeneration pipeline and both test suites to iterate against the same exemplar without interference. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
40317cd to
3724e79
Compare
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.
Introduces three new SimplnxCore image I/O filters (ReadImageFilter, WriteImageFilter, ReadImageStackFilter) backed by a new format-agnostic IImageIO
abstraction layer, fixes a long-standing multi-component conversion bug in the legacy ITK reader, and consolidates the test data archives for both filter
families into two versioned _v3 archives.
New SimplnxCore filters
ITKImportImageStackFilter counterparts (origin/spacing overrides with pre/post-processed timing, voxel and physical cropping, data type conversion, XY/XZ/YZ
plane slicing on write, flip transforms, grayscale conversion, resampling).
New IImageIO abstraction layer (simplnx/Utilities/ImageIO/)
never larger than a single 2D slice.
Upstream ITK reader bug fix
count, not the scalar element count. For multi-component images (e.g. RGB itk::Vector<uint8, 3>) this left two-thirds of the destination uninitialized. Fixed
by multiplying by itk::NumericTraits::GetLength().