Skip to content

Commit d173cc5

Browse files
authored
Script to merge volume tracing into on-disk segmentation (#3431)
* [WIP] script to merge volume tracing into on-disk segmentation * group by segmentation files, overwrite the necessary files * implement pr feedback
1 parent 961f9bd commit d173cc5

File tree

3 files changed

+131
-0
lines changed

3 files changed

+131
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.zip
2+
tmp-*
+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#!/usr/bin/env python3
2+
3+
from argparse import ArgumentParser
4+
import zipfile
5+
import shutil
6+
import os
7+
import sys
8+
import random
9+
import string
10+
import wkw
11+
import numpy as np
12+
import re
13+
from operator import add
14+
15+
def main():
16+
args = create_parser().parse_args()
17+
confirmation_prompt(args)
18+
tracing_tmpdir_path = extract_tracing_zip(args)
19+
20+
tracing_dataset = wkw.Dataset.open(os.path.join(tracing_tmpdir_path, '1'))
21+
segmentation_dataset = wkw.Dataset.open(os.path.join(args.segmentation_path, '1'))
22+
23+
assert(tracing_dataset.header.num_channels == segmentation_dataset.header.num_channels)
24+
assert(tracing_dataset.header.voxel_type == segmentation_dataset.header.voxel_type)
25+
26+
tracing_bboxes = file_bboxes(tracing_dataset)
27+
segmentation_bboxes = file_bboxes(segmentation_dataset)
28+
29+
bboxes_grouped = group_tracing_bboxes(tracing_bboxes, segmentation_bboxes)
30+
31+
print("Found {} tracing files, which will affect {} segmentation files".format(len(tracing_bboxes), len(bboxes_grouped)))
32+
33+
segmentation_file_len_voxels = segmentation_dataset.header.block_len * segmentation_dataset.header.file_len
34+
35+
for counter, bbox_group_key in enumerate(bboxes_grouped):
36+
segmentation_bbox = bboxes_grouped[bbox_group_key][0]
37+
tracing_bboxes = bboxes_grouped[bbox_group_key][1]
38+
39+
print("Reading segmentation file {} of {}, bounding box: {}...".format(counter+1, len(bboxes_grouped), segmentation_bbox))
40+
data = segmentation_dataset.read(segmentation_bbox[0], segmentation_bbox[1])
41+
42+
print(" Overwriting tracing buckets in memory...")
43+
for tracing_bbox in tracing_bboxes:
44+
print(" Overwriting", tracing_bbox)
45+
tracing_data = tracing_dataset.read(tracing_bbox[0], tracing_bbox[1])
46+
topleft = list(map(lambda x: x % segmentation_file_len_voxels, tracing_bbox[0]))
47+
shape = tracing_bbox[1]
48+
bottomright = list( map(add, topleft, shape) )
49+
data[0:1, topleft[0]:bottomright[0], topleft[1]:bottomright[1], topleft[2]:bottomright[2]] = tracing_data
50+
51+
print(" Writing segmentation file back to disk...")
52+
segmentation_dataset.write([0, 0, 0], data)
53+
print("Cleaning up temporary files...")
54+
shutil.rmtree(tracing_tmpdir_path)
55+
print("Done.")
56+
57+
def confirmation_prompt(args):
58+
if not args.yes:
59+
answer = input("Are you sure you want to modify the data in {}? This cannot be undone. To continue, type “yes”: ".format(args.segmentation_path))
60+
if answer != "yes":
61+
print("Aborting")
62+
sys.exit(0)
63+
64+
def extract_tracing_zip(args):
65+
tracing_tmpdir_path = tmp_filename()
66+
os.makedirs(tracing_tmpdir_path)
67+
with zipfile.ZipFile(args.tracing_path) as outer_zip:
68+
if 'data.zip' in outer_zip.namelist():
69+
outfile_path = os.path.join(tracing_tmpdir_path, 'data.zip')
70+
with outer_zip.open('data.zip') as data_zip, open(outfile_path, 'wb') as outfile:
71+
shutil.copyfileobj(data_zip, outfile)
72+
extract_data_zip(outfile_path, tracing_tmpdir_path)
73+
os.remove(outfile_path)
74+
else:
75+
extract_data_zip(args.tracing_path)
76+
return tracing_tmpdir_path
77+
78+
def extract_data_zip(path, tracing_tmpdir_path):
79+
with zipfile.ZipFile(path) as file:
80+
zipfile.ZipFile.extractall(file, path=tracing_tmpdir_path)
81+
82+
def group_tracing_bboxes(tracing_bboxes, segmentation_bboxes):
83+
grouped = {}
84+
for tracing_bbox in tracing_bboxes:
85+
segmentation_bbox = matching_segmentation_bbox(segmentation_bboxes, tracing_bbox)
86+
if not str(segmentation_bbox) in grouped:
87+
grouped[str(segmentation_bbox)] = (segmentation_bbox, [])
88+
grouped[str(segmentation_bbox)][1].append(tracing_bbox)
89+
return grouped
90+
91+
def matching_segmentation_bbox(segmentation_bboxes, tracing_bbox):
92+
for segmentation_bbox in segmentation_bboxes:
93+
if (segmentation_bbox[0][0] <= tracing_bbox[0][0]
94+
and segmentation_bbox[0][1] <= tracing_bbox[0][1]
95+
and segmentation_bbox[0][2] <= tracing_bbox[0][2]
96+
and segmentation_bbox[1][0] >= tracing_bbox[1][0]
97+
and segmentation_bbox[1][1] >= tracing_bbox[1][1]
98+
and segmentation_bbox[1][2] >= tracing_bbox[1][2]):
99+
return segmentation_bbox
100+
print("Error: tracing extends outside of segmentation data. Stopping, no data was modified.")
101+
sys.exit(1)
102+
103+
def file_bboxes(dataset):
104+
file_len_voxels = dataset.header.block_len * dataset.header.file_len
105+
p = re.compile('(.*)/z([0-9]+)/y([0-9]+)/x([0-9]+).wkw')
106+
bboxes = []
107+
for file in dataset.list_files():
108+
m = p.match(file)
109+
file_coords = [m.group(4), m.group(3), m.group(2)]
110+
offset = [int(x) * file_len_voxels for x in file_coords]
111+
shape = [file_len_voxels, file_len_voxels, file_len_voxels]
112+
bboxes.append((offset, shape))
113+
return bboxes
114+
115+
def create_parser():
116+
parser = ArgumentParser()
117+
parser.add_argument('tracing_path', help='Volume tracing zip file')
118+
parser.add_argument('segmentation_path', help='Directory containing the segmentation to overwrite. (Path should not include zoom level)')
119+
parser.add_argument('-y', '--yes', action="store_true", help='Skip the confirmation prompt')
120+
return parser
121+
122+
def tmp_filename():
123+
return 'tmp-' + ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(10))
124+
125+
if __name__ == '__main__':
126+
main()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
wkw
2+
argparse
3+
numpy

0 commit comments

Comments
 (0)