Skip to content

Commit

Permalink
Merge pull request #41 from OmooLab/feature/dev
Browse files Browse the repository at this point in the history
Feature/dev
  • Loading branch information
icrdr authored Sep 4, 2024
2 parents 21e0b85 + 655b19b commit 7c71417
Show file tree
Hide file tree
Showing 32 changed files with 2,590 additions and 1,382 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,6 @@ blendcache_*

.secrets

.vdb

!scipy_ndimage/*/**
9 changes: 8 additions & 1 deletion bioxelnodes/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import bpy

from .props import BIOXELNODES_LayerListUL
from . import auto_load
from . import menus

Expand All @@ -9,11 +10,17 @@

def register():
auto_load.register()
bpy.types.WindowManager.bioxelnodes_progress_factor = bpy.props.FloatProperty()
bpy.types.WindowManager.bioxelnodes_progress_factor = bpy.props.FloatProperty(
default=1.0)
bpy.types.WindowManager.bioxelnodes_progress_text = bpy.props.StringProperty()
bpy.types.WindowManager.bioxelnodes_layer_list_UL = bpy.props.PointerProperty(
type=BIOXELNODES_LayerListUL)
menus.add()


def unregister():
menus.remove()
del bpy.types.WindowManager.bioxelnodes_progress_factor
del bpy.types.WindowManager.bioxelnodes_progress_text
del bpy.types.WindowManager.bioxelnodes_layer_list_UL
auto_load.unregister()
3 changes: 3 additions & 0 deletions bioxelnodes/assets/Nodes/BioxelNodes_v0.1.x.blend
Git LFS file not shown
3 changes: 3 additions & 0 deletions bioxelnodes/assets/Nodes/BioxelNodes_v0.2.x.blend
Git LFS file not shown
3 changes: 3 additions & 0 deletions bioxelnodes/assets/Nodes/BioxelNodes_v1.0.x.blend
Git LFS file not shown
49 changes: 31 additions & 18 deletions bioxelnodes/bioxel/layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@
import numpy as np

from . import scipy
from . import skimage as ski
from . import scipy as ndi

# 3rd-party
import transforms3d

# TODO: turn to dataclasses


Expand Down Expand Up @@ -71,23 +69,27 @@ def max(self):
def copy(self):
return copy.deepcopy(self)

def fill(self, value: float, mask: np.ndarray):
def fill(self, value: float, mask: np.ndarray, smooth: int = 0):
mask_frames = ()
if mask.ndim == 4:
if mask.shape[0] != self.frame_count:
raise Exception("Mask frame count is not same as ")
for f in range(self.frame_count):
mask_frame = mask[f, :, :, :]
mask_frame = scipy.minimum_filter(
mask_frame.astype(np.float32), size=3)
if smooth > 0:
mask_frame = scipy.minimum_filter(mask_frame.astype(np.float32),
mode="nearest",
size=smooth)
# mask_frame = scipy.median_filter(
# mask_frame.astype(np.float32), size=2)
mask_frames += (mask_frame,)
elif mask.ndim == 3:
for f in range(self.frame_count):
mask_frame = mask[:, :, :]
mask_frame = scipy.minimum_filter(
mask_frame.astype(np.float32), size=3)
if smooth > 0:
mask_frame = scipy.minimum_filter(mask_frame.astype(np.float32),
mode="nearest",
size=smooth)
# mask_frame = scipy.median_filter(
# mask_frame.astype(np.float32), size=2)
mask_frames += (mask_frame,)
Expand All @@ -98,20 +100,19 @@ def fill(self, value: float, mask: np.ndarray):
_mask = np.expand_dims(_mask, axis=-1)
self.data = _mask * value + (1-_mask) * self.data

def resize(self, shape: tuple, progress_callback=None):
def resize(self, shape: tuple, smooth: int = 0, progress_callback=None):
if len(shape) != 3:
raise Exception("Shape must be 3 dim")

data = self.data
order = 0 if self.dtype == bool else 1

# TXYZC > TXYZ
if self.kind in ['label', 'scalar']:
data = np.amax(data, -1)
# # TXYZC > TXYZ
# if self.kind in ['label', 'scalar']:
# data = np.amax(data, -1)

# if self.kind in ['scalar']:
# dtype = data.dtype
# data = data.astype(np.float32)
# data = data.astype(np.float32)

data_frames = ()
for f in range(self.frame_count):
Expand All @@ -122,13 +123,22 @@ def resize(self, shape: tuple, progress_callback=None):
# shape,
# preserve_range=True,
# anti_aliasing=data.dtype.kind != "b")
frame = data[f, :, :, :, :]
if smooth > 0:
frame = scipy.median_filter(frame.astype(np.float32),
mode="nearest",
size=smooth)

factors = np.divide(self.shape, shape)
zoom_factors = [1 / f for f in factors]
frame = ndi.zoom(data[f, :, :, :],
zoom_factors,
order = 0 if frame.dtype == bool else 1
frame = ndi.zoom(frame,
zoom_factors+[1.0],
mode="nearest",
grid_mode=False,
order=order)

if smooth > 0:
frame = frame.astype(self.dtype)
data_frames += (frame,)

data = np.stack(data_frames)
Expand All @@ -137,7 +147,10 @@ def resize(self, shape: tuple, progress_callback=None):
# data = data.astype(dtype)

# TXYZ > TXYZC
if self.kind in ['label', 'scalar']:
data = np.expand_dims(data, axis=-1) # expend channel
# if self.kind in ['label', 'scalar']:
# data = np.expand_dims(data, axis=-1) # expend channel

self.data = data

mat_scale = transforms3d.zooms.zfdir2aff(factors[0])
self.affine = np.dot(self.affine, mat_scale)
87 changes: 64 additions & 23 deletions bioxelnodes/bioxel/parse.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from pathlib import Path
import numpy as np
from .layer import Layer

# 3rd-party
import SimpleITK as sitk
Expand Down Expand Up @@ -42,7 +41,8 @@
SEQUENCE_EXTS = ['.bmp', '.BMP',
'.jpg', '.JPG', '.jpeg', '.JPEG',
'.tif', '.TIF', '.tiff', '.TIFF',
'.png', '.PNG']
'.png', '.PNG',
'.mrc']


def get_ext(filepath: Path) -> str:
Expand All @@ -64,18 +64,40 @@ def get_ext(filepath: Path) -> str:
return filepath.suffix


def get_file_name(filepath: Path):
def get_filename(filepath: Path):
ext = get_ext(filepath)
return filepath.name.removesuffix(ext).replace(" ", "-")
return filepath.name.removesuffix(ext)


def get_file_number(filepath: Path) -> str:
name = get_file_name(filepath)
def get_filename_parts(filepath: Path) -> str:
def has_digits(s):
return any(char.isdigit() for char in s)

name = get_filename(filepath)
parts = name.replace(".", " ").replace("_", " ").split(" ")
skip_prefixs = ["CH", "ch", "channel"]
number_part = None
number_part_i = None

for i, part in enumerate(parts[::-1]):
if has_digits(part):
if not any([part.startswith(prefix) for prefix in skip_prefixs]):
number_part = part
number_part_i = len(parts)-i
break

if number_part is None:
return name, "", ""

prefix_parts = parts[:number_part_i-1]
prefix_parts_count = sum([len(part)+1 for part in prefix_parts])

digits = ""
suffix = ""

# Iterate through the characters in reverse order
started = False
for char in name[::-1]:
for char in number_part[::-1]:
if char.isdigit():
started = True
# If the character is a digit, add it to the digits string
Expand All @@ -84,29 +106,42 @@ def get_file_number(filepath: Path) -> str:
if started:
# If a non-digit character is encountered, stop the loop
break
else:
suffix += char

digits = digits[::-1]

prefix_parts_count += len(number_part) - \
len(digits) - len(suffix)

# Reverse the digits string to get the correct order
return digits[::-1]
prefix = name[:prefix_parts_count]
suffix = name[prefix_parts_count+len(digits):]

return prefix, digits, suffix

def get_sequence_name(filepath: Path) -> str:
name = get_file_name(filepath)
number = get_file_number(filepath)
return name.removesuffix(number)

def get_file_no_digits_name(filepath: Path) -> str:
prefix, digits, suffix = get_filename_parts(filepath)
prefix = remove_end_str(prefix, "_")
prefix = remove_end_str(prefix, ".")
prefix = remove_end_str(prefix, "-")
prefix = remove_end_str(prefix, " ")
return prefix + suffix

def get_sequence_index(filepath: Path) -> int:
number = get_file_number(filepath)
return int(number) if number != "" else 0

def get_file_index(filepath: Path) -> int:
prefix, digits, suffix = get_filename_parts(filepath)
return int(digits) if digits != "" else 0


def collect_sequence(filepath: Path):
file_dict = {}
for f in filepath.parent.iterdir():
if f.is_file() \
and get_ext(filepath) == get_ext(f) \
and get_sequence_name(filepath) == get_sequence_name(f):
index = get_sequence_index(f)
and get_file_no_digits_name(filepath) == get_file_no_digits_name(f):
index = get_file_index(f)
file_dict[index] = f

# reomve isolated seq file
Expand All @@ -124,7 +159,13 @@ def collect_sequence(filepath: Path):
return sequence


def parse_volumetric_data(data_file: str, series_id="", progress_callback=None) -> Layer:
def remove_end_str(string: str, end: str):
while string.endswith(end) and len(string) > 0:
string = string.removesuffix(end)
return string


def parse_volumetric_data(data_file: str, series_id="", progress_callback=None):
"""Parse any volumetric data to numpy with shap (T,X,Y,Z,C)
Args:
Expand All @@ -139,7 +180,7 @@ def parse_volumetric_data(data_file: str, series_id="", progress_callback=None)
ext = get_ext(data_path)

if progress_callback:
progress_callback(0, "Reading the Data...")
progress_callback(0.0, "Reading the Data...")

is_sequence = False
if ext in SEQUENCE_EXTS:
Expand Down Expand Up @@ -181,7 +222,7 @@ def parse_volumetric_data(data_file: str, series_id="", progress_callback=None)
elif mrc.is_volume_stack():
data = np.expand_dims(data, axis=-1) # expend channel

name = get_file_name(data_path)
name = get_file_no_digits_name(data_path)
spacing = (mrc.voxel_size.x,
mrc.voxel_size.y,
mrc.voxel_size.z)
Expand Down Expand Up @@ -245,7 +286,7 @@ def parse_volumetric_data(data_file: str, series_id="", progress_callback=None)
except:
...

name = get_file_name(data_path)
name = get_file_no_digits_name(data_path)
except:
...

Expand Down Expand Up @@ -297,10 +338,10 @@ def get_meta(key):

elif ext in SEQUENCE_EXTS and is_sequence:
itk_image = sitk.ReadImage(sequence)
name = get_sequence_name(data_path)
name = get_file_no_digits_name(data_path)
else:
itk_image = sitk.ReadImage(data_path)
name = get_file_name(data_path)
name = get_filename(data_path)

# for key in itk_image.GetMetaDataKeys():
# print(f"{key},{itk_image.GetMetaData(key)}")
Expand Down
Loading

0 comments on commit 7c71417

Please sign in to comment.