<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">import os

import SimpleITK as sitk
import matplotlib.pyplot as plt
from matplotlib.widgets import AxesWidget
import numpy as np


class Show3D():
	def __init__(self, img, title, segment=False ):
		self.img = img
		self.size = img.GetSize()
		self.axis = 'z'
		self.slices = self.size[2]-1	# -1 becasue slices start at zero, in python but also in slicer for comparison.
		self.slice = self.slices/2
		self.segment = segment
		nda = sitk.GetArrayFromImage(img[:, :,self.slice])
		dpi = 30
		margin=0.05
		figsize = (1 + margin) * nda.shape[1] / dpi, (1 + 2*margin) * nda.shape[0]
		self.extent = (0, nda.shape[1], nda.shape[0], 0)
		self.fig = plt.figure(title, figsize=figsize)
		self.ax = self.fig.add_axes([margin, margin, 1 - 2 * margin, 1 - 2 * margin])
		self.ax.text(0.5*nda.shape[1], -5, '{} of {}'.format(self.slice, self.slices), ha='center')
		if segment:
			self.ax.text(0.1*nda.shape[1], 1.07*nda.shape[0], 'Left Click to\nSeed Skin\nSegmentation', ha='center',
						 bbox={'alpha': 0.8, 'pad': 10,  'facecolor': 'cyan'})
			self.ax.text(0.5*nda.shape[1], 1.07*nda.shape[0], 'Middle Click to\nSeed Fat\nSegmentation', ha='center',
						 bbox={'alpha': 0.8, 'pad': 10, 'facecolor': 'yellow'})
			self.ax.text(0.9*nda.shape[1], 1.07*nda.shape[0], 'Right Click to\nSeed Muscle\nSegmentation', ha='center',
						 bbox={'alpha': 0.8, 'pad': 10, 'facecolor': 'red'})
			self.muscleSeeds = []
			self.fatSeeds = []
			self.skinSeeds = []
			self.click = self.fig.canvas.mpl_connect('button_press_event', self.onClick)
		plt.set_cmap("gray")
		self.ax.imshow(nda, extent=self.extent)
		#
		self.cidscroll=self.fig.canvas.mpl_connect('scroll_event', self)
		# self.key =	self.fig.canvas.mpl_connect('key_press_event', self.onKeyPress)


	def __call__(self, event):
		if event.button == 'down':
			if self.slice &gt; 0:
				self.slice -= 1
		elif event.button == 'up':
			if self.slice &lt; self.slices:
				self.slice += 1
		if self.axis == 'z':
			nda = sitk.GetArrayFromImage(self.img[:, :, self.slice])
		elif self.axis == 'y':
			nda = sitk.GetArrayFromImage(self.img[:, self.slice, :])
		elif self.axis == 'x':
			nda = sitk.GetArrayFromImage(self.img[self.slice, :, :])
		self.ax.clear()
		self.ax.text(0.5 * nda.shape[1], -5, '{} of {}'.format(self.slice, self.slices), ha='center')
		self.ax.imshow(nda, extent=self.extent, interpolation=None)
		if self.segment:
			self.ax.text(0.1 * nda.shape[1], 1.07 * nda.shape[0], 'Left Click to\nSeed Skin\nSegmentation', ha='center',
						 bbox={'alpha': 0.8, 'pad': 10, 'facecolor': 'cyan'})
			self.ax.text(0.5 * nda.shape[1], 1.07 * nda.shape[0], 'Middle Click to\nSeed Fat\nSegmentation', ha='center',
						 bbox={'alpha': 0.8, 'pad': 10, 'facecolor': 'yellow'})
			self.ax.text(0.9 * nda.shape[1], 1.07 * nda.shape[0], 'Right Click to\nSeed Muscle\nSegmentation', ha='center',
						 bbox={'alpha': 0.8, 'pad': 10, 'facecolor': 'red'})
		plt.draw()

	# def onKeyPress(self, event):
	# 	if event.key == self.axis:	return
	# 	elif event.key == 'x':
	# 		self.axis = 'x'
	# 		self.slices = self.size[0]-1
	# 		self.slice = self.slices/2
	# 		nda = sitk.GetArrayFromImage(self.img[self.slice, :, :])
	# 	elif event.key == 'y':
	# 		self.axis = 'y'
	# 		self.slices = self.size[1]-1
	# 		self.slice = self.slices/2
	# 		nda = sitk.GetArrayFromImage(self.img[:, self.slice, :])
	# 	elif event.key == 'z':
	# 		self.axis = 'z'
	# 		self.slices = self.size[2]-1
	# 		self.slice = self.slices/2
	# 		nda = sitk.GetArrayFromImage(self.img[:, :, self.slice])
	# 	else: return
	# 	plt.draw()

	def onClick(self, event):
		if self.segment:
			x, y = int(event.xdata), int(event.ydata)
			z = self.slice
			if event.button == 1:	# left click
				plt.plot(x, y, 'co')
				self.skinSeeds.append((x, y, z))
			elif event.button == 2:	# middle button
				plt.plot(x, y, 'yo')
				self.fatSeeds.append((x, y, z))
			elif event.button == 3:	# right click
				# plt.plot(x, y, color='sienna', marker='o')
				plt.plot(x, y, 'ro')
				self.muscleSeeds.append((x, y, z))
			plt.draw()

class ShowWithSlider():
	#	My seeding methods don't work with this Slider"""
	def __init__(self, img, title):
		self.img = img
		self.size = img.GetSize()
		self.axis = 'z'
		try:				self.slices = self.size[2]-1	# -1 becasue slices start at zero, in python but also in slicer for comparison.
		except IndexError:	self.slices=0
		self.slice = self.slices/2
		#
		try:				nda = sitk.GetArrayFromImage(img[:, :,self.slice])
		except IndexError:	nda  = sitk.GetArrayFromImage(img)
		#
		margin = 0.05
		self.extent = (0, nda.shape[1], nda.shape[0], 0)
		self.fig = plt.figure(title, figsize=(15,12) )	# figsize is measured in inches
		self.ax = self.fig.add_axes([margin, margin, 1-2*margin, 1-2*margin])
		#
		self.ax.text(0.5*nda.shape[1], -5, '{} of {}'.format(self.slice, self.slices), ha='center')
		plt.set_cmap("gray")
		#
		#
		axSlice = plt.axes([1 - margin, margin, 0.01, 1 - 2 * margin], axisbg='ivory')
		if len(self.size) ==3:
			self.sliceSlider=VertSlider(axSlice, 'Slice',0,self.size[2]-1,self.slice,facecolor='aliceblue',edgecolor='black')
			self.sliceSlider.on_changed(self.onSlider)
		#
		self.ax.imshow(nda, extent=self.extent)
		#
		self.cidscroll=self.fig.canvas.mpl_connect('scroll_event', self)
		# self.key =	self.fig.canvas.mpl_connect('key_press_event', self.onKeyPress)

	def __call__(self, event):
		if event.button == 'down':
			if self.slice &gt; 0:
				self.slice -= 1
		elif event.button == 'up':
			if self.slice &lt; self.slices:
				self.slice += 1
		self.sliceSlider.set_val(self.slice)
		if self.axis == 'z':
			nda = sitk.GetArrayFromImage(self.img[:, :, self.slice])
		elif self.axis == 'y':
			nda = sitk.GetArrayFromImage(self.img[:, self.slice, :])
		elif self.axis == 'x':
			nda = sitk.GetArrayFromImage(self.img[self.slice, :, :])
		self.reDraw(nda)

	# def onKeyPress(self, event):
	# 	if event.key == self.axis:	return
	# 	elif event.key == 'x':
	# 		self.axis = 'x'
	# 		self.slices = self.size[0]-1
	# 		self.slice = self.slices/2
	# 		nda = sitk.GetArrayFromImage(self.img[self.slice, :, :])
	# 	elif event.key == 'y':
	# 		self.axis = 'y'
	# 		self.slices = self.size[1]-1
	# 		self.slice = self.slices/2
	# 		nda = sitk.GetArrayFromImage(self.img[:, self.slice, :])
	# 	elif event.key == 'z':
	# 		self.axis = 'z'
	# 		self.slices = self.size[2]-1
	# 		self.slice = self.slices/2
	# 		nda = sitk.GetArrayFromImage(self.img[:, :, self.slice])
	# 	else: return
	# 	plt.draw()

	def onSlider(self, sliderValue):
		sliderValue=int(sliderValue)
		self.slice = sliderValue
		#
		nda = sitk.GetArrayFromImage(self.img[:, :, self.slice])
		self.reDraw(nda)

	def reDraw(self, nda):
		self.ax.clear()
		self.ax.text(0.5 * nda.shape[1], -5, '{} of {}'.format(self.slice, self.slices), ha='center')
		self.ax.imshow(nda, extent=self.extent)
		plt.draw()

class VertSlider(AxesWidget):
	"""
	A slider representing a floating point range

	The following attributes are defined
	*ax*		: the slider :class:`matplotlib.axes.Axes` instance
	*val*		: the current slider value
	*vline*		: a :class:`matplotlib.lines.Line2D` instance
				representing the initial value of the slider
	*poly*		: A :class:`matplotlib.patches.Polygon` instance
				which is the slider knob
	*valfmt*		: the format string for formatting the slider text
	*label*		: a :class:`matplotlib.text.Text` instance
				for the slider label
	*closedmin*	: whether the slider is closed on the minimum
	*closedmax*	: whether the slider is closed on the maximum
	*slidermin*	: another slider - if not *None*, this slider must be
				greater than *slidermin*
	*slidermax*	: another slider - if not *None*, this slider must be
				less than *slidermax*
	*dragging*	: allow for mouse dragging on slider
	Call :meth:`on_changed` to connect to the slider event
	"""
	def __init__(self, ax, label, valmin, valmax, valinit=0, valfmt='%i',
					closedmin=True, closedmax=True, slidermin=None,
					slidermax=None, dragging=True, **kwargs):
		"""
		Create a slider from *valmin* to *valmax* in axes *ax*
		*valinit*	: The slider initial position
		*label*		: The slider label
		*valfmt*	: Used to format the slider value
		*closedmin* and *closedmax*
					Indicate whether the slider interval is closed
		*slidermin* and *slidermax*
					Used to constrain the value of this slider to the values of other sliders.

		additional kwargs are passed on to ``self.poly`` which is the
		:class:`matplotlib.patches.Rectangle` which draws the slider
		knob.  See the :class:`matplotlib.patches.Rectangle` documentation
		valid property names (e.g., *facecolor*, *edgecolor*, *alpha*, ...)
		"""
		AxesWidget.__init__(self, ax)
		#
		self.valmin = valmin
		self.valmax = valmax
		self.val = valinit
		self.valinit = valinit
		self.poly = ax.axhspan(valmin, valinit, 0, 1, **kwargs)
		#
		# self.vline = ax.axhline(valinit, 0, 1, color='r', lw=1)
		#
		self.valfmt = valfmt
		ax.set_xticks([])
		ax.set_ylim((valmin, valmax))
		ax.set_yticks([])
		ax.set_navigate(False)
		#
		self.connect_event('button_press_event', self._update)
		self.connect_event('button_release_event', self._update)
		if dragging:
			self.connect_event('motion_notify_event', self._update)
		self.label = ax.text(0.5, 1.03, label, transform=ax.transAxes, verticalalignment='center', horizontalalignment='center')
		#
		self.valtext = ax.text(0.5, -0.03, valfmt % valinit, transform=ax.transAxes, verticalalignment='center', horizontalalignment='center')
		#
		self.cnt = 0
		self.observers = {}
		#
		self.closedmin = closedmin
		self.closedmax = closedmax
		self.slidermin = slidermin
		self.slidermax = slidermax
		self.drag_active = False

	def _update(self, event):
		"""update the slider position"""
		if self.ignore(event):
			return
		if event.button != 1:
			return
		if event.name == 'button_press_event' and event.inaxes == self.ax:
			self.drag_active = True
			event.canvas.grab_mouse(self.ax)
		if not self.drag_active:
			return
		elif (	(event.name == 'button_release_event') or
			(event.name == 'button_press_event' and event.inaxes != self.ax) ):
				self.drag_active = False
				event.canvas.release_mouse(self.ax)
				return
		#
		val = event.ydata
		if val &lt;= self.valmin:
			if not self.closedmin:
				return
			val = self.valmin
		elif val &gt;= self.valmax:
			if not self.closedmax:
				return
			val = self.valmax
		#
		if self.slidermin is not None and val &lt;= self.slidermin.val:
			if not self.closedmin:
				return
			val = self.slidermin.val
		#
		if self.slidermax is not None and val &gt;= self.slidermax.val:
			if not self.closedmax:
				return
			val = self.slidermax.val
		#
		# For my purposes I want this to be an integer
		val = int(val)
		#
		self.set_val(val)

	def set_val(self, val):
		xy = self.poly.xy
		xy[1] = 0, val
		xy[2] = 1, val
		self.poly.xy = xy
		self.valtext.set_text(self.valfmt % val)
		if self.drawon:
			self.ax.figure.canvas.draw()
		self.val = val
		if not self.eventson:
			return
		for cid, func in self.observers.iteritems():
			func(val)

	def on_changed(self, func):
		"""
		When the slider value is changed, call *func* with the new
		slider position

		A connection id is returned which can be used to disconnect
		"""
		cid = self.cnt
		self.observers[cid] = func
		self.cnt += 1
		return cid

	def disconnect(self, cid):
		"""remove the observer with connection id *cid*"""
		try:				del self.observers[cid]
		except KeyError:	pass

	def reset(self):
		"""reset the slider to the initial value if needed"""
		if (self.val != self.valinit):
			self.set_val(self.valinit)


def ReadImage(file):
	"""Check if file is ia file or a directory, and read it into memory
		returns the sitk image"""
	if os.path.isdir(file):		# this method assumes (and works) only if there is only one dicom in the directory
		reader = sitk.ImageSeriesReader()
		reader.SetFileNames(reader.GetGDCMSeriesFileNames(file))
	else:
		reader = sitk.ImageFileReader()
		reader.SetFileName(file)
	image = reader.Execute()
	return image

def PreProcess(image):
	"""Currently uses Curvature Flow
		Still looking for better options!"""
	# Still looking for better options for preProcessing
	processedImage = sitk.CurvatureFlow(image1=image, timeStep=0.0125, numberOfIterations=3)
	return processedImage

def Segmentation(image, name, seeds, label=1):
	if seeds:
		intensity = np.zeros(len(seeds))
		for i in xrange(len(seeds)):
			intensity[i] = image.GetPixel(seeds[i])
		#
		avg = np.mean(intensity)
		std = np.std(intensity)
		if std==0:    std=2
		#
		edgeMax = avg + 2 * std
		edgeMin = avg - 2 * std
		if edgeMin &lt; 0:    edgeMin = 0
		print '{} Threshold: {} - {}'.format(name, edgeMin, edgeMax)
		#
		imgLabel = sitk.ConnectedThreshold(image1=image,
										  seedList=seeds,
										  lower=edgeMin,
										  upper=edgeMax,
										  replaceValue=label)
		return imgLabel
	else: return image &lt; 0

def JoinImages(files1, output='', reverse=False):
	"""Checks if files is an iterable of file or a directory
		if directory gets all files in directory
		reads all files into sitk image
		uses sitk TileImageFilter to join images
		writes join image to output if given
		if reverse is true reverse list of files
		returns joined image"""
	if os.path.isdir(files1):
		os.chdir(files1)
		files1 = sorted(os.listdir(files1))
	files=[]
	for file in files1:
		if file.endswith('.nii'):
			print file
			files.append(file)

	images = [ReadImage(file) for file in files]
	if reverse:		images = images[::-1]
	#
	allImages = sitk.TileImageFilter()
	allImages.SetLayout((1, 1, 0))
	allImages = allImages.Execute(images)
	#
	# Verify output
	ShowWithSlider(allImages, 'Check if images have continuity!!!')
	plt.show()
	#
	if output:		sitk.WriteImage(allImages, output)
	#
	return allImages
</pre></body></html>