Skip to content

Commit 5d2a188

Browse files
Merge pull request #1043 from annie-xd-wang/update-features-optimize-volume-search3D
Update features: optimize volume search 3d
2 parents de3f893 + 49f2611 commit 5d2a188

File tree

3 files changed

+106
-7
lines changed

3 files changed

+106
-7
lines changed

src/navigate/model/analysis/boundary_detect.py

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,9 +524,11 @@ def map_labels(
524524
The maximum number of z steps
525525
positions : array
526526
Array of positions
527+
target_labels : array
528+
Array of target label index.
527529
"""
528530
if target_pixel_size >= current_pixel_size:
529-
return 1, [position]
531+
return 1, [position], [0]
530532
if overlap < 0:
531533
overlap = 0
532534
if x_direction not in ["x", "-x", "y", "-y"]:
@@ -555,6 +557,12 @@ def map_labels(
555557
regionprops = measure.regionprops(labeled_image)
556558
z_range = 1
557559

560+
target_labels_index = []
561+
start = -1
562+
end = -1
563+
start_weight = current_image_width + current_image_height
564+
end_weight = 0
565+
558566
for i in range(target_num):
559567
min_z, min_y, min_x, max_z, max_y, max_x = regionprops[i].bbox
560568

@@ -565,6 +573,53 @@ def map_labels(
565573
) < filter_pixel_number:
566574
continue
567575

576+
target_labels_index.append(i)
577+
# find the start and end position
578+
centroid_z, centroid_y, centroid_x = regionprops[i].centroid
579+
if start < 0:
580+
start = len(target_labels_index) - 1
581+
start_weight = centroid_x + centroid_y
582+
elif centroid_x + centroid_y < start_weight:
583+
if end_weight < start_weight:
584+
end = start
585+
end_weight = start_weight
586+
start = len(target_labels_index) - 1
587+
start_weight = centroid_x + centroid_y
588+
elif centroid_x + centroid_y > end_weight:
589+
end = len(target_labels_index) - 1
590+
end_weight = centroid_x + centroid_y
591+
592+
# build a graph
593+
weight_graph = [[0 for i in range(len(target_labels_index))] for _ in range(len(target_labels_index))]
594+
for i in range(len(target_labels_index)):
595+
centroid_z_i, centroid_y_i, centroid_x_i = regionprops[target_labels_index[i]].centroid
596+
for j in range(len(target_labels_index)):
597+
if i == j:
598+
weight_graph[j][i] = weight_graph[i][j] = current_image_width + current_image_height
599+
continue
600+
centroid_z_j, centroid_y_j, centroid_x_j = regionprops[target_labels_index[j]].centroid
601+
weight_graph[i][j] = abs(centroid_x_i - centroid_x_j) + abs(centroid_y_i - centroid_y_j)
602+
weight_graph[j][i] = weight_graph[i][j]
603+
# find the appoximation shortest path in (x, y).
604+
visited_num = 1
605+
target_labels = [target_labels_index[start]]
606+
pre = start
607+
visited = [False] * len(target_labels_index)
608+
visited[start] = True
609+
while visited_num < len(target_labels_index):
610+
while True:
611+
idx = weight_graph[pre].index(min(weight_graph[pre]))
612+
weight_graph[pre][idx] = weight_graph[idx][pre] = current_image_width + current_image_height
613+
if not visited[idx]:
614+
break
615+
target_labels.append(target_labels_index[idx])
616+
pre = idx
617+
visited[idx] = True
618+
visited_num += 1
619+
620+
for i in target_labels:
621+
min_z, min_y, min_x, max_z, max_y, max_x = regionprops[i].bbox
622+
568623
num_x = math.ceil((max_x - min_x) / (x_pixel * (1 - overlap)))
569624
shift_x = (num_x * x_pixel - (max_x - min_x)) // 2
570625

@@ -615,4 +670,4 @@ def map_labels(
615670
for x_pos, y_pos in product(x_positions, y_positions)
616671
]
617672

618-
return z_range, position_table
673+
return z_range, position_table, target_labels

src/navigate/model/features/volume_search.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,20 @@
3131
#
3232

3333
from queue import Queue
34+
import numpy as np
35+
from tifffile import imwrite
36+
from os import path
37+
3438
from navigate.model.analysis.boundary_detect import (
3539
find_tissue_boundary_2d,
3640
binary_detect,
3741
map_boundary,
3842
find_cell_boundary_3d,
3943
map_labels,
4044
)
41-
import numpy as np
42-
from tifffile import imwrite
43-
from os import path
45+
from navigate.tools.multipos_table_tools import(
46+
write_to_csv_file
47+
)
4448

4549

4650
def draw_box(img, xl, yl, xu, yu, fill=65535):
@@ -579,7 +583,7 @@ def data_func(self, frame_ids):
579583
z_end = microscope_state_config["end_position"]
580584
z_step = microscope_state_config["step_size"]
581585

582-
if microscope_state_config["multiposition_count"] == 0:
586+
if len(self.model.configuration["multi_positions"]) == 0:
583587
pos_dict = self.model.get_stage_position()
584588
position = [
585589
pos_dict[f"{axis}_pos"] for axis in ["x", "y", "z", "theta", "f"]
@@ -648,7 +652,7 @@ def data_func(self, frame_ids):
648652
"CameraParameters"
649653
][self.target_resolution]["img_y_pixels"]
650654

651-
z_range, positions = map_labels(
655+
z_range, positions, target_labels = map_labels(
652656
labeled_image,
653657
position,
654658
z_start,
@@ -665,6 +669,20 @@ def data_func(self, frame_ids):
665669
filter_pixel_number=self.filter_pixel_number,
666670
)
667671

672+
# save positions
673+
write_to_csv_file(positions, path.join(
674+
self.model.configuration["experiment"]["Saving"]["save_directory"],
675+
"positions.csv",
676+
),)
677+
# save target label index sequences
678+
target_labels_file = path.join(
679+
self.model.configuration["experiment"]["Saving"]["save_directory"],
680+
"target_labels.txt"
681+
)
682+
with open(target_labels_file, "w") as f:
683+
for idx in target_labels:
684+
f.write(f"{idx}\n")
685+
668686
self.model.event_queue.put(("multiposition", positions))
669687
self.model.configuration["multi_positions"] = positions
670688
if len(positions) > 0:

src/navigate/tools/multipos_table_tools.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
# Standard library imports
3333
from math import ceil
34+
import csv
3435

3536
# Third party imports
3637
import numpy as np
@@ -245,3 +246,28 @@ def update_table(table, pos, append=False):
245246
table.resetColors()
246247
table.redraw()
247248
table.tableChanged()
249+
250+
def write_to_csv_file(positions, file_path):
251+
"""Write positions to a csv file.
252+
253+
Parameters
254+
----------
255+
pos: list or np.array
256+
A list of positions.
257+
file_path: str
258+
The target csv file path.
259+
Returns
260+
-------
261+
result: bool
262+
Whether positions are saved successfully.
263+
"""
264+
try:
265+
with open(file_path, "w", newline="") as f:
266+
writer = csv.writer(f)
267+
writer.writerow(["X", "Y", "Z", "R", "F"])
268+
269+
for p in positions:
270+
writer.writerow(p)
271+
return True
272+
except FileNotFoundError:
273+
return False

0 commit comments

Comments
 (0)