scirs2-ndimage 0.4.2

N-dimensional image processing module for SciRS2 (scirs2-ndimage)
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
//! Module Documentation Builders
//!
//! This module contains functions to build comprehensive documentation
//! for all the different modules in the SciRS2 NDImage library.

use crate::documentation::types::{DocumentationSite, FunctionDoc, ModuleDoc, Parameter, Result};

impl DocumentationSite {
    /// Build comprehensive module documentation for all library modules
    pub fn build_module_documentation(&mut self) -> Result<()> {
        self.modules = vec![
            build_filters_documentation(),
            build_morphology_documentation(),
            build_interpolation_documentation(),
            build_measurements_documentation(),
        ];
        Ok(())
    }
}

/// Build documentation for the Filters module
pub fn build_filters_documentation() -> ModuleDoc {
    let mut module = ModuleDoc::new(
        "Filters",
        "Image filtering operations including Gaussian, median, rank, and edge detection filters",
    );

    // Gaussian filter documentation
    let mut gaussian_filter = FunctionDoc::new(
        "gaussian_filter",
        "pub fn gaussian_filter<T>(input: &ArrayD<T>, sigma: f64) -> ArrayD<T>",
        "Apply Gaussian filter to n-dimensional array",
        "ArrayD<T> - Filtered array",
    );

    gaussian_filter.add_parameter(Parameter::required(
        "_input",
        "&ArrayD<T>",
        "Input n-dimensional array",
    ));
    gaussian_filter.add_parameter(Parameter::required(
        "sigma",
        "f64",
        "Standard deviation for Gaussian kernel",
    ));

    gaussian_filter.add_example(
        r#"use scirs2_ndimage::filters::gaussian_filter;
use scirs2_core::ndarray::Array2;

let image = Array2::from_elem((100, 100), 1.0f64);
let filtered = gaussian_filter(&image, 2.0);
assert_eq!(filtered.shape(), image.shape());"#,
    );

    gaussian_filter.add_note("Uses separable convolution for efficiency");
    gaussian_filter.add_note("Supports all numeric types");

    module.add_function(gaussian_filter);

    // Median filter documentation
    let mut median_filter = FunctionDoc::new(
        "median_filter",
        "pub fn median_filter<T>(input: &ArrayD<T>, size: usize) -> ArrayD<T>",
        "Apply median filter to remove noise while preserving edges",
        "ArrayD<T> - Filtered array",
    );

    median_filter.add_parameter(Parameter::required(
        "_input",
        "&ArrayD<T>",
        "Input n-dimensional array",
    ));
    median_filter.add_parameter(Parameter::required(
        "size",
        "usize",
        "Size of the median filter window",
    ));

    median_filter.add_example(
        r#"use scirs2_ndimage::filters::median_filter;
use scirs2_core::ndarray::Array2;

let noisyimage = Array2::from_elem((50, 50), 128.0f64);
let filtered = median_filter(&noisyimage, 3);
// Median filter removes salt-and-pepper noise"#,
    );

    median_filter.add_note("Excellent for removing salt-and-pepper noise");
    median_filter.add_note("Preserves edges better than linear filters");

    module.add_function(median_filter);

    // Module examples
    module.add_example("Basic filtering operations");
    module.add_example("Edge detection pipeline");
    module.add_example("Noise reduction techniques");

    module
}

/// Build documentation for the Morphology module
pub fn build_morphology_documentation() -> ModuleDoc {
    let mut module = ModuleDoc::new(
        "Morphology",
        "Mathematical morphology operations for binary and grayscale images",
    );

    // Binary erosion documentation
    let mut binary_erosion = FunctionDoc::new(
        "binary_erosion",
        "pub fn binary_erosion(input: &ArrayD<bool>, structure: &ArrayD<bool>) -> ArrayD<bool>",
        "Perform binary erosion operation",
        "ArrayD<bool> - Eroded binary array",
    );

    binary_erosion.add_parameter(Parameter::required(
        "_input",
        "&ArrayD<bool>",
        "Input binary array",
    ));
    binary_erosion.add_parameter(Parameter::required(
        "structure",
        "&ArrayD<bool>",
        "Structuring element",
    ));

    binary_erosion.add_example(
        r#"use scirs2_ndimage::morphology::binary_erosion;
use scirs2_core::ndarray::Array2;

let binary_image = Array2::from_elem((10, 10), true);
let structure = Array2::from_elem((3, 3), true);
let eroded = binary_erosion(&binary_image, &structure);"#,
    );

    binary_erosion.add_note("Shrinks white regions in binary images");
    binary_erosion.add_note("Useful for separating connected objects");

    module.add_function(binary_erosion);

    // Distance transform documentation
    let mut distance_transform = FunctionDoc::new(
        "distance_transform_edt",
        "pub fn distance_transform_edt(input: &ArrayD<bool>) -> ArrayD<f64>",
        "Compute Euclidean distance transform using optimized algorithm",
        "ArrayD<f64> - Distance transform",
    );

    distance_transform.add_parameter(Parameter::required(
        "_input",
        "&ArrayD<bool>",
        "Input binary array",
    ));

    distance_transform.add_example(
        r#"use scirs2_ndimage::morphology::distance_transform_edt;
use scirs2_core::ndarray::Array2;

let binary_image = Array2::from_elem((100, 100), false);
let distances = distance_transform_edt(&binary_image);
// Each pixel contains distance to nearest background pixel"#,
    );

    distance_transform.add_note("Uses Felzenszwalb & Huttenlocher separable algorithm for O(n) performance");
    distance_transform.add_note("Supports arbitrary dimensions");

    module.add_function(distance_transform);

    // Module examples
    module.add_example("Object size analysis");
    module.add_example("Shape decomposition");
    module.add_example("Skeletonization");

    module
}

/// Build documentation for the Interpolation module
pub fn build_interpolation_documentation() -> ModuleDoc {
    let mut module = ModuleDoc::new(
        "Interpolation",
        "Geometric transformations and interpolation operations",
    );

    // Affine transform documentation
    let mut affine_transform = FunctionDoc::new(
        "affine_transform",
        "pub fn affine_transform<T>(input: &ArrayD<T>, matrix: &Array2<f64>) -> ArrayD<T>",
        "Apply affine transformation to n-dimensional array",
        "ArrayD<T> - Transformed array",
    );

    affine_transform.add_parameter(Parameter::required(
        "_input",
        "&ArrayD<T>",
        "Input array to transform",
    ));
    affine_transform.add_parameter(Parameter::required(
        "matrix",
        "&Array2<f64>",
        "Affine transformation matrix",
    ));

    affine_transform.add_example(
        r#"use scirs2_ndimage::interpolation::affine_transform;
use scirs2_core::ndarray::{Array2, array};

let image = Array2::from_elem((50, 50), 1.0f64);
let rotation_matrix = array![[0.866, -0.5], [0.5, 0.866]]; // 30 degree rotation
let rotated = affine_transform(&image, &rotation_matrix);"#,
    );

    affine_transform.add_note("Supports rotation, scaling, shearing, and translation");
    affine_transform.add_note("Uses spline interpolation for high quality results");

    module.add_function(affine_transform);

    // Module examples
    module.add_example("Image registration");
    module.add_example("Geometric correction");
    module.add_example("Multi-resolution analysis");

    module
}

/// Build documentation for the Measurements module
pub fn build_measurements_documentation() -> ModuleDoc {
    let mut module = ModuleDoc::new(
        "Measurements",
        "Statistical measurements and region analysis",
    );

    // Center of mass documentation
    let mut center_of_mass = FunctionDoc::new(
        "center_of_mass",
        "pub fn center_of_mass<T>(input: &ArrayD<T>) -> Vec<f64>",
        "Calculate center of mass of n-dimensional array",
        "Vec<f64> - Center of mass coordinates",
    );

    center_of_mass.add_parameter(Parameter::required(
        "_input",
        "&ArrayD<T>",
        "Input array",
    ));

    center_of_mass.add_example(
        r#"use scirs2_ndimage::measurements::center_of_mass;
use scirs2_core::ndarray::Array2;

let image = Array2::from_elem((100, 100), 1.0f64);
let com = center_of_mass(&image);
println!("Center of mass: {:?}", com);"#,
    );

    center_of_mass.add_note("Works with any numeric type");
    center_of_mass.add_note("Returns coordinates in array index order");

    module.add_function(center_of_mass);

    // Module examples
    module.add_example("Object property analysis");
    module.add_example("Region statistics");
    module.add_example("Feature extraction");

    module
}

/// Helper function to add common filter functions to a module
pub fn add_common_filter_functions(module: &mut ModuleDoc) {
    // Add sobel filter
    let mut sobel_filter = FunctionDoc::new(
        "sobel_filter",
        "pub fn sobel_filter<T>(input: &ArrayD<T>) -> ArrayD<T>",
        "Apply Sobel edge detection filter",
        "ArrayD<T> - Edge-detected array",
    );

    sobel_filter.add_parameter(Parameter::required(
        "_input",
        "&ArrayD<T>",
        "Input n-dimensional array",
    ));

    sobel_filter.add_example(
        r#"use scirs2_ndimage::filters::sobel_filter;
use scirs2_core::ndarray::Array2;

let image = Array2::from_elem((100, 100), 1.0f64);
let edges = sobel_filter(&image);"#,
    );

    sobel_filter.add_note("Detects edges using Sobel operators");
    sobel_filter.add_note("Returns magnitude of gradient");

    module.add_function(sobel_filter);

    // Add laplacian filter
    let mut laplacian_filter = FunctionDoc::new(
        "laplacian_filter",
        "pub fn laplacian_filter<T>(input: &ArrayD<T>) -> ArrayD<T>",
        "Apply Laplacian edge detection filter",
        "ArrayD<T> - Edge-detected array",
    );

    laplacian_filter.add_parameter(Parameter::required(
        "_input",
        "&ArrayD<T>",
        "Input n-dimensional array",
    ));

    laplacian_filter.add_example(
        r#"use scirs2_ndimage::filters::laplacian_filter;
use scirs2_core::ndarray::Array2;

let image = Array2::from_elem((100, 100), 1.0f64);
let edges = laplacian_filter(&image);"#,
    );

    laplacian_filter.add_note("Uses second derivative for edge detection");
    laplacian_filter.add_note("More sensitive to noise than Sobel");

    module.add_function(laplacian_filter);
}

/// Helper function to add common morphology functions to a module
pub fn add_common_morphology_functions(module: &mut ModuleDoc) {
    // Add binary dilation
    let mut binary_dilation = FunctionDoc::new(
        "binary_dilation",
        "pub fn binary_dilation(input: &ArrayD<bool>, structure: &ArrayD<bool>) -> ArrayD<bool>",
        "Perform binary dilation operation",
        "ArrayD<bool> - Dilated binary array",
    );

    binary_dilation.add_parameter(Parameter::required(
        "_input",
        "&ArrayD<bool>",
        "Input binary array",
    ));
    binary_dilation.add_parameter(Parameter::required(
        "structure",
        "&ArrayD<bool>",
        "Structuring element",
    ));

    binary_dilation.add_example(
        r#"use scirs2_ndimage::morphology::binary_dilation;
use scirs2_core::ndarray::Array2;

let binary_image = Array2::from_elem((10, 10), true);
let structure = Array2::from_elem((3, 3), true);
let dilated = binary_dilation(&binary_image, &structure);"#,
    );

    binary_dilation.add_note("Expands white regions in binary images");
    binary_dilation.add_note("Useful for connecting nearby objects");

    module.add_function(binary_dilation);
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_filters_documentation() {
        let filters_doc = build_filters_documentation();
        assert_eq!(filters_doc.name, "Filters");
        assert!(!filters_doc.functions.is_empty());
        assert!(!filters_doc.examples.is_empty());

        // Check that Gaussian filter is documented
        let gaussian = filters_doc
            .functions
            .iter()
            .find(|f| f.name == "gaussian_filter");
        assert!(gaussian.is_some());

        let gaussian = gaussian.expect("Operation failed");
        assert_eq!(gaussian.parameters.len(), 2);
        assert!(!gaussian.examples.is_empty());
        assert!(!gaussian.notes.is_empty());
    }

    #[test]
    fn test_morphology_documentation() {
        let morphology_doc = build_morphology_documentation();
        assert_eq!(morphology_doc.name, "Morphology");
        assert!(!morphology_doc.functions.is_empty());

        // Check that binary erosion is documented
        let erosion = morphology_doc
            .functions
            .iter()
            .find(|f| f.name == "binary_erosion");
        assert!(erosion.is_some());

        let erosion = erosion.expect("Operation failed");
        assert_eq!(erosion.parameters.len(), 2);
    }

    #[test]
    fn test_interpolation_documentation() {
        let interpolation_doc = build_interpolation_documentation();
        assert_eq!(interpolation_doc.name, "Interpolation");
        assert!(!interpolation_doc.functions.is_empty());

        // Check that affine transform is documented
        let affine = interpolation_doc
            .functions
            .iter()
            .find(|f| f.name == "affine_transform");
        assert!(affine.is_some());
    }

    #[test]
    fn test_measurements_documentation() {
        let measurements_doc = build_measurements_documentation();
        assert_eq!(measurements_doc.name, "Measurements");
        assert!(!measurements_doc.functions.is_empty());

        // Check that center of mass is documented
        let com = measurements_doc
            .functions
            .iter()
            .find(|f| f.name == "center_of_mass");
        assert!(com.is_some());
    }

    #[test]
    fn test_module_documentation_builder() {
        let mut site = DocumentationSite::new();
        let result = site.build_module_documentation();

        assert!(result.is_ok());
        assert_eq!(site.modules.len(), 4);

        // Check all expected modules are present
        let module_names: Vec<_> = site.modules.iter().map(|m| &m.name).collect();
        assert!(module_names.contains(&&"Filters".to_string()));
        assert!(module_names.contains(&&"Morphology".to_string()));
        assert!(module_names.contains(&&"Interpolation".to_string()));
        assert!(module_names.contains(&&"Measurements".to_string()));
    }
}