pdnl-process 0.6__tar.gz → 0.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pdnl_process
3
- Version: 0.6
3
+ Version: 0.7
4
4
  Summary: PDNL Process
5
5
  Project-URL: Homepage, https://github.com/PennCompPathology/pdnl_process
6
6
  Author-email: Noah Capp <noahmcapp@gmail.com>
@@ -0,0 +1 @@
1
+ from .main import main, process_roi
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import os
4
+ import sys
5
+ import argparse
6
+ import json
7
+
8
+ import numpy as np
9
+ from tqdm import tqdm
10
+ import pdnl_sana.geo
11
+ import pdnl_sana.image
12
+ import pdnl_sana.process
13
+ import pdnl_sana.logging
14
+ import pdnl_sana.filter
15
+ import pdnl_sana.threshold
16
+
17
+ from matplotlib import pyplot as plt
18
+
19
+ def process_roi(frame, mask, subroi_masks, frame_loc, roi_name, output_path,
20
+ apply_smoothing=False, normalize_background=False,
21
+ background_radius=200, background_overlap=0.5,
22
+ triangular_strictness=0.0, minimum_threshold=0,
23
+ morphology_filters=[],
24
+ staining_code='H-DAB', stain_vector=None, debug_level='normal'):
25
+
26
+ # TODO: move all pdnl_sana.process code into here, then other scripts import these functions
27
+ out_d = os.path.join(output_path, roi_name)
28
+ os.makedirs(out_d, exist_ok=True)
29
+ logger = pdnl_sana.logging.Logger(debug_level, os.path.join(out_d, 'log.pkl'))
30
+
31
+ # TODO: shouldn't be omitting the mask here, but leaving it here so all data is generated in the same way for now.
32
+ # this was a fix for the background code, but that code is solved now
33
+ if staining_code == 'H-DAB':
34
+ processor = pdnl_sana.process.HDABProcessor(
35
+ logger, frame,
36
+ #main_mask=mask,
37
+ apply_smoothing=apply_smoothing,
38
+ normalize_background=normalize_background,
39
+ stain_vector=stain_vector,
40
+ radius=background_radius, overlap=background_overlap,
41
+ )
42
+ if staining_code == 'CV-DAB':
43
+ processor = pdnl_sana.process.CVDABProcessor(
44
+ logger, frame,
45
+ #main_mask=mask,
46
+ apply_smoothing=apply_smoothing,
47
+ normalize_background=normalize_background,
48
+ stain_vector=stain_vector,
49
+ )
50
+ hist = processor.dab.get_histogram(mask=processor.main_mask)
51
+ stain = processor.dab.copy()
52
+ stain.save(os.path.join(out_d, 'stain.npy'))
53
+
54
+ # calculate the threshold
55
+ triangular_strictness = triangular_strictness
56
+ threshold = pdnl_sana.threshold.triangular_method(
57
+ hist,
58
+ strictness=triangular_strictness,
59
+ )
60
+ threshold = np.clip(threshold, minimum_threshold, None)
61
+
62
+ stain.mask(mask)
63
+ stain.threshold(threshold)
64
+ morphology_filters = [pdnl_sana.filter.MorphologyFilter(**x) \
65
+ for x in morphology_filters]
66
+ for filt in morphology_filters:
67
+ stain.apply_morphology_filter(filt)
68
+
69
+ # TODO: don't write anything out if output_path=None
70
+ if debug_level in ['debug', 'full']:
71
+ frame.save(os.path.join(out_d, 'frame.png'))
72
+ processor.bckg.save(os.path.join(out_d, 'bckg.png'))
73
+
74
+ if debug_level == 'full':
75
+ plt.show()
76
+ stain.save(os.path.join(out_d, 'pos.png'))
77
+ mask.save(os.path.join(out_d, 'mask.png'))
78
+ for subroi_name in subroi_masks:
79
+ subroi_masks[subroi_name].save(os.path.join(out_d, f'submask_{subroi_name}.png'))
80
+ logger.data['triangular_strictness'] = triangular_strictness
81
+ logger.data['minimum_threshold'] = minimum_threshold
82
+ logger.data['morphology_filter'] = morphology_filters
83
+ logger.data['threshold'] = threshold
84
+ logger.data['frame_loc'] = frame_loc
85
+ logger.write_data()
86
+
87
+ return frame, stain, logger
88
+
89
+ def main():
90
+
91
+ parser = argparse.ArgumentParser()
92
+ parser.add_argument('-i', '--input_path', help="path to image data to process", required=True)
93
+ parser.add_argument('-o', '--output_path', help="path to write outputs to", required=True)
94
+ parser.add_argument('-s', '--staining_code', help="stain protocol used to stain the input image", default='H-DAB')
95
+ parser.add_argument('-p', '--parameters_file', help=".json file containing processing parameters", default=None)
96
+ parser.add_argument('--debug_level', help="outputs extra files", default='normal')
97
+ args = parser.parse_args()
98
+
99
+ if args.parameters_file:
100
+ params = json.load(open(args.parameters_file))
101
+ else:
102
+ params = {}
103
+
104
+ os.makedirs(args.output_path, exist_ok=True)
105
+
106
+ # get the background image
107
+ # TODO: test how big the concatenated frame will be, and move to big roi mode if too big
108
+ rois = pdnl_sana.slide.concatenate_chunks(args.input_path)
109
+ for roi_name in rois:
110
+ frame, mask, subroi_masks, frame_loc = rois[roi_name]
111
+
112
+ process_roi(frame, mask, subroi_masks, frame_loc, roi_name, args.output_path,
113
+ apply_smoothing=params.get('apply_smoothing', False),
114
+ normalize_background=params.get('normalize_background', False),
115
+ triangular_strictness=params.get('triangular_strictness', 0.0),
116
+ minimum_threshold=params.get('minimum_threshold', 0),
117
+ morphology_filters=[pdnl_sana.filter.MorphologyFilter(**x) for x in params.get('morphology_filters')],
118
+ staining_code=args.staining_code,
119
+ stain_vector=params.get('stain_vector', None),
120
+ debug_level=args.debug_level,
121
+ )
122
+
123
+ if __name__ == "__main__":
124
+ main()
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pdnl_process"
7
- version = "0.6"
7
+ version = "0.7"
8
8
  authors = [
9
9
  { name="Noah Capp", email="noahmcapp@gmail.com" },
10
10
  ]
@@ -1 +0,0 @@
1
- from .main import main
@@ -1,103 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
- import os
4
- import sys
5
- import argparse
6
- import json
7
-
8
- import numpy as np
9
- from tqdm import tqdm
10
- import pdnl_sana.geo
11
- import pdnl_sana.image
12
- import pdnl_sana.process
13
- import pdnl_sana.logging
14
- import pdnl_sana.filter
15
- import pdnl_sana.threshold
16
-
17
- from matplotlib import pyplot as plt
18
-
19
- def main():
20
-
21
- parser = argparse.ArgumentParser()
22
- parser.add_argument('-i', '--input_path', help="path to image data to process", required=True)
23
- parser.add_argument('-o', '--output_path', help="path to write outputs to", required=True)
24
- parser.add_argument('-s', '--staining_code', help="stain protocol used to stain the input image", default='H-DAB')
25
- parser.add_argument('-p', '--parameters_file', help=".json file containing processing parameters", default=None)
26
- parser.add_argument('--debug_level', help="outputs extra files", default='normal')
27
- args = parser.parse_args()
28
-
29
- if args.parameters_file:
30
- params = json.load(open(args.parameters_file))
31
- else:
32
- params = {}
33
-
34
- os.makedirs(args.output_path, exist_ok=True)
35
-
36
- # get the background image
37
- # TODO: test how big the concatenated frame will be, and move to big roi mode if too big
38
- rois = pdnl_sana.slide.concatenate_chunks(args.input_path)
39
- for roi_name in rois:
40
- frame, mask, frame_loc = rois[roi_name]
41
-
42
- # TODO: move all pdnl_sana.process code into here, then other scripts import these functions
43
- out_d = os.path.join(args.output_path, roi_name)
44
- os.makedirs(out_d, exist_ok=True)
45
- logger = pdnl_sana.logging.Logger(args.debug_level, os.path.join(out_d, 'log.pkl'))
46
-
47
- # TODO: shouldn't be omitting the mask here, but leaving it here so all data is generated in the same way for now.
48
- # this was a fix for the background code, but that code is solved now
49
- if args.staining_code == 'H-DAB':
50
- processor = pdnl_sana.process.HDABProcessor(
51
- logger, frame,
52
- #main_mask=mask,
53
- apply_smoothing=params.get('apply_smoothing', False),
54
- normalize_background=params.get('normalize_background', False),
55
- stain_vector=params.get('stain_vector', None),
56
- radius=200, overlap=0.5,
57
- )
58
- if args.staining_code == 'CV-DAB':
59
- processor = pdnl_sana.process.CVDABProcessor(
60
- logger, frame,
61
- #main_mask=mask,
62
- apply_smoothing=params.get('apply_smoothing', False),
63
- normalize_background=params.get('normalize_background', False),
64
- stain_vector=params.get('stain_vector', None)
65
- )
66
- hist = processor.dab.get_histogram(mask=processor.main_mask)
67
- stain = processor.dab.copy()
68
- stain.save(os.path.join(out_d, 'stain.npy'))
69
-
70
- # calculate the threshold
71
- triangular_strictness = params.get('triangular_strictness', 0.0)
72
- threshold = pdnl_sana.threshold.triangular_method(
73
- hist,
74
- strictness=triangular_strictness,
75
- )
76
-
77
- minimum_threshold = params.get('minimum_threshold', 0)
78
- if threshold < minimum_threshold:
79
- threshold = minimum_threshold
80
-
81
- stain.mask(mask)
82
- stain.threshold(threshold)
83
- morphology_filters = [pdnl_sana.filter.MorphologyFilter(**x) \
84
- for x in params.get('morphology_filters', [])]
85
- for filt in morphology_filters:
86
- stain.apply_morphology_filter(filt)
87
-
88
- if args.debug_level in ['debug', 'full']:
89
- frame.save(os.path.join(out_d, 'frame.png'))
90
-
91
- if args.debug_level == 'full':
92
- plt.show()
93
- stain.save(os.path.join(out_d, 'pos.png'))
94
- mask.save(os.path.join(out_d, 'mask.png'))
95
- logger.data['triangular_strictness'] = triangular_strictness
96
- logger.data['minimum_threshold'] = minimum_threshold
97
- logger.data['morphology_filter'] = morphology_filters
98
- logger.data['threshold'] = threshold
99
- logger.data['frame_loc'] = frame_loc
100
- logger.write_data()
101
-
102
- if __name__ == "__main__":
103
- main()
File without changes
File without changes