Coverage for src/recon3d/image_stack_to_array.py: 34%
59 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-02 00:06 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-02 00:06 +0000
1"""Converts a series of images to a stack array."""
3import argparse
4from pathlib import Path
5from typing import NamedTuple
7import numpy as np
8import yaml
10import recon3d.utility as ut
13class Recipe(NamedTuple):
14 """Defines the recipe to run this module directly from its Python API.
16 Attributes
17 ----------
18 """
20 image_dir: Path
21 image_type: str
22 out_dir: Path
25def save_image_stack_to_array(image_dir: Path, file_extension: str, out_dir: Path):
26 """
27 Reads all images with a specified file extension from a directory,
28 stores them in a numpy array, and saves the array to a .npy file in the
29 specified directory.
31 Parameters:
32 image_dir: The directory from which to read images.
33 file_extension: The file extension of the images to read.
34 out_dir: The directory where the .npy file will be saved.
35 """
36 try:
37 # Assuming 'ut.read_images' is a valid function that reads images and
38 # returns a numpy array
39 array_data = ut.read_images(image_dir, file_extension)
41 # Correctly form the output file path
42 out_file_path = out_dir.joinpath(f"{image_dir.name}.npy")
44 # Save the numpy array to a .npy file
45 np.save(out_file_path, array_data)
47 print(f"Images from {image_dir} saved to {out_file_path}")
49 except Exception as e:
50 print(f"An error occurred: {e}")
53def validate_recipe(*, recipe: Recipe) -> bool:
54 """Validate the given recipe.
56 Ensures that all values in the Recipe NamedTuple are valid.
58 Parameters
59 ----------
60 recipe : Recipe
61 The recipe to validate.
63 Raises
64 ------
65 AssertionError
66 If any of the recipe attributes are invalid.
68 Examples
69 --------
70 >>> recipe = Recipe(
71 ... input_path=Path("path/to/input"),
72 ... input_file_type=".tif",
73 ... output_path=Path("path/to/output")
74 ... )
75 >>> validate_recipe(recipe)
76 True
77 """
78 assert isinstance(recipe.image_dir, Path), "image_dir must be a Path object"
79 assert recipe.image_dir.is_dir(), "image_dir must be a directory"
80 assert isinstance(recipe.image_type, str), "image_type must be a string"
81 assert recipe.image_type in [
82 ".tif",
83 ".tiff",
84 ], "image_type must be .tif or .tiff"
85 assert isinstance(recipe.out_dir, Path), "out_path must be a Path object"
86 assert recipe.out_dir.is_dir(), "out_path must be a directory"
88 return True
91def image_to_stack_array(*, yml_input_file: Path) -> bool:
92 """Converts a series of images to a stack array.
94 Parameters
95 ----------
96 yml_input_file : Path
97 The path to the input .yml file containing the image paths and other
98 parameters.
100 Returns
101 -------
102 True if the conversion is successful, False otherwise.
104 Raises
105 ------
106 FileNotFoundError
107 If the input .yml file is not found.
108 TypeError
109 If the input file type is not supported.
110 OSError
111 If there is an error with the yml module.
112 """
113 print(f"This is {Path(__file__).resolve()}")
115 fin = yml_input_file.resolve().expanduser()
117 print(f"Processing file: {fin}")
119 if not fin.is_file():
120 raise FileNotFoundError(f"File not found: {str(fin)}")
122 file_type = fin.suffix.casefold()
123 supported_types = (".yaml", ".yml")
125 if file_type not in supported_types:
126 raise TypeError("Only file types .yaml, and .yml are supported.")
128 db = []
130 try:
131 with open(file=fin, mode="r", encoding="utf-8") as stream:
132 db = yaml.load(stream, Loader=yaml.SafeLoader) # overwrite
133 except yaml.YAMLError as error:
134 print(f"Error with yml module: {error}")
135 print(f"Could not open or decode: {fin}")
136 raise OSError from error
138 print(f"Success: database created from file: {fin}")
139 print(db)
141 recipe = Recipe(
142 image_dir=Path(db["image_dir"]).expanduser(),
143 image_type=db["image_type"],
144 out_dir=Path(db["out_dir"]).expanduser(),
145 )
147 validate_recipe(recipe=recipe)
149 save_image_stack_to_array(
150 image_dir=recipe.image_dir,
151 file_extension=recipe.image_type,
152 out_dir=recipe.out_dir,
153 )
155 return True # success
158def main():
159 """
160 Runs the module from the command line.
162 This function serves as the entry point for terminal-based access to the
163 module. It uses the argparse library to parse command-line arguments.
165 Parameters
166 ----------
167 None
169 Returns
170 -------
171 None
173 Examples
174 --------
175 To run the module, use the following command in the terminal:
176 $ image_to_stack_array path/to/input.yml
177 """
179 parser = argparse.ArgumentParser()
180 parser.add_argument("input_file", help="the .yml input file")
181 args = parser.parse_args()
182 input_file = args.input_file
183 input_file = Path(input_file).expanduser()
185 image_to_stack_array(yml_input_file=input_file)
188if __name__ == "__main__":
189 main()