Skip to content

Commit da38626

Browse files
committed
Integrated custom output resolution
Default behaviour was to save the stitched end result on maximum resolution. This commit provides the user with the ability to specify the resolution (µm/pixel) at which the final result should be saved. Writing speed of the final result has also greatly improved by more efficiently computing the final transformations.
1 parent 454f8a5 commit da38626

File tree

5 files changed

+346
-326
lines changed

5 files changed

+346
-326
lines changed

src/assembly_utils/jigsawnet.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ def SingleTest(checkpoint_root, K, net, is_training=False):
214214
sess_init_op = tf.group(tf.compat.v1.global_variables_initializer(),
215215
tf.compat.v1.local_variables_initializer())
216216
sess.run(sess_init_op)
217-
saver.restore(sess, tf.train.latest_checkpoint(f"./{check_point}"))
217+
saver.restore(sess, tf.train.latest_checkpoint(check_point))
218218
sessions.append(sess)
219219

220220
# Inference on JigsawNet. Note how this is only performed with batch_size=1. Perhaps

src/main.py

+49-30
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,43 @@
1-
import os
2-
os.environ["VIPS_CONCURRENCY"] = "20"
31
import argparse
4-
import logging
52
import json
3+
import logging
4+
import os
65
import pathlib
76

8-
from preprocessing_utils.prepare_data import prepare_data
97
from assembly_utils.detect_configuration import detect_configuration
10-
from pythostitcher_utils.preprocess import preprocess
11-
from pythostitcher_utils.optimize_stitch import optimize_stitch
8+
from preprocessing_utils.prepare_data import prepare_data
129
from pythostitcher_utils.fragment_class import Fragment
13-
from pythostitcher_utils.get_resname import get_resname
1410
from pythostitcher_utils.full_resolution import generate_full_res
11+
from pythostitcher_utils.get_resname import get_resname
12+
from pythostitcher_utils.optimize_stitch import optimize_stitch
13+
from pythostitcher_utils.preprocess import preprocess
14+
15+
os.environ["VIPS_CONCURRENCY"] = "20"
1516

1617

17-
def load_parameter_configuration(data_dir, save_dir, patient_idx):
18+
def load_parameter_configuration(data_dir, save_dir, output_res):
1819
"""
1920
Convenience function to load all the PythoStitcher parameters and pack them up
2021
in a dictionary for later use.
2122
"""
2223

2324
# Verify its existence
24-
config_file = pathlib.Path("./config/parameter_config.json")
25+
config_file = pathlib.Path().absolute().parent.joinpath("config/parameter_config.json")
2526
assert config_file.exists(), "parameter config file not found"
2627

2728
# Load main parameter config
2829
with open(config_file) as f:
2930
parameters = json.load(f)
3031

32+
# Convert model weight paths to absolute paths
33+
parameters["weights_fragment_classifier"] = pathlib.Path().absolute().parent.joinpath(parameters["weights_fragment_classifier"])
34+
parameters["weights_jigsawnet"] = pathlib.Path().absolute().parent.joinpath(parameters["weights_jigsawnet"])
35+
3136
# Insert parsed arguments
3237
parameters["data_dir"] = data_dir
3338
parameters["save_dir"] = save_dir
34-
parameters["patient_idx"] = patient_idx
39+
parameters["patient_idx"] = data_dir.name
40+
parameters["output_res"] = output_res
3541
parameters["fragment_names"] = [i.name for i in data_dir.joinpath("raw_images").iterdir() if i.is_dir()]
3642
parameters["n_fragments"] = len(parameters["fragment_names"])
3743
parameters["resolution_scaling"] = [i/parameters["resolutions"][0] for i in parameters["resolutions"]]
@@ -69,32 +75,43 @@ def collect_arguments():
6975
description="Stitch prostate histopathology images into a pseudo whole-mount image"
7076
)
7177
parser.add_argument(
72-
"--datadir", required=True, help="General data directory with all patients"
78+
"--datadir",
79+
required=True,
80+
type=pathlib.Path,
81+
help="Path to the case to stitch"
7382
)
7483
parser.add_argument(
75-
"--savedir", required=True, help="Directory to save the results"
84+
"--savedir",
85+
required=True,
86+
type=pathlib.Path,
87+
help="Directory to save the results"
7688
)
7789
parser.add_argument(
78-
"--patient", required=True, help="Patient to process"
90+
"--resolution",
91+
required=True,
92+
default=0.25,
93+
type=float,
94+
help="Output resolution (µm/pixel) of the reconstructed image. Should be roughly "
95+
"in range of 0.25-20."
7996
)
8097
args = parser.parse_args()
8198

8299
# Extract arguments
83-
patient_idx = args.patient
84-
data_dir = pathlib.Path(args.datadir).joinpath(patient_idx)
85-
save_dir = pathlib.Path(args.savedir).joinpath(patient_idx)
100+
data_dir = pathlib.Path(args.datadir)
101+
save_dir = pathlib.Path(args.savedir).joinpath(data_dir.name)
102+
resolution = args.resolution
86103

87-
assert pathlib.Path(args.datadir).is_dir(), "provided data directory doesn't exist"
88-
assert data_dir.is_dir(), "provided patient could not be found in data directory"
104+
assert data_dir.is_dir(), "provided patient directory doesn't exist"
89105
assert data_dir.joinpath("raw_images").is_dir(), "patient has no 'raw_images' directory"
90106
assert len(list(data_dir.joinpath("raw_images").iterdir())) > 0, "no images found in 'raw_images' directory"
107+
assert resolution > 0, "output resolution cannot be negative"
91108

92109
print(f"\nRunning job with following parameters:"
93-
f"\n - Data dir: {args.datadir}"
110+
f"\n - Data dir: {data_dir}"
94111
f"\n - Save dir: {save_dir}"
95-
f"\n - Patient: {patient_idx}")
112+
f"\n - Output resolution: {resolution} µm/pixel\n")
96113

97-
return data_dir, save_dir, patient_idx
114+
return data_dir, save_dir, resolution
98115

99116

100117
def main():
@@ -115,7 +132,7 @@ def main():
115132
/data
116133
/{Patient_identifier}
117134
/raw_images
118-
{fragment_name}.mrxs
135+
{fragment_name}.mrxs§
119136
{fragment_name}.mrxs
120137
/raw_masks
121138
{fragment_name}.tif
@@ -126,8 +143,8 @@ def main():
126143

127144
### ARGUMENT CONFIGURATION ###
128145
# Collect arguments
129-
data_dir, save_dir, patient_idx = collect_arguments()
130-
parameters = load_parameter_configuration(data_dir, save_dir, patient_idx)
146+
data_dir, save_dir, output_res = collect_arguments()
147+
parameters = load_parameter_configuration(data_dir, save_dir, output_res)
131148

132149
# Initiate logging file
133150
logfile = save_dir.joinpath("pythostitcher_log.log")
@@ -144,9 +161,10 @@ def main():
144161
log = logging.getLogger("pythostitcher")
145162

146163
parameters["log"] = log
147-
parameters["log"].log(parameters["my_level"], f"Running job with following parameters:"
148-
f"\n - Data dir: {parameters['data_dir']}"
149-
f"\n - Save dir: {parameters['save_dir']}\n")
164+
parameters["log"].log(parameters["my_level"], f"Running job with following parameters:")
165+
parameters["log"].log(parameters["my_level"], f" - Data dir: {parameters['data_dir']}")
166+
parameters["log"].log(parameters["my_level"], f" - Save dir: {parameters['save_dir']}")
167+
parameters["log"].log(parameters["my_level"], f" - Output resolution: {parameters['output_res']}\n")
150168

151169
if not data_dir.joinpath("raw_masks").is_dir():
152170
parameters["log"].log(
@@ -155,7 +173,8 @@ def main():
155173
f"PythoStitcher with pregenerated tissuemasks, please put these files in "
156174
f"[{data_dir.joinpath('raw_masks')}]. If no tissuemasks are supplied, "
157175
f"PythoStitcher will use a generic tissue segmentation which may not perform "
158-
f"as well as the AI-generated masks.")
176+
f"as well as the AI-generated masks. In addition, PythoStitcher will not "
177+
f"be able to generate the full resolution end result.")
159178

160179
### MAIN PYTHOSTITCHER #s##
161180
# Preprocess data
@@ -182,7 +201,7 @@ def main():
182201
fragments = []
183202
for im_path, fragment_name in sol.items():
184203
fragments.append(Fragment(
185-
im_path = im_path,
204+
im_path=im_path,
186205
fragment_name=fragment_name,
187206
kwargs=parameters)
188207
)
@@ -198,7 +217,7 @@ def main():
198217

199218
parameters["log"].log(
200219
parameters["my_level"],
201-
f"Succesfully stitched solution {count_sol}"
220+
f"### Succesfully stitched solution {count_sol} ###\n"
202221
)
203222

204223
return

0 commit comments

Comments
 (0)