Skip to content

Commit

Permalink
changed coded nodegroups to assets file
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Douglass authored and Michael Douglass committed Apr 28, 2024
1 parent 5e821ec commit afcaaf3
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 215 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,11 @@ __pycache__/constants.cpython-310.pyc
__pycache__/__init__.cpython-310.pyc
__pycache__/node_groups.cpython-310.pyc
test.py
__pycache__/__init__.cpython-311.pyc
__pycache__/blender_utils.cpython-311.pyc
__pycache__/constants.cpython-311.pyc
__pycache__/dicom_util.cpython-311.pyc
__pycache__/install_modules.cpython-311.pyc
__pycache__/node_groups.cpython-311.pyc
__pycache__/proton.cpython-311.pyc
assets/MedBlend_Assets.blend1
20 changes: 9 additions & 11 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
extract_dicom_data,
filter_by_series_uid
)
from .node_groups import apply_dose_shader, apply_image_shader, add_CT_to_volume_geo_nodes, add_proton_geo_nodes
from .node_groups import apply_DICOM_shader, add_CT_to_volume_geo_nodes, add_proton_geo_nodes
from .blender_utils import add_data_fields, create_object
from .install_modules import verify_user_sitepackages, install_python_modules, check_dependencies

Expand Down Expand Up @@ -163,15 +163,11 @@ def execute(self, context):
origin = [image_origin[2], image_origin[1], image_origin[0]]#[int(len(sorted_images)/2)]
origin = np.asarray(origin)
volume_dim = np.shape(CT_volume)



print('Origin:', origin)
print('Volume Dimensions:', volume_dim)
print('Spacing:', spacing)

# Print out some information about your sorted slices
#print(f"Number of slices: {len(sorted_images)}")
#print(f"First slice instance number: {sorted_images[0].InstanceNumber}")
#print(f"Last slice instance number: {sorted_images[-1].InstanceNumber}")


# Create an OpenVDB volume from the pixel data
Expand Down Expand Up @@ -202,7 +198,7 @@ def execute(self, context):
#images_loaded = True
else:
print('No DICOM images loaded')
apply_image_shader()
apply_DICOM_shader('Image Material')
return {"FINISHED"}

#Class to load Proton Plan files
Expand Down Expand Up @@ -390,10 +386,11 @@ def execute(self, context):

#Converts list to numpy array
dose_matrix = np.asarray(pixel_data)
dose_matrix = np.flipud(dose_matrix)

#Normalises the image volume in range 0,1
#dose_matrix = dose_matrix/np.max(dose_matrix)
dose_matrix = rescale_DICOM_image(dose_matrix)
#dose_matrix = rescale_DICOM_image(dose_matrix)
#dose_matrix = dose_matrix.transpose(0, 2, 1)
# Create an OpenVDB volume from the pixel data

Expand All @@ -419,11 +416,11 @@ def execute(self, context):
bpy.ops.object.volume_import(filepath=str(dose_dir), files=[])
#DICOM_object = easybpy.get_selected_object()
# Set the volume's origin to match the DICOM image position
bpy.context.object.location = (origin[2]/1000,origin[1]/1000,origin[0]/1000)
#bpy.context.object.location = (origin[2]/1000,origin[1]/1000,origin[0]/1000)
dose_loaded = True
else:
print('No Dose File Loaded')
apply_dose_shader()
apply_DICOM_shader('Dose Material')

return {"FINISHED"}

Expand Down Expand Up @@ -507,6 +504,7 @@ def execute(self, context):

# Add the volume to the scene
bpy.ops.object.volume_import(filepath=str(struct_dir), files=[])
apply_DICOM_shader('Structure Material')
#DICOM_object = easybpy.get_selected_object()
# Set the volume's origin to match the DICOM image position
#bpy.context.object.location = (origin[2]/1000,origin[1]/1000,origin[0]/1000)
Expand Down
Binary file added assets/MedBlend_Assets.blend
Binary file not shown.
6 changes: 6 additions & 0 deletions install_modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import os
import site
import bpy
import importlib


def verify_user_sitepackages(mda_path):
"""
Expand Down Expand Up @@ -33,6 +35,10 @@ def is_module_installed(module_name):
with open(current_path+'/requirements.txt') as f:
for line in f:
module_name = line.strip().split('==')[0] # Remove version if present

# Invalidate the import cache to ensure that the latest version of the module is imported
importlib.invalidate_caches() # Invalidate the import cache

#print('Checking for module:', module_name)
if not is_module_installed(module_name):
print(f"Module '{module_name}' is not installed")
Expand Down
227 changes: 23 additions & 204 deletions node_groups.py
Original file line number Diff line number Diff line change
@@ -1,218 +1,37 @@
import bpy
import os

def dose_material_shader():

def append_item_from_blend(file_path, item_type, item_name):
"""
Constructs the volume shader for the dose volume
Append an item from a .blend file
"""
mat = bpy.data.materials.new(name = "Dose Material")
mat.use_nodes = True
dose_material = mat.node_tree

#start with a clean node tree
for node in dose_material.nodes:
dose_material.nodes.remove(node)
#initialize dose_material nodes
#node Math
math = dose_material.nodes.new("ShaderNodeMath")
math.operation = 'MULTIPLY'
#Value_001
math.inputs[1].default_value = 2.0
#Value_002
math.inputs[2].default_value = 0.5
#node ColorRamp
colorramp = dose_material.nodes.new("ShaderNodeValToRGB")
colorramp.color_ramp.color_mode = 'RGB'
colorramp.color_ramp.hue_interpolation = 'NEAR'
colorramp.color_ramp.interpolation = 'LINEAR'
colorramp.color_ramp.elements.remove(colorramp.color_ramp.elements[0])
colorramp_cre_0 = colorramp.color_ramp.elements[0]
colorramp_cre_0.position = 0.0
colorramp_cre_0.alpha = 0.0
colorramp_cre_0.color = (0.0, 0.0, 0.0, 0.0)
colorramp_cre_1 = colorramp.color_ramp.elements.new(0.3227274417877197)
colorramp_cre_1.alpha = 0.5
colorramp_cre_1.color = (0.0, 0.029376786202192307, 1.0, 0.5)
colorramp_cre_2 = colorramp.color_ramp.elements.new(0.6818180680274963)
colorramp_cre_2.alpha = 1.0
colorramp_cre_2.color = (1.0, 0.7747962474822998, 0.0, 1.0)
colorramp_cre_3 = colorramp.color_ramp.elements.new(1.0)
colorramp_cre_3.alpha = 1.0
colorramp_cre_3.color = (1.0, 0.0041215610690414906, 0.0, 1.0)
#node Volume Info
volume_info = dose_material.nodes.new("ShaderNodeVolumeInfo")
#node ColorRamp.001
colorramp_001 = dose_material.nodes.new("ShaderNodeValToRGB")
colorramp_001.color_ramp.color_mode = 'RGB'
colorramp_001.color_ramp.hue_interpolation = 'NEAR'
colorramp_001.color_ramp.interpolation = 'LINEAR'
colorramp_001.color_ramp.elements.remove(colorramp_001.color_ramp.elements[0])
colorramp_001_cre_0 = colorramp_001.color_ramp.elements[0]
colorramp_001_cre_0.position = 0.0
colorramp_001_cre_0.alpha = 0.0
colorramp_001_cre_0.color = (0.0, 0.0, 0.0, 0.0)
colorramp_001_cre_1 = colorramp_001.color_ramp.elements.new(1.0)
colorramp_001_cre_1.alpha = 1.0
colorramp_001_cre_1.color = (1.0, 1.0, 1.0, 1.0)
#node Material Output
material_output = dose_material.nodes.new("ShaderNodeOutputMaterial")
material_output.target = 'ALL'
#Displacement
material_output.inputs[2].default_value = (0.0, 0.0, 0.0)
#Thickness
material_output.inputs[3].default_value = 0.0
#node Principled Volume
principled_volume = dose_material.nodes.new("ShaderNodeVolumePrincipled")
#Color
principled_volume.inputs[0].default_value = (0.5, 0.5, 0.5, 1.0)
#Color Attribute
principled_volume.inputs[1].default_value = ""
#Density
principled_volume.inputs[2].default_value = 0.0
#Density Attribute
principled_volume.inputs[3].default_value = "density"
#Anisotropy
principled_volume.inputs[4].default_value = 0.0
#Absorption Color
principled_volume.inputs[5].default_value = (0.0, 0.0, 0.0, 1.0)
#Blackbody Intensity
principled_volume.inputs[8].default_value = 0.0
#Blackbody Tint
principled_volume.inputs[9].default_value = (1.0, 1.0, 1.0, 1.0)
#Temperature
principled_volume.inputs[10].default_value = 1000.0
#Temperature Attribute
principled_volume.inputs[11].default_value = "temperature"
#Weight
principled_volume.inputs[12].default_value = 0.0
#Set locations
math.location = (-253.8451385498047, 547.6362915039062)
colorramp.location = (-583.43896484375, 330.26849365234375)
volume_info.location = (-822.9508056640625, 436.30157470703125)
colorramp_001.location = (-581.3194580078125, 565.661865234375)
material_output.location = (344.9896545410156, 601.4866943359375)
principled_volume.location = (-74.74122619628906, 568.8428344726562)
#Set dimensions
math.width, math.height = 140.0, 100.0
colorramp.width, colorramp.height = 240.0, 100.0
volume_info.width, volume_info.height = 140.0, 100.0
colorramp_001.width, colorramp_001.height = 240.0, 100.0
material_output.width, material_output.height = 140.0, 100.0
principled_volume.width, principled_volume.height = 240.0, 100.
#initialize dose_material links
#colorramp_001.Color -> math.Value
dose_material.links.new(colorramp_001.outputs[0], math.inputs[0])
#volume_info.Density -> colorramp.Fac
dose_material.links.new(volume_info.outputs[1], colorramp.inputs[0])
#volume_info.Density -> colorramp_001.Fac
dose_material.links.new(volume_info.outputs[1], colorramp_001.inputs[0])
#math.Value -> principled_volume.Emission Strength
dose_material.links.new(math.outputs[0], principled_volume.inputs[6])
#colorramp.Color -> principled_volume.Emission Color
dose_material.links.new(colorramp.outputs[0], principled_volume.inputs[7])
#principled_volume.Volume -> material_output.Volume
dose_material.links.new(principled_volume.outputs[0], material_output.inputs[1])
bpy.ops.wm.append(
directory=file_path + "\\" + item_type + "\\",
filename=item_name
)

def apply_dose_shader():
return dose_material_shader()
def apply_DICOM_shader(shader_name):
current_path = bpy.path.abspath(os.path.dirname(__file__))

#combine current path with the immediate sub-folder called "assets"
path = os.path.join(current_path, "assets")
#sets assets file name to MedBlend_Assets.blend
assets_file = os.path.join(path, "MedBlend_Assets.blend")


def image_material_shader():
"""
Constructs the volume shader for the CT and MRI images
"""
#checks if there exists a material in the current scene called "Image Material"
if not shader_name in bpy.data.materials:
append_item_from_blend(assets_file, "Material", shader_name)
#Attach the image material shader to thhe currently selected object
bpy.context.object.data.materials.append(bpy.data.materials[shader_name])
else:
bpy.context.object.data.materials.append(bpy.data.materials[shader_name])

mat = bpy.data.materials.new(name = "Image Material")
mat.use_nodes = True
#initialize image_material node group

image_material = mat.node_tree
#start with a clean node tree
for node in image_material.nodes:
image_material.nodes.remove(node)
#initialize image_material nodes
#node Material Output
material_output = image_material.nodes.new("ShaderNodeOutputMaterial")
material_output.target = 'ALL'
#Displacement
material_output.inputs[2].default_value = (0.0, 0.0, 0.0)
#Thickness
material_output.inputs[3].default_value = 0.0
#node Math
math = image_material.nodes.new("ShaderNodeMath")
math.operation = 'MULTIPLY'
#Value_001
math.inputs[1].default_value = 5.0
#Value_002
math.inputs[2].default_value = 0.5
#node ColorRamp
colorramp = image_material.nodes.new("ShaderNodeValToRGB")
colorramp.color_ramp.color_mode = 'RGB'
colorramp.color_ramp.hue_interpolation = 'NEAR'
colorramp.color_ramp.interpolation = 'LINEAR'
colorramp.color_ramp.elements.remove(colorramp.color_ramp.elements[0])
colorramp_cre_0 = colorramp.color_ramp.elements[0]
colorramp_cre_0.position = 0.0
colorramp_cre_0.alpha = 0.0
colorramp_cre_0.color = (0.0, 0.0, 0.0, 0.0)
colorramp_cre_1 = colorramp.color_ramp.elements.new(1.0)
colorramp_cre_1.alpha = 1.0
colorramp_cre_1.color = (1.0, 1.0, 1.0, 1.0)
#node Volume Info
volume_info = image_material.nodes.new("ShaderNodeVolumeInfo")
#node Principled Volume
principled_volume = image_material.nodes.new("ShaderNodeVolumePrincipled")
#Color
principled_volume.inputs[0].default_value = (0.5, 0.5, 0.5, 1.0)
#Color Attribute
principled_volume.inputs[1].default_value = ""
#Density
principled_volume.inputs[2].default_value = 0.0
#Density Attribute
principled_volume.inputs[3].default_value = "density"
#Anisotropy
principled_volume.inputs[4].default_value = 0.0
#Absorption Color
principled_volume.inputs[5].default_value = (0.0, 0.0, 0.0, 1.0)
#Blackbody Intensity
principled_volume.inputs[8].default_value = 0.0
#Blackbody Tint
principled_volume.inputs[9].default_value = (1.0, 1.0, 1.0, 1.0)
#Temperature
principled_volume.inputs[10].default_value = 1000.0
#Temperature Attribute
principled_volume.inputs[11].default_value = "temperature"
#Weight
principled_volume.inputs[12].default_value = 0.0
#Set locations
material_output.location = (300.0, 300.0)
math.location = (-290.64935302734375, 185.22756958007812)
colorramp.location = (-650.9771118164062, 14.403594970703125)
volume_info.location = (-876.3124389648438, -123.81324768066406)
principled_volume.location = (-85.48944091796875, 91.50717163085938)
#Set dimensions
material_output.width, material_output.height = 140.0, 100.0
math.width, math.height = 140.0, 100.0
colorramp.width, colorramp.height = 240.0, 100.0
volume_info.width, volume_info.height = 140.0, 100.0
principled_volume.width, principled_volume.height = 240.0, 100.0
#initialize image_material links
#colorramp.Color -> math.Value
image_material.links.new(colorramp.outputs[0], math.inputs[0])
#colorramp.Color -> principled_volume.Emission Color
image_material.links.new(colorramp.outputs[0], principled_volume.inputs[7])
#volume_info.Density -> colorramp.Fac
image_material.links.new(volume_info.outputs[1], colorramp.inputs[0])
#math.Value -> principled_volume.Emission Strength
image_material.links.new(math.outputs[0], principled_volume.inputs[6])
#principled_volume.Volume -> material_output.Volume
image_material.links.new(principled_volume.outputs[0], material_output.inputs[1])



def apply_image_shader():
return image_material_shader()
return True


def ct_volume_to_mesh_node_group():
Expand Down

0 comments on commit afcaaf3

Please sign in to comment.