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.
- {pdnl_process-0.6 → pdnl_process-0.7}/PKG-INFO +1 -1
- pdnl_process-0.7/pdnl_process/__init__.py +1 -0
- pdnl_process-0.7/pdnl_process/main.py +124 -0
- {pdnl_process-0.6 → pdnl_process-0.7}/pyproject.toml +1 -1
- pdnl_process-0.6/pdnl_process/__init__.py +0 -1
- pdnl_process-0.6/pdnl_process/main.py +0 -103
- {pdnl_process-0.6 → pdnl_process-0.7}/.github/workflows/publish.yml +0 -0
- {pdnl_process-0.6 → pdnl_process-0.7}/.gitignore +0 -0
- {pdnl_process-0.6 → pdnl_process-0.7}/README.md +0 -0
|
@@ -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()
|
|
@@ -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
|
|
File without changes
|