From 0c8cb7b4301553070b0ef2f17c34190897dfcfd0 Mon Sep 17 00:00:00 2001
From: quantulr <35954003+quantulr@users.noreply.github.com>
Date: Fri, 19 Apr 2024 17:08:06 +0800
Subject: [PATCH] update
---
.gitignore | 160 ++++++++++++++++++
.idea/crystalfly.iml | 2 +-
.idea/misc.xml | 2 +-
.idea/poetry.xml | 10 ++
.idea/vcs.xml | 6 +
crystalfly/main.py | 5 +-
crystalfly/test.py | 52 ++++++
crystalfly/test_volumn.py | 58 +++++++
.../__pycache__/image_reader.cpython-311.pyc | Bin 2228 -> 2282 bytes
crystalfly/thread/image_reader.py | 8 +-
.../__pycache__/import_file.cpython-311.pyc | Bin 3875 -> 4565 bytes
.../__pycache__/main_window.cpython-311.pyc | Bin 3135 -> 5719 bytes
.../__pycache__/volume_viewer.cpython-311.pyc | Bin 0 -> 5886 bytes
.../ui/__pycache__/vtk_viewer.cpython-311.pyc | Bin 4280 -> 5041 bytes
crystalfly/ui/ctk.cpp | 112 ++++++++++++
crystalfly/ui/import_file.py | 27 ++-
crystalfly/ui/main_window.py | 58 ++++++-
crystalfly/ui/main_window.ui | 12 +-
crystalfly/ui/volume_viewer.py | 77 +++++++++
crystalfly/ui/vtk_viewer.py | 27 ++-
20 files changed, 585 insertions(+), 31 deletions(-)
create mode 100644 .gitignore
create mode 100644 .idea/poetry.xml
create mode 100644 .idea/vcs.xml
create mode 100644 crystalfly/test.py
create mode 100644 crystalfly/test_volumn.py
create mode 100644 crystalfly/ui/__pycache__/volume_viewer.cpython-311.pyc
create mode 100644 crystalfly/ui/ctk.cpp
create mode 100644 crystalfly/ui/volume_viewer.py
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6769e21
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,160 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/#use-with-ide
+.pdm.toml
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# PyCharm
+# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+# and can be added to the global gitignore or merged into this file. For a more nuclear
+# option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
\ No newline at end of file
diff --git a/.idea/crystalfly.iml b/.idea/crystalfly.iml
index d0876a7..fc4b484 100644
--- a/.idea/crystalfly.iml
+++ b/.idea/crystalfly.iml
@@ -2,7 +2,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 1d62595..5bf8748 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,5 +3,5 @@
-
+
\ No newline at end of file
diff --git a/.idea/poetry.xml b/.idea/poetry.xml
new file mode 100644
index 0000000..2097c01
--- /dev/null
+++ b/.idea/poetry.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/crystalfly/main.py b/crystalfly/main.py
index 1de6a4e..de66de9 100644
--- a/crystalfly/main.py
+++ b/crystalfly/main.py
@@ -1,15 +1,18 @@
+import ctypes
import sys
from PySide6.QtWidgets import QApplication
from crystalfly.ui.main_window import MainWindow
+ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("crystalfly")
+
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
- app.exec()
+ sys.exit(app.exec())
if __name__ == '__main__':
diff --git a/crystalfly/test.py b/crystalfly/test.py
new file mode 100644
index 0000000..aa670b2
--- /dev/null
+++ b/crystalfly/test.py
@@ -0,0 +1,52 @@
+import sys
+
+from PySide6.QtCore import QThread, Signal, Slot
+from PySide6.QtWidgets import QWidget, QPushButton, QApplication, QLabel, QVBoxLayout
+from vtkmodules.vtkIOImage import vtkImageReader2
+
+
+class TestThread(QThread):
+ timeSignal = Signal(str)
+
+ def __init__(self):
+ super().__init__()
+
+ def run(self):
+ reader = vtkImageReader2()
+ reader.SetFileName("D:/Downloads/christmas_tree_512x499x512_uint16.raw")
+ reader.SetFileDimensionality(3)
+ reader.SetDataSpacing(0.1, 0.1, 0.1)
+ reader.SetDataExtent(0, 511, 0, 498, 0, 511)
+ reader.SetDataScalarTypeToUnsignedShort()
+ reader.Update()
+ self.timeSignal.emit("success")
+ # for i in range(10):
+ # print(i)
+ # self.timeSignal.emit(str(i))
+ # time.sleep(1)
+
+
+class MainView(QWidget):
+ def __init__(self):
+ super().__init__()
+ self.resize(800, 600)
+ self.test_thread = TestThread()
+ main_layout = QVBoxLayout()
+ self.label = QLabel("0")
+ self.button = QPushButton('TEST')
+ self.button.clicked.connect(self.button_clicked)
+ main_layout.addWidget(self.label)
+ main_layout.addWidget(self.button)
+ self.setLayout(main_layout)
+ self.test_thread.timeSignal.connect(self.label.setText)
+
+ @Slot()
+ def button_clicked(self):
+ self.test_thread.start()
+
+
+if __name__ == '__main__':
+ app = QApplication(sys.argv)
+ window = MainView()
+ window.show()
+ app.exec()
diff --git a/crystalfly/test_volumn.py b/crystalfly/test_volumn.py
new file mode 100644
index 0000000..43bdf67
--- /dev/null
+++ b/crystalfly/test_volumn.py
@@ -0,0 +1,58 @@
+import vtk
+from PySide6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget
+from vtkmodules.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
+
+
+class VolumeRenderingWindow(QMainWindow):
+ def __init__(self):
+ super().__init__()
+
+ reader = vtk.vtkImageReader2()
+ reader.SetDataExtent(0, 511, 0, 499, 0, 511)
+ reader.SetDataByteOrderToLittleEndian()
+ reader.SetDataScalarTypeToUnsignedShort()
+ reader.SetFileName("D:/Downloads/christmas_tree_512x499x512_uint16.raw") # Replace with your file path
+ reader.Update()
+
+ volume_mapper = vtk.vtkGPUVolumeRayCastMapper() # You can also use vtkFixedPointVolumeRayCastMapper
+ volume_mapper.SetInputData(reader.GetOutput())
+
+ volume_property = vtk.vtkVolumeProperty()
+ color_transfer_function = vtk.vtkColorTransferFunction()
+ color_transfer_function.AddRGBPoint(0, 0, 0, 0) # Black
+ color_transfer_function.AddRGBPoint(255, 1, 1, 1) # White
+ volume_property.SetColor(color_transfer_function)
+
+ gradient_opacity_transfer_function = vtk.vtkPiecewiseFunction()
+ gradient_opacity_transfer_function.AddPoint(0, 0.0)
+ gradient_opacity_transfer_function.AddPoint(90, 0.5)
+ gradient_opacity_transfer_function.AddPoint(100, 1.0)
+ volume_property.SetGradientOpacity(gradient_opacity_transfer_function)
+
+ volume_actor = vtk.vtkVolume()
+ volume_actor.SetMapper(volume_mapper)
+ volume_actor.SetProperty(volume_property)
+
+ renderer = vtk.vtkRenderer()
+ renderer.AddVolume(volume_actor)
+
+ # Create a PySide6 widget to embed the VTK rendering window
+ vtk_widget = QVTKRenderWindowInteractor()
+ vtk_widget.SetRenderWindow(renderer.GetRenderWindow())
+
+ # Set up the main window layout
+ central_widget = QWidget()
+ layout = QVBoxLayout()
+ layout.addWidget(vtk_widget)
+ central_widget.setLayout(layout)
+ self.setCentralWidget(central_widget)
+
+ # Set background color
+ renderer.SetBackground(0.1, 0.2, 0.4)
+
+
+if __name__ == "__main__":
+ app = QApplication([])
+ window = VolumeRenderingWindow()
+ window.show()
+ app.exec()
diff --git a/crystalfly/thread/__pycache__/image_reader.cpython-311.pyc b/crystalfly/thread/__pycache__/image_reader.cpython-311.pyc
index 258e0472a89047105d64dc6140277309bfcd27ba..898b5017ba204f3669f24a6bf69122211d3ab409 100644
GIT binary patch
delta 442
zcmX|6yGjF55Z$}k$4%nKY)C{x9xLjC+K5`3h!7N;6voO%7x%^(6AgExC`7Rc2zD}!
zl@IWNSSYCY2R1f|q*}1C5?ebf@AY+xGn_eRW|%wuUDqx&%_lJ6Ofp~C*IYET|JIY1
zY_X1J728u6W>p*Igg)8Tr^?nMnI@J^=uCmKnqBbl(O*cca{ZBpNfgI5@mv&yD-nt)
zhAv?jC8Hi!a!4spHI{Ofibcsv)!`!sJfJLU14T?G0!%vwqaEP|x3_TTLHJ<3iOm)^
z8`y+#(M0pN1@R08YC@4+_<`+%YcURnw2l05Bt_V=duhbywXLc(SKX`-c#{%H163Xm
z={Zu(uzqgADp_=fn@e(cgdcVl{uiMRUu+mO2q$t<2{GZs;8A|+FrKk-96n9l_*-40
zO`K}sR0F5rP#N>;EJgi{;8hvxZR5&hbScnpC&(M#KjJwj0~2aLEUO8m!=Abk9pLVN
Z_!EzoSM9YDNz*}y;d$hPEj%o7{|g{HXqx~4
delta 441
zcmaDQxJ8h6IWI340}vS4$fa>kDD78AyZhXPe1hjIwOY7#SE=GfvKDlws7I+`}j@$aIUPI5j7&
zhzF>q7^HFXQAR%-ZXlyd3d3Z*`1s7c%#!$cuxdG=q6UV$9Q;=}BxZ
zSY;V`CR?#ODk=o0mbfIABnBrZ<|Gz{R2HO$2KczG$)vic)au7!X
NBirQ79L6jlc>t7@X;A-EPP+kAQXh;1MSlj0CUAdv`7MF?1pj8sfoxl*^5cS%gV*qUAP
zfsAOS960n4G#4u6KoyBLLh7ZL_EPm9Xk{!a&`L;1RqsUYsp_F`)*mfOt{v^Xee?Uh
zH#7U@H~aF!ul>HSMbV9*wI{>N)V1vk;lH;B=Te$C9aJ
zQfe_dmzup@5A>hI*ero_2%Ce>;omS%FL6t_Ov6Ga-Q(JY#%`#=MikY!r3{SapLSZ_^gr6MuzYh~nsXUpSuQ
z0E^Mt2>=V0T%;q;F5E@uo#mb=0J-Mrz<`HtgZ@X5qo>aC%?+%e4X%t8{E)4Hh+s4-
z0iz9WbrCqO$+7f$18x>LTayzSjFmSDoW03eYOC>(7YEK^aY?qI_grE(kbE=Ica9T*
zbJjVh;r}m3dDp1F%)y~}8t|?cB-lnvoX-ca_;$Ftz`xN6MR;LTTrX@JHY41~La1yj
zqdh3nzEvoOZ`jNBU4MO%;7!o5JGJh}uNsl->-<{%&0bd~)}7WE9G(GJ$LheB+4TqOKZg^@%}TfDpDz!iq@PXAt&@gei!y+L1UI({8ZnOU!jV
z$`;mC@($xhm|>Lyks4WI#2uEXOrMf9va<2Cq{>#}1cY2RUCW?RnNemSuVwG6GEuXN
zY&>8u-2pKX)@nlQrN6ksn@nPQA870|bSm{8N~1^8R8^Wfkfsl%=`G)JTWHI5?2&dp
zta=72o`I84cq_S;JQllmo>axbia2-@8hQhXHjt-Pai}5=orH!PNHZ&9A(JpsGbr8&
zdR!G_6)|=af{CnMjT}j1RcY)%8b6fAkEOm-dd1yON8Lf1c1!Wz#5eix+YWlB4|}F7
zf^;fKM?$zNgb#%1p%AS!9ulQrx_`t&^dnEtHLK`OUA0arZmU(5SMu3H@xCdrI+n7=
z1D##AX2rVcD^EYZMSu2uila2)9Zs?T17UR~F=j3@!!97{Wu_a9DavxLkk$2^S}4eJ
z922HV>%!lvodf&rSpOa$-Se(=^f>y?5SZ6C#CxCJJL4EIMPuT)mz|XrnTmJQW$}|6
zp-09;t*EROR6POiOi|N{t20HS)?{ZX&JvrYGfR7x6kF&|;sEy3-^J@Ow)`tZthpoL
z|0PV-rko~AFa%{F{Tik-zK`WI4n9^nVy0;hXd;U-HHzo;X8qn&+K6iPsGO^DU&c
G`F{Yam!?7h
delta 1075
zcmZuvO-vI(6rS1bZny1je}GE2#Zt;oDJl{qDxrV}BOwM7gL=S(wP6>9lpm*CV@wSk
zICwCo&AVuVrbYuX95izBqKP+eKx)9AhzBnw2BIfV&TMUs!O70sH}Cu2?7r{4PtDK6
z?lnbmBDzv%!c$MgygPt*^Rb~0j5uV7bjx&OLs`WLt7jjxchs92Q^VbY{UI#6=k;Nz|Z?OmRwt%QmZaM?6Y*EKq*o^1%xz+_cg
zdSHbzF@B6=7?gS-rbHnpx>=o7AqxW4Aj(32WvPbjG}&5ZR=18zd3EV$7MBS)`Rkgxkqf#vpCf
zCoyK&ZNzIqX){U8KU$R>Q`0F!)01Yhsu*L|Q*$>sJi9PY%nOv!nVP4~vHAo{E}^@T
z;^}A9ETMf71;a)4#E#m%t#)szJw>%=S3O!(yLQyXwwl;d2a4*z9*oG%Fd-j19zFHC
zcdMzt*wk+|b5D|KOLwG}ZK-8TYAZ@@o0W%z;EntaN8y&z;InGBrwyyfI8OrbR0)e#
z1O4zpX~rkvt8yKOV94Fk=wUUmX(bV6*xwS?E~_r$hn(9VRO#6ogLCCEU_)t5rVQ`h
zGe=}0wvVVe;E^aVU)|?eAPj?^9+?e^#T<>-!lGvag5C&rK%e()8@uEsA{K-F+b=0G
wJFjO_#sIlUk8HBipAkIvUgP&r0>*s9z3uq)K00i2^^ZCaSp4UIKH@sz_CT$ZwpuAFBJI>YK6mi$IH%uE#TP
z-n=*S=FPk}Z|1KJ4fP1V*x$S7K8+ys4_dLm+A6U3696xegd|Qy87|3j6b`6?Oii+e
z!8K|y6H0~{98|-Z+GH(*Ln_YHCF>X*R_im7WQ4)BDxYacHZT~gjhSdN%Ao*~L+}^i
z&&f@%ID}rqzw#{}v!TLq8}gP?ouB@{)gA^AN;W4?1kep6)vqHdBG<~zuYxch{3~Db
zq{PplM8i8;O>kE5c1l~I<&2uspsZJODe0~~+;+c=&>z@dI*YWat^SJDe9lDSQCi!f6DVVbPuVM=rA
ziWgi~9(v7jX@$@Qcy`>~*=KB3QSImd0@=UT&<<|+-QrfCfxArHRl@NijvIK$#6vnB
zDxYlM2tJRL+fPFgEw`S6qM_W<0R_L)bJgg%X7*g$2%7kG8S}sAzvVY)4cu;7%abfx4@Ya-Gsy+5<6>
z&nBt8FqY~!0X8B;q^%Eav#9!$iK)=VM<$YJb}xJz=OG7!LJ35
zwz+fvuzp-Ud{{rOPCl%k|Ly-A4IZEs$2T78JsrIr!0mX?L%AJo9l-5))I+%)9qs34
zJ~%Y>jtcjVQoW(gRgDrFQkl?xY-hCF0^%^@TJk3Fk2JUvF^0Tx0{UiVY7W0s?nX3y@hjs$bFZC
zN`!h)-o!m6e7T4(8~BQeuju#+MK_qZw}i)vc+9}#CLY)EI7LTI+*iWmMLcfc2@_A~
zc;YRfBdn7|5hu3$-i#Rdl8Gd;bQk|EO5q
zcU1VD70GyAZ^1DL=*#&IaGFl=c4Q96NgSCYYzuHS4i-c?&V(AUZ)Qh5hTNGQmBXFc
zQ90b19f`wxP#>_GoD_J(_5x{#8N2cyX)UwjDks%=_?=yKG_7Z^0e{fL?`q>{<97jn
zsLJ04^1He@62BDohCa+~*G^q0y|8ykKh0t^>w|1IfvwOIQL-921y!r=33H6%1qq_l
zh1?UXv5KfVN-J8eJCSu$72yfHgA0lzCj!h>lJn4QC9thJ%wa(I;!@jLpQV&CbCv(Z
z4I2yJM4v}DqUA``jCAdy=DK*97oJa*_^u+~W$-;F-=p(AfHV2765m(k`wV`-5Gx8XL+Ce!
zew`(6yD9XQghWwD7{ahA4C^fU2?k2Sa8VdGgb`C1(S?z6Y|t}T<~R?Itm($^yUYEN
zHNCsC`xxASDhF?ZBcs4Z&e275k4LMXtu7;acEWQ?y6Bsf<0NEjh%UQg;8qj2>UMfx
zPHK$Q4E8QT_JTSzC@WvVadkF^mit{blbxG_9ZH9_g7Q;2y?~f|s2)z}vt1*o+^M8X3Zh7`^HxLQ+
z@1g^;_NLG;c9D|}pm6=#>_+VC2kQ@Z11CfA!tq@Mg`53YgTm2jS>?1TNI?A*di2*3Fpa*i@zxEmrLkymP6_7xdPLtj60bGvH$`p1Gra
zk|T0OUrjC&9>8)rHBYGDwLJLy%)8|Y^{3Wpcm=4eME(qbmA5b@J70MkJ70M!XmhXI
z@WypUVGm^NnqPS-=dpUq-jHMJjOlTHf
z%qdwqXRFcOgY;F;;zXvDA5cX>Gzk3}k5?u#L1v*!jUW$im}s|#eBtG
zjN-aKl~F?Xr!u;s`_o%=R`;he8rA)&j4tT@^tSo*=BHcvt$bm$FuIMupLjW8#x9j&
z9~WaE>%aWmh|QR>8KY~~?3y*2@0!hb4b-&OxXJB?KjJvpDF^499b4HSS=CP%w4<
E2gkOg)c^nh
delta 1312
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
literal 0
HcmV?d00001
diff --git a/crystalfly/ui/__pycache__/vtk_viewer.cpython-311.pyc b/crystalfly/ui/__pycache__/vtk_viewer.cpython-311.pyc
index 0affa0639e928a91085e6378c92c91f4e71fac82..cf38fd90fe3f692ed6b827f6c3b8cf3463b03631 100644
GIT binary patch
delta 2086
zcma)6Uu+ab7@ygHw|9Gc2lQ&M*FRiKDPAnsKoNu#trRSV|CC^|FPnp%)`h*hI=cth
zG-)3itxAH;VCs{(2SteSfshyQjD~|Wa@oWLAK|Hr5Tg(J%^ufs*hFW)`R#mv
zX1;H}`DVWCy1ps)sjf#5v~Ay{$KKNBW69}vfm=Wpvao{;41d89@}ePPE)yLoFB@`R
zF_eIpoKRjh)L<+-;e5o1~Z2c_G$8JJ~vKI+T=W;^Ivb?CHUPdy5SOai}avfAjioBB`&Oz^Xy{5ZvvZO
z;!!78Ag|fhIPvE1_f5YJ5xfmqAwfnAK|n+#(iIHxLa#MLwlI;#ggG>ZEnzllD3&;j
zjF2S(s+J5GwiFV1Y!Lzr4fyDoV5zf`q0gZU*oeV~!+z}Ki33l>?`PCEN;!+>3f^g<
z?hgJEbe^pT`$75vUO*mZ*VQCz4fiB4n!;1aTsEIVWs$wC^+ZiRD`=hu)~TqeEDPdX
zkTli0U<#dCwl0VH^rRV73pW7e^0=(AZ*Mmez*Q5tO0uuSoh=Dpc1sh4`l@N#1=}-C8V6$*lDZN+
z6hCV7QZUa2wLrscP`ZSp><6j0L-Zw=IAejmA2!X?PR?~r)8$D`v#`8>Bmtwzmd4}A
z*8QvjrTZJeA2aA@RevXRF?2^w-d2;h)YPJys;H@IGCe0<)bFx+Ik8qn9euajH!rqt
zo|6{U)`trFLVizvm_XsS8+(;~SZRT!XfwMMYR1p7PeL17H-NyGgYaE`lIb+v$ZfjW
zFQE?H$NmmY;@%sR>I}v$?5}X!wmv>V9VOl;mOJ=>P}rj&1{J
zbkoVck7l)@IbSTfWbewf;Gvo9d8!UpwHgMeZeJJR463S8sDnG|`rGRIvh=ZjOU*8-*-D)#
z-%lpaw!}6L@Ll+#UGV4-j3}==+RcF<67A%`uOi*eLFTZBO~jg~gM{%nXsDL17*}!7
zp}XG!KylW;Y9jUiD<2NbAGmyA=FpOql811)X$kTFf8YzUoLWN55R>FhO9+77i|v|L
zvD|;PZ3)5ee?YM7AjC|<-v|$GzG#&k;%0;QxnL1$7siK+1&>_tj!clk$ic0CWW~&n
z9es1uw#fGEF>km?2^CvmlfJ$p9VywhT*>T2Jc|`}HQpHwo>LkEQ>ucXM+x&;Y4&-%
zHCB7)UCN&zs<9vA8>XXt$kTWY>XncAz57!gti}2wJq|3-y89Erl87=8v4^zMSCiZR7F;0HM)xiD~+_I?7(m~|AtC)|F2y9d!sHA
I*akcQ2Tf@O;{X5v
delta 1442
zcmZ`&UuYaf7@yg{bGO;eU0S)#d3U|Gx!9xLmC%}pQfjEwD8*pB5@EqEF*}h9dl#L(
zBy9;KLePjp2&3jr0)nOZB<+I_KIpSAml9}M6#AeK5rh-1h!4eY_OfXXb#CT&-=Fz@
z^L^jUe)Y`P$E{nYnM5#_FBWF!$fjklTmx+jdC0>)YG4OrAxpm0kR3UaWnXEijvC2|
zuQhZ>k7U&+jf9iHNJ8Vt)7FruQ~3)Sp)X-|hm-V34V4pnLM`Lan0YsAZ+H8TE
zot(P5xo2a{2XTeJi%+kN!M^t)9f}<6AxBzAv)IFH#F0H|4LOP@1FD_^sCg>YXS+MJ
zwLXWeqwCm7z;SwLOge=khhcIJgUHcov+GI
zW1U}<3z~<)(8s@x4U#AEZ{%aflQ0XyPGm7^6=GI|=2Ee|osL-tfYs(MQTdi~Zv057
z1`BUf782L3H|s6e4g1Gw>owZ+D0{u$^yZgBlSP`l6sb&98TQph3*E)2hfL!cbptZJ
zr4DDLPzk6%8zx+L#-9!X*A1YVi2tI#L@f|*W_mB68Xw#T&Op3|zgE$Y#QZ@2NWV|)
zd&J%$*wfXk2I8jb|+Wa%~gax_=xb&v=8N^a(R&p
zJ10OqlKtq_ZoQ-YJF9?4_(SVCtq9(7k{42?6>()OCm&J>}aR3-9i6`
Q_ETqm6Xrku!xts`4?ST{NdN!<
diff --git a/crystalfly/ui/ctk.cpp b/crystalfly/ui/ctk.cpp
new file mode 100644
index 0000000..2d8c4f3
--- /dev/null
+++ b/crystalfly/ui/ctk.cpp
@@ -0,0 +1,112 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+//#include
+
+//VTK_MODULE_INIT( vtkRenderingOpenGL2 );
+//VTK_MODULE_INIT( vtkRenderingVolumeOpenGL2 );
+int main()
+{
+
+ //raw data reader
+
+ vtkSmartPointer reader = vtkSmartPointer::New();
+
+ reader->SetFileName("/home/wjm/code/p_volume_rendering/data/marschner_lobb_41x41x41_uint8.raw");
+ reader->SetFileDimensionality(3);//设置显示图像的维数
+ reader->SetDataScalarType(VTK_UNSIGNED_CHAR);//VTK_UNSIGNED_short将数据转换为unsigned char型
+ reader->SetDataExtent(0, 40, 0, 40, 0, 40);
+ reader->SetDataSpacing(1, 1, 1); //设置像素间间距
+ //reader->SetDataOrigin(0.0, 0.0, 0.0);//设置基准点,(一般没有用)做虚拟切片时可能会用的上
+ reader->Update();
+
+
+
+
+ //visualize the raw data
+
+
+ // properties options
+ vtkNew volumeProperty;
+ volumeProperty->ShadeOn();
+ volumeProperty->SetInterpolationType(VTK_LINEAR_INTERPOLATION);
+
+ // get the real range in hounsfield
+ vtkDataArray *arr = reader->GetOutput()->GetPointData()->GetScalars();
+ double range[2];
+ arr->GetRange(range);
+
+ // 1D transfer functions
+ vtkNew colorTF;
+ colorTF->AddRGBPoint(-200, 0.0, 0.0, 0.0);
+ colorTF->AddRGBPoint(110, 0.4, 0.4, 1.0);
+ colorTF->AddRGBPoint(512, 1.0, 1.0, 1.0);
+ colorTF->AddRGBPoint(range[1], 0.9, 0.1, 0.3);
+
+ vtkNew scalarTF;
+ //scalarTF->AddPoint(-200, 0.00);
+ scalarTF->AddPoint(-255, 0.00);
+ scalarTF->AddPoint(110, 0.00);
+ scalarTF->AddPoint(512, 0.5);
+ scalarTF->AddPoint(range[1], 0.9);
+
+ vtkNew gradientTF;
+ gradientTF->AddPoint(-200, 0.0);
+ gradientTF->AddPoint(range[1] / 4.0, 1.0);
+
+ volumeProperty->SetScalarOpacity(scalarTF);
+ volumeProperty->SetGradientOpacity(gradientTF);
+ volumeProperty->SetColor(colorTF);
+
+ // setup rendering context
+ vtkNew renderWindow;
+ renderWindow->SetSize(512, 512);
+ renderWindow->SetMultiSamples(0);
+
+ // mapping data
+ vtkNew mapper;
+ mapper->SetInputConnection(reader->GetOutputPort());
+ mapper->SetBlendModeToComposite();
+ mapper->SetUseJittering(1);
+
+ // renderer and volume
+ vtkNew renderer;
+ renderWindow->AddRenderer(renderer);
+ renderer->SetBackground(0.03, 0.33, 0.33);
+
+ vtkNew volume;
+ volume->SetMapper(mapper);
+ volume->SetProperty(volumeProperty);
+ renderer->AddVolume(volume);
+
+ renderer->ResetCamera();
+ renderer->GetActiveCamera()->Zoom(1.3);
+
+ vtkNew interactor;
+ interactor->SetRenderWindow(renderWindow);
+
+ vtkNew style;
+ interactor->SetInteractorStyle(style);
+
+ renderWindow->Render();
+
+ interactor->Start();
+
+
+ return 0;
+
+}
diff --git a/crystalfly/ui/import_file.py b/crystalfly/ui/import_file.py
index 718710e..e4d17ed 100644
--- a/crystalfly/ui/import_file.py
+++ b/crystalfly/ui/import_file.py
@@ -3,6 +3,8 @@ from pathlib import Path
from PySide6.QtCore import Slot, QEvent
from PySide6.QtUiTools import loadUiType
from PySide6.QtWidgets import QDialog, QFileDialog
+from vtkmodules.vtkCommonCore import VTK_INT, VTK_SHORT, VTK_LONG, VTK_FLOAT, VTK_UNSIGNED_SHORT, VTK_UNSIGNED_INT, \
+ VTK_UNSIGNED_LONG
from crystalfly.thread.image_reader import ImageReaderThread
@@ -12,7 +14,7 @@ ImportFileType, _ = loadUiType(str(Path(__file__).parent.joinpath("import_file.u
class ImportFile(QDialog, ImportFileType):
def __init__(self):
super(ImportFile, self).__init__()
- self.image_read_thread = None
+ # self.image_read_thread = None
self.setupUi(self)
self.browse_file.clicked.connect(self.browse_file_handler)
@@ -30,19 +32,34 @@ class ImportFile(QDialog, ImportFileType):
@Slot()
def load_image_file(self):
+ data_type_text = self.data_type_combobox.currentText()
+ data_type = None
+ if data_type_text == "int 8":
+ data_type = VTK_INT
+ elif data_type_text == "uint 8":
+ data_type = VTK_UNSIGNED_INT
+ elif data_type_text == "int 16":
+ data_type = VTK_SHORT
+ elif data_type_text == "uint 16":
+ data_type = VTK_UNSIGNED_SHORT
+ elif data_type_text == "int 32":
+ data_type = VTK_LONG
+ elif data_type_text == "uint 32":
+ data_type = VTK_UNSIGNED_LONG
+ elif data_type_text == "float":
+ data_type = VTK_FLOAT
file_data = {
"file_path": self.file_path_input.text(),
- "data_type": self.data_type_combobox.currentText(),
+ "data_type": data_type,
"size": {
"x": self.size_x_spin.value(),
"y": self.size_y_spin.value(),
"z": self.size_z_spin.value(),
}
}
- self.image_read_thread = ImageReaderThread(file_data)
+ image_read_thread = ImageReaderThread(file_data, self)
# self.image_read_thread.loadedSignal.connect(self.set_image)
- self.image_read_thread.start()
-
+ image_read_thread.start()
@Slot()
def browse_file_handler(self):
diff --git a/crystalfly/ui/main_window.py b/crystalfly/ui/main_window.py
index 721cb27..bd375e6 100644
--- a/crystalfly/ui/main_window.py
+++ b/crystalfly/ui/main_window.py
@@ -3,8 +3,10 @@ from pathlib import Path
from PySide6.QtCore import Slot
from PySide6.QtUiTools import loadUiType
from PySide6.QtWidgets import QMainWindow
+from vtkmodules.vtkRenderingOpenGL2 import vtkGenericOpenGLRenderWindow
from crystalfly.ui.import_file import ImportFile
+from crystalfly.ui.volume_viewer import VolumeViewer
from crystalfly.ui.vtk_viewer import VTKImageViewer
MainWindowType, _ = loadUiType(str(Path(__file__).parent.joinpath("main_window.ui")))
@@ -13,22 +15,60 @@ MainWindowType, _ = loadUiType(str(Path(__file__).parent.joinpath("main_window.u
class MainWindow(QMainWindow, MainWindowType):
def __init__(self):
super(MainWindow, self).__init__()
+ self.volume = None
+ self.transverse = None
+ self.sagittal = None
+ self.coronal = None
+ self.vtk_render_window = vtkGenericOpenGLRenderWindow()
self.setupUi(self)
self.file_open_dialog = ImportFile()
self.file_open.triggered.connect(self.handle_file_open)
self.init_four_pane()
+ self.is_pane_maximum = False
def init_four_pane(self):
- coronal = VTKImageViewer()
- coronal.image_viewer.SetSliceOrientationToYZ()
- sagittal = VTKImageViewer()
- sagittal.image_viewer.SetSliceOrientationToXZ()
- transverse = VTKImageViewer()
- transverse.image_viewer.SetSliceOrientationToXY()
+ self.coronal = VTKImageViewer(1)
+ self.sagittal = VTKImageViewer(3)
+ self.transverse = VTKImageViewer(4)
+ self.volume = VolumeViewer(2)
+ self.coronal.image_viewer.SetSliceOrientationToYZ()
+ self.sagittal.image_viewer.SetSliceOrientationToXZ()
+ self.transverse.image_viewer.SetSliceOrientationToXY()
+
+ self.volume.doubleClicked.connect(self.cell_max)
+ self.coronal.doubleClicked.connect(self.cell_max)
+ self.sagittal.doubleClicked.connect(self.cell_max)
+ self.transverse.doubleClicked.connect(self.cell_max)
# self.gridLayout.addWidget()
- self.gridLayout_2.addWidget(coronal)
- self.gridLayout_3.addWidget(sagittal)
- self.gridLayout_4.addWidget(transverse)
+ self.volume_grid_layout.addWidget(self.volume)
+ self.coronal_grid_layout.addWidget(self.coronal)
+ self.gridLayout_3.addWidget(self.sagittal)
+ self.gridLayout_4.addWidget(self.transverse)
+
+ @Slot(int)
+ def cell_max(self, quadrant: int):
+ print(quadrant)
+ if self.is_pane_maximum:
+ self.widget_3d.show()
+ self.widget_coronal.show()
+ self.widget_sagittal.show()
+ self.widget_transverse.show()
+ self.is_pane_maximum = False
+ else:
+ self.widget_3d.hide()
+ self.widget_coronal.hide()
+ self.widget_sagittal.hide()
+ self.widget_transverse.hide()
+ print(quadrant)
+ if quadrant == 1:
+ self.widget_coronal.show()
+ elif quadrant == 2:
+ self.widget_3d.show()
+ elif quadrant == 3:
+ self.widget_sagittal.show()
+ elif quadrant == 4:
+ self.widget_transverse.show()
+ self.is_pane_maximum = True
@Slot()
def cell_click(self):
diff --git a/crystalfly/ui/main_window.ui b/crystalfly/ui/main_window.ui
index d74ebec..04d9314 100644
--- a/crystalfly/ui/main_window.ui
+++ b/crystalfly/ui/main_window.ui
@@ -40,11 +40,11 @@
0
-
-
+
border: 1px solid rgb(195, 195, 195);
-
+
1
@@ -61,12 +61,12 @@
-
-
+
border: 1px solid rgb(195, 195, 195);
margin-left: -1px;
-
+
1
@@ -83,7 +83,7 @@ margin-left: -1px;
-
-
+
border: 1px solid rgb(195, 195, 195);
margin-left: -1px;
@@ -106,7 +106,7 @@ margin-top: -1px;
-
-
+
border: 1px solid rgb(195, 195, 195);
margin-top: -1px;
diff --git a/crystalfly/ui/volume_viewer.py b/crystalfly/ui/volume_viewer.py
new file mode 100644
index 0000000..190c1e7
--- /dev/null
+++ b/crystalfly/ui/volume_viewer.py
@@ -0,0 +1,77 @@
+# noinspection PyUnresolvedReferences
+import vtkmodules.vtkRenderingContextOpenGL2
+from PySide6.QtCore import Signal
+from PySide6.QtGui import QMouseEvent
+from vtkmodules.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
+from vtkmodules.vtkCommonDataModel import vtkPiecewiseFunction
+from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera
+from vtkmodules.vtkRenderingCore import vtkVolume, vtkVolumeProperty, vtkRenderer, vtkColorTransferFunction
+from vtkmodules.vtkRenderingVolume import vtkGPUVolumeRayCastMapper
+# noinspection PyUnresolvedReferences
+from vtkmodules.vtkRenderingVolumeOpenGL2 import vtkSmartVolumeMapper
+
+from crystalfly.model.image_reader import image_reader_model
+
+
+class VolumeViewer(QVTKRenderWindowInteractor):
+ doubleClicked = Signal(int)
+
+ def __init__(self, quadrant: int):
+ super().__init__()
+ self.quadrant = quadrant
+ self.render_window = self.GetRenderWindow()
+ self.render_window.SetMultiSamples(0)
+
+ self.render_window.AddRenderer(vtkRenderer())
+ self.renderer = self.render_window.GetRenderers().GetFirstRenderer()
+ # self.iren = vtkRenderWindowInteractor()
+ # self.iren.SetRenderWindow(self.render_window)
+
+ self.volume_mapper = vtkGPUVolumeRayCastMapper()
+ self.volume_mapper.SetBlendModeToComposite()
+ self.volume_mapper.SetUseJittering(1)
+
+ self.colorTF = vtkColorTransferFunction()
+ self.colorTF.AddRGBPoint(-200, 0.0, 0.0, 0.0)
+ self.colorTF.AddRGBPoint(110, 0.4, 0.4, 1.0)
+ self.colorTF.AddRGBPoint(512, 1.0, 1.0, 1.0)
+
+ self.scalarTF = vtkPiecewiseFunction()
+ self.scalarTF.AddPoint(-255, 0.00)
+ self.scalarTF.AddPoint(110, 0.00)
+ self.scalarTF.AddPoint(512, 0.5)
+
+ self.volume_property = vtkVolumeProperty()
+ self.volume_property.ShadeOn()
+ self.volume_property.SetInterpolationTypeToLinear()
+ self.volume_property.SetColor(self.colorTF)
+ self.volume_property.SetScalarOpacity(self.scalarTF)
+
+ self.volume = vtkVolume()
+ self.volume.SetMapper(self.volume_mapper)
+ self.volume.SetProperty(self.volume_property)
+
+ self.renderer.ResetCamera()
+ self.renderer.GetActiveCamera().Zoom(1.3)
+
+ self.interactor_style = vtkInteractorStyleTrackballCamera()
+ self.iren = self.render_window.GetInteractor()
+ # self.iren.SetRenderWindow(self.render_window)
+ self.iren.SetInteractorStyle(self.interactor_style)
+ self.iren.Initialize()
+
+ self.renderer.AddVolume(self.volume)
+ image_reader_model.loadedSignal.connect(self.set_image)
+ self.renderer.SetBackground(0.3, 0.3, 0.3)
+ self.renderer.SetBackgroundAlpha(0.4)
+
+ def set_image(self, image):
+ self.volume_mapper.SetInputData(image)
+ self.iren.SetRenderWindow(self.render_window)
+ self.render_window.Render()
+ self.volume.Update()
+ # self.volume_mapper.Render()
+
+ def mouseDoubleClickEvent(self, evt: QMouseEvent):
+ print(evt, self.quadrant)
+ self.doubleClicked.emit(self.quadrant)
diff --git a/crystalfly/ui/vtk_viewer.py b/crystalfly/ui/vtk_viewer.py
index fe14dd9..b2e1a17 100644
--- a/crystalfly/ui/vtk_viewer.py
+++ b/crystalfly/ui/vtk_viewer.py
@@ -1,21 +1,27 @@
# noinspection PyUnresolvedReferences
-# import vtkmodules.vtkRenderingContextOpenGL2
-from PySide6.QtGui import QCloseEvent
+import vtkmodules.vtkRenderingContextOpenGL2
+from PySide6.QtCore import Signal
+from PySide6.QtGui import QCloseEvent, QMouseEvent
from vtkmodules.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
-from vtkmodules.vtkInteractionImage import vtkImageViewer2
+from vtkmodules.vtkInteractionImage import vtkResliceImageViewer, vtkImageViewer2
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleImage
+from vtkmodules.vtkInteractionWidgets import vtkResliceCursorLineRepresentation, vtkImagePlaneWidget
from crystalfly.model.image_reader import image_reader_model
class VTKImageViewer(QVTKRenderWindowInteractor):
- def __init__(self):
+ doubleClicked = Signal(int)
+
+ def __init__(self, quadrant: int):
super().__init__()
+ self.quadrant = quadrant
+ # self.render_window = render_window
self.render_window = self.GetRenderWindow()
# image viewer
+ # self.image_viewer = vtkResliceImageViewer()
self.image_viewer = vtkImageViewer2()
- # self.image_viewer.SetRenderWindow(self.render_window)
# 交互
self.interactor_style = vtkInteractorStyleImage()
@@ -25,6 +31,14 @@ class VTKImageViewer(QVTKRenderWindowInteractor):
self.interactor_style.AddObserver("MouseWheelBackwardEvent", self.mouse_wheel_backward_event)
self.iren.Initialize()
+ # rep = vtkResliceCursorLineRepresentation.SafeDownCast(
+ # self.image_viewer.GetResliceCursorWidget().GetRepresentation())
+ # # self.image_viewer.
+ # rep.GetResliceCursorActor().GetCursorAlgorithm().SetReslicePlaneNormal(0)
+ #
+ # plane_widget = vtkImagePlaneWidget()
+ # plane_widget.SetInteractor(self.iren)
+ # plane_widget.On()
image_reader_model.loadedSignal.connect(self.set_image)
def set_image(self, image):
@@ -49,3 +63,6 @@ class VTKImageViewer(QVTKRenderWindowInteractor):
def closeEvent(self, evt: QCloseEvent):
super().closeEvent(evt)
self.Finalize()
+
+ def mouseDoubleClickEvent(self, evt: QMouseEvent):
+ self.doubleClicked.emit(self.quadrant)
|