ct.io¶
Functions for reading and writing images and depth images.
- ct.io.imwrite(im_path, im, quality=95)[source]¶
Write an image, with no surprises.
- This function handles common image writing tasks including:
Automatic directory creation
Image format detection based on file extension
Input validation and type conversion
Color space conversion (RGB to BGR for OpenCV)
- Parameters:
im_path (Union[str, Path]) – Path to save the image. Supported extensions:
.jpg,.jpeg,.png. Parent directories will be created automatically if they don’t exist.im (Union[UInt8[np.ndarray], Float[np.ndarray]]) –
Image data as a numpy array. Supported formats:
Grayscale: 2D array (height x width)
Color: 3D array (height x width x 3)
Supported data types:
uint8: Values in range [0, 255]
float32/float64: Values in range [0.0, 1.0] (will be scaled to uint8)
quality (int, optional) – JPEG quality setting (1-100). Defaults to 95. Higher values mean better quality but larger file size. Only applies to JPEG images.
Notes
Depth images (typically uint16) should use imwrite_depth() instead
Float images are automatically scaled to [0, 1] range and converted to uint8
For PNG images, the quality parameter is ignored
Color images are automatically converted from RGB to BGR format for OpenCV
Examples
# Save a grayscale image grayscale = np.random.rand(256, 256).astype(np.float32) imwrite('output.jpg', grayscale) # Save a color image with high quality color = np.random.rand(256, 256, 3).astype(np.uint8) imwrite('output.jpg', color, quality=100)
- ct.io.imwrite_depth(im_path, im, depth_scale=1000.0)[source]¶
Write depth map to a 16-bit PNG file with depth scaling.
- This function handles depth map storage by:
Scaling depth values by depth_scale
Converting to 16-bit unsigned integer format
Creating necessary directories
Validating input data
- Parameters:
im_path (Union[str, Path]) – Output file path. Must have .png extension. Parent directories will be created automatically if they don’t exist.
im (Float[np.ndarray]) –
Depth map as a 2D numpy array. Must be:
Shape: (height, width)
Data type: float32 or float64
Values: Depth values in meters (or other consistent units)
depth_scale (float, optional) –
Scaling factor to apply before converting to uint16. Defaults to 1000.0. This determines the precision of stored depth values. For example:
depth_scale=1000: 1mm precision
depth_scale=100: 1cm precision
depth_scale=1: 1m precision
Notes
Invalid depth values (np.nan, np.inf, etc.) are converted to 0
Depth values are clipped to uint16 range (0-65535) after scaling
For best results, use 0 to represent invalid depth values
When reading the depth map with imread_depth(), use the same depth_scale to recover the original depth values
The user is responsible for defining what is invalid depth. E.g., invalid depth can represented as np.nan, np.inf, 0, -1, etc. This function simply multiplies the depth by depth_scale can convert to uint16. For instance, with depth_scale = 1000:
- Input depths : [np.nan, np.inf, -np.inf, 0, -1, 3.14] - Written to ".png": [ 0, 0, 0, 0, 64536, 3140] - Read from ".png" : [ 0, 0, 0, 0, 64536, 3140] - Convert to float : [ 0, 0, 0, 0, 64.536, 3.14] ^ Best practice: Use 0 to represent invalid depth
Note that -1 is converted to 64536 / 1000 = 64.536 meters, therefore, it is important to clip depth with min_depth and max_depth. The best practice is to use 0 as invalid depth.
Examples
# Write depth map with 1mm precision depth = np.random.rand(256, 256).astype(np.float32) * 10 # 0-10 meters imwrite_depth('depth.png', depth, depth_scale=1000) # Write depth map with 1cm precision imwrite_depth('depth.png', depth, depth_scale=100)
- ct.io.imread(im_path, alpha_mode=None)[source]¶
Read and image, with no surprises. Guaranteed to return float32 arrays in range [0, 1] with RGB(A) color space.
- This function handles image reading by:
Automatically converting to float32 in range [0, 1]
Supporting both grayscale and color images
Providing multiple options for handling alpha channels
Converting color space from BGR to RGB
- Parameters:
im_path (Union[str, Path]) –
Path to the image file. Supported formats:
.jpg/.jpeg: JPEG format
.png: PNG format (may contain alpha channel)
alpha_mode (Optional[str]) –
Specifies how to handle alpha channels:
None : Default. Raise error if alpha channel is present
”keep” : Preserve alpha channel (returns RGBA)
”ignore”: Discard alpha channel (returns RGB)
”white” : Composite with white background (returns RGB)
”black” : Composite with black background (returns RGB)
- Returns:
- Normalized image array with:
Data type: float32
Value range: [0, 1]
- Possible shapes:
Grayscale: (height, width)
Color: (height, width, 3)
With alpha: (height, width, 4) (only when alpha_mode=”keep”)
- Possible number of channels based on alpha_mode:
alpha_mode == None : {1, 3}
alpha_mode == “keep” : {1, 3, 4}
alpha_mode == “ignore”: {1, 3}
alpha_mode == “white” : {1, 3}
alpha_mode == “black” : {1, 3}
- Return type:
Union[Float[np.ndarray]]
Notes
Input images must be uint8 or uint16 format
Color images are automatically converted from BGR to RGB
For depth images, use imread_depth() instead
When alpha_mode is None, images with alpha channels will raise an error
Examples
# Read grayscale image gray = imread('image.jpg') # Read color image, ignore alpha if present rgb = imread('image.png', alpha_mode='ignore') # Read image with alpha channel preserved rgba = imread('image.png', alpha_mode='keep') # Read image with white background for transparency rgb_white = imread('image.png', alpha_mode='white')
- ct.io.imread_depth(im_path, depth_scale=1000.0)[source]¶
Read and normalize a 16-bit depth map from a PNG file.
- This function handles depth map reading by:
Loading 16-bit depth values from PNG
Converting to float32
Applying depth scale normalization
Validating input data
- Parameters:
- Returns:
- Depth map as a 2D numpy array with:
Data type: float32
Shape: (height, width)
Values: Depth values in meters (or other consistent units)
- Return type:
Float[np.ndarray]
Notes
Invalid depth values (0, 65535) are preserved in the output
The depth_scale should match the one used during writing
For best results, use 0 to represent invalid depth values
Depth values are not automatically clipped - the user should handle clipping based on their specific requirements
The user is responsible for defining what is invalid depth. E.g., invalid depth can represented as np.nan, np.inf, 0, -1, etc. This function simply multiplies the depth by depth_scale can convert to uint16. For instance, with depth_scale = 1000:
- Input depths : [np.nan, np.inf, -np.inf, 0, -1, 3.14] - Written to ".png": [ 0, 0, 0, 0, 64536, 3140] - Read from ".png" : [ 0, 0, 0, 0, 64536, 3140] - Convert to float : [ 0, 0, 0, 0, 64.536, 3.14] ^ Best practice: Use 0 to represent invalid depth
Note that -1 is converted to 64536 / 1000 = 64.536 meters, therefore, it is important to clip depth with min_depth and max_depth. The best practice is to use 0 as invalid depth.
Examples
# Read depth map with 1mm precision depth = imread_depth('depth.png', depth_scale=1000) # Read depth map with 1cm precision depth = imread_depth('depth.png', depth_scale=100) # Read depth map with 1m precision depth = imread_depth('depth.png', depth_scale=1)