Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/dev #18

Merged
merged 3 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions .github/workflows/upload-assets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
# id: draft_release
# uses: cardinalby/[email protected]
# with:
# releaseName: Draft
# releaseName: Upload
# env:
# GITHUB_TOKEN: ${{ github.token }}

Expand Down Expand Up @@ -70,5 +70,38 @@ jobs:
with:
upload_url: ${{ needs.draft_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: ./package.zip
asset_name: BioxelNodes_${{ needs.draft_release.outputs.version }}.zip
asset_name: BioxelNodes_Addon_${{ needs.draft_release.outputs.version }}.zip
asset_content_type: application/zip

upload_blender_extension:
name: Upload Blender Extension
needs: draft_release
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
lfs: 'true'
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.11
- name: Zip Extension
run: |
pip download SimpleITK --dest bioxelnodes/wheels --only-binary=:all: --python-version=3.11 --platform=macosx_11_0_arm64
pip download SimpleITK --dest bioxelnodes/wheels --only-binary=:all: --python-version=3.11 --platform=win_amd64
rm -r bioxelnodes/externalpackage
cp extension/__init__.py bioxelnodes/__init__.py
cp extension/preferences.py bioxelnodes/preferences.py
cp extension/blender_manifest.toml bioxelnodes/blender_manifest.toml
zip -r package.zip bioxelnodes
- name: Upload Release Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.draft_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: ./package.zip
asset_name: BioxelNodes_Extension_${{ needs.draft_release.outputs.version }}.zip
asset_content_type: application/zip
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Before us, there have been many tutorials and add-ons for importing volumetric d

Below are some examples with Bioxel Nodes. Thanks to Cycles Render, the volumetric data can be rendered with great detail:

![gallery](docs/assets/gallery.png)
![cover](docs/assets/cover.png)

The "Bioxel" in "Bioxel Nodes", is a combination of the words "Bio-" and "Voxel". Bioxel is a voxel that stores biological data. We are developing a toolkit around Bioxel for better biological data visualization. but before its release, we made this Blender version of bioxels toolkit first, in order to let more people to have fun with volumetric data. [Getting Started](https://omoolab.github.io/BioxelNodes/latest/getting-started)

Expand Down
2 changes: 1 addition & 1 deletion bioxelnodes/auto_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def unregister():
#################################################

def get_all_submodules(directory):
return list(iter_submodules(directory, directory.name))
return list(iter_submodules(directory, __package__))


def iter_submodules(path, package_name):
Expand Down
20 changes: 12 additions & 8 deletions bioxelnodes/externalpackage/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ def start_logging(self, logfile_name: str = 'side-packages-install') -> logging.

# Set up logging configuration
logfile_path = Path(self.log_path, f"{logfile_name}.log")
logging.basicConfig(filename=logfile_path, level=logging.INFO)
logging.basicConfig(filename=logfile_path,
level=logging.INFO, encoding='utf-8')

# Return logger object
return logging.getLogger()
Expand Down Expand Up @@ -248,13 +249,16 @@ def run_python(self, cmd_list: list = None, timeout: int = 600):
result = subprocess.run(cmd_list, timeout=timeout,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)

if result.returncode != 0:
log.error('Command failed: %s', cmd_list)
log.error('stdout: %s', result.stdout.decode())
log.error('stderr: %s', result.stderr.decode(errors='ignore'))
else:
log.info('Command succeeded: %s', cmd_list)
log.info('stdout: %s', result.stdout.decode())
try:
if result.returncode != 0:
log.error('Command failed: %s', cmd_list)
log.error('stdout: %s', result.stdout.decode())
log.error('stderr: %s', result.stderr.decode(errors='ignore'))
else:
log.info('Command succeeded: %s', cmd_list)
log.info('stdout: %s', result.stdout.decode())
except:
...
# return the command list, return code, stdout, and stderr as a tuple
return result

Expand Down
198 changes: 1 addition & 197 deletions bioxelnodes/io_points.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,200 +22,4 @@ def create_points_obj(points, name="points"):
# make the bmesh the object's mesh
bm.to_mesh(mesh)
bm.free() # always do this when finished
return obj


# class ImportDICOMPointsDialog(bpy.types.Operator):
# bl_idname = "bioxelnodes.import_dicom_points_dialog"
# bl_label = "Volume Data as Bioxels"
# bl_description = "Import Volume Data as Bioxels (VDB)"
# bl_options = {'UNDO'}

# filepath: bpy.props.StringProperty(
# subtype="FILE_PATH",
# options={'HIDDEN'}
# ) # type: ignore

# bioxels_shape: bpy.props.IntVectorProperty(
# name="Bioxels Shape (ReadOnly)",
# min=0,
# default=(100, 100, 100)
# ) # type: ignore

# bioxel_size: bpy.props.FloatProperty(
# name="Bioxel Size",
# soft_min=0.1, soft_max=10.0,
# min=1e-2, max=1e2,
# default=1,
# update=on_bioxel_size_changed
# ) # type: ignore

# orig_spacing: bpy.props.FloatVectorProperty(
# name="Original Spacing",
# default=(1, 1, 1),
# update=on_orig_spacing_changed
# ) # type: ignore

# orig_shape: bpy.props.IntVectorProperty(
# name="Original Shape",
# default=(100, 100, 100),
# options={'HIDDEN'}
# ) # type: ignore

# auto: bpy.props.BoolProperty(
# name="Auto Setting",
# default=False,
# options={'HIDDEN'}
# ) # type: ignore

# scene_scale: bpy.props.FloatProperty(
# name="Scene Scale",
# soft_min=0.001, soft_max=100.0,
# min=1e-6, max=1e6,
# default=0.01,
# ) # type: ignore

# do_add_segmentnode: bpy.props.BoolProperty(
# name="Add Segment Node",
# default=True,
# ) # type: ignore

# do_change_render_setting: bpy.props.BoolProperty(
# name="Change Render Setting",
# default=True,
# ) # type: ignore

# def execute(self, context):
# files = get_data_files(self.filepath)
# name = Path(self.filepath).parent.name

# image = sitk.ReadImage(files)

# bioxel_size = float(self.bioxel_size)
# orig_spacing = tuple(self.orig_spacing)
# image_spacing = image.GetSpacing()
# image_shape = image.GetSize()

# bioxels_spacing = (
# image_spacing[0] / orig_spacing[0] * bioxel_size,
# image_spacing[1] / orig_spacing[1] * bioxel_size,
# image_spacing[2] / orig_spacing[2] * bioxel_size
# )

# bioxels_shape = (
# int(image_shape[0] / bioxel_size * orig_spacing[0]),
# int(image_shape[1] / bioxel_size * orig_spacing[1]),
# int(image_shape[2] / bioxel_size * orig_spacing[2]),
# )

# print("Resampling...")
# image = sitk.Resample(
# image1=image,
# size=bioxels_shape,
# transform=sitk.Transform(),
# interpolator=sitk.sitkLinear,
# outputOrigin=image.GetOrigin(),
# outputSpacing=bioxels_spacing,
# outputDirection=image.GetDirection(),
# defaultPixelValue=0,
# outputPixelType=image.GetPixelID(),
# )

# print("Orienting to RAS...")
# image = sitk.DICOMOrient(image, 'RAS')

# array = sitk.GetArrayFromImage(image)
# orig_dtype = str(array.dtype)
# print(f"Coverting Dtype from {orig_dtype} to float...")
# array = array.astype(float)

# # ITK indices, by convention, are [i,j,k] while NumPy indices are [k,j,i]
# # https://www.slicer.org/wiki/Coordinate_systems

# # ITK Numpy 3D
# # R (ight) i -> k -> x
# # A (nterior) j -> j -> y
# # S (uperior) k -> i -> z

# array = np.transpose(array)
# bioxels_max = float(np.max(array))
# bioxels_min = float(np.min(array))
# bioxels_shape = array.shape

# print("Bioxel Size:", bioxel_size)
# print("Bioxels Shape:", bioxels_shape)

# bioxels_offset = 0.0
# if bioxels_min < 0 and orig_dtype[0] != "u":
# bioxels_offset = -bioxels_min
# array = array + np.full_like(array, bioxels_offset)
# bioxels_max = float(np.max(array))
# bioxels_min = float(np.min(array))
# print("Offseted Max:", bioxels_max)
# print("Offseted Min:", bioxels_min)

# points = []
# for x in range(array.shape[0]):
# for y in range(array.shape[1]):
# for z in range(array.shape[2]):
# points.append({
# "pos": (x, y, z),
# "value": array[x, y, z],
# })

# # # Build VDB
# # grid = vdb.FloatGrid()
# # grid.copyFromArray(array.copy())

# # # After sitk.DICOMOrient(), origin and direction will also orient base on LPS
# # # so we need to convert them into RAS
# # mat_lps2ras = axis_conversion(
# # from_forward='-Z',
# # from_up='-Y',
# # to_forward='-Z',
# # to_up='Y'
# # ).to_4x4()

# # mat_location = mathutils.Matrix.Translation(
# # mathutils.Vector(image.GetOrigin())
# # )

# # mat_rotation = mathutils.Matrix(
# # np.array(image.GetDirection()).reshape((3, 3))
# # ).to_4x4()

# # mat_scale = mathutils.Matrix.Scale(
# # bioxel_size, 4
# # )

# # transfrom = mat_lps2ras @ mat_location @ mat_rotation @ mat_scale

# obj = create_points_obj(points)

# # Make transformation
# scene_scale = float(self.scene_scale)
# # (S)uperior -Z -> Y
# # (A)osterior Y -> Z
# mat_ras2blender = axis_conversion(
# from_forward='-Z',
# from_up='Y',
# to_forward='Y',
# to_up='Z'
# ).to_4x4()

# mat_scene_scale = mathutils.Matrix.Scale(
# scene_scale, 4
# )

# obj.matrix_world = mat_ras2blender @ mat_scene_scale

# self.report({"INFO"}, "Successfully Imported")

# return {'FINISHED'}

# def invoke(self, context, event):
# # print(tuple(self.orig_shape))
# self.auto = True
# self.bioxel_size = 1
# context.window_manager.invoke_props_dialog(self)
# return {'RUNNING_MODAL'}
return obj
2 changes: 1 addition & 1 deletion bioxelnodes/misc.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import bpy
from pathlib import Path
import shutil
from bioxelnodes.utils import get_all_layers, get_container, get_container_layers
from .utils import get_all_layers, get_container, get_container_layers


def save_layer(layer, output_dir):
Expand Down
4 changes: 2 additions & 2 deletions bioxelnodes/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
def add_driver_to_node_factory(source_prop, target_prop):
callback_str = f"""
import bpy
from bioxelnodes.utils import add_direct_driver, get_bioxels_obj
from .utils import add_direct_driver, get_bioxels_obj
bioxels_obj = get_bioxels_obj(bpy.context.active_object)
if bioxels_obj:
container_obj = bioxels_obj.parent
Expand All @@ -26,7 +26,7 @@ def add_driver_to_node_factory(source_prop, target_prop):
def set_prop_to_node_factory(source_prop, target_prop):
callback_str = f"""
import bpy
from bioxelnodes.utils import get_bioxels_obj
from .utils import get_bioxels_obj
bioxels_obj = get_bioxels_obj(bpy.context.active_object)
if bioxels_obj:
container_obj = bioxels_obj.parent
Expand Down
1 change: 0 additions & 1 deletion bioxelnodes/preferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,4 @@ def draw(self, context):

layout.label(text="Configuration")
layout.prop(self, 'cache_dir')

layout.prop(self, "do_change_render_setting")
Binary file added docs/assets/cover.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 13 additions & 2 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,19 @@ Currently only support Blender 4.0 or above, make sure you have the correct vers

## Add-on Installation

Download the latest version https://github.com/OmooLab/BioxelNodes/releases/latest
In Blender, Edit > Preferences > Add-ons > Install, select the `BioxelNodes_{version}.zip` you just downloaded.
#### For Blender 4.2 or higher

Download the **Extension** version `BioxelNodes_Extension_{version}.zip` from https://github.com/OmooLab/BioxelNodes/releases/latest
In Blender, Edit > Preferences > Extensions > Install from Disk, select the zip file you just downloaded.

Thats it!

> If it cannot be enable, just reboot blender.

#### For Blender 4.0 or 4.1

Download the **Addon** version `BioxelNodes_Addon_{version}.zip` from https://github.com/OmooLab/BioxelNodes/releases/latest
In Blender, Edit > Preferences > Add-ons > Install, select the zip file you just downloaded.

The add-on requires a third-party python dependency called SimpleITK, click `Install SimpleITK` button below to install the dependency. After clicking, blender may get stuck, it is downloading and installing, just wait for a moment. After that, click `Reboot Blender` button.

Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Before us, there have been many tutorials and add-ons for importing volumetric d

Below are some examples with Bioxel Nodes. Thanks to Cycles Render, the volumetric data can be rendered with great detail:

![gallery](assets/gallery.png)
![cover](assets/cover.png)

The "Bioxel" in "Bioxel Nodes", is a combination of the words "Bio-" and "Voxel". Bioxel is a voxel that stores biological data. We are developing a toolkit around Bioxel for better biological data visualization. but before its release, we made this Blender version of bioxels toolkit first, in order to let more people to have fun with volumetric data. [Getting Started](https://omoolab.github.io/BioxelNodes/latest/getting-started)

Expand Down
22 changes: 22 additions & 0 deletions extension/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import bpy

from . import auto_load
from . import menus


auto_load.init()


def register():
auto_load.register()
menus.add()
bpy.types.Scene.bioxel_layer_dir = bpy.props.StringProperty(
name="Bioxel Layers Directory",
subtype='DIR_PATH',
default="//"
)


def unregister():
menus.remove()
auto_load.unregister()
Loading
Loading