This commit is contained in:
quantulr
2024-04-16 17:31:12 +08:00
commit 0c8e503d2f
30 changed files with 1265 additions and 0 deletions

0
crystalfly/__init__.py Normal file
View File

Binary file not shown.

16
crystalfly/main.py Normal file
View File

@ -0,0 +1,16 @@
import sys
from PySide6.QtWidgets import QApplication
from crystalfly.ui.main_window import MainWindow
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
if __name__ == '__main__':
main()

View File

Binary file not shown.

View File

@ -0,0 +1,16 @@
from typing import Any
from PySide6.QtCore import QObject, Signal
class ImageReaderModel(QObject):
loadedSignal = Signal(Any)
def __init__(self):
super().__init__()
def loaded(self, image):
self.loadedSignal.emit(image)
image_reader_model = ImageReaderModel()

View File

Binary file not shown.

View File

@ -0,0 +1,34 @@
from typing import Any
from PySide6.QtCore import QThread, Signal
from vtkmodules.vtkIOImage import vtkMedicalImageReader2
from crystalfly.model.image_reader import image_reader_model
class ImageReaderThread(QThread):
loadedSignal = Signal(Any)
def __init__(self, file_data):
QThread.__init__(self)
self.file_data = file_data
def run(self):
reader = vtkMedicalImageReader2()
reader.SetFileName(self.file_data["file_path"])
reader.SetFileDimensionality(3)
reader.SetDataSpacing(0.1, 0.1, 0.1)
print(self.file_data)
reader.SetDataExtent(
0,
self.file_data["size"]["x"] - 1,
0,
self.file_data["size"]["y"] - 1,
0,
self.file_data["size"]["z"] - 1,
)
# self.file_data["data_type"]
reader.SetDataScalarTypeToUnsignedShort()
reader.Update()
image_reader_model.loaded(reader.GetOutput())
print("success")

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,52 @@
from pathlib import Path
from PySide6.QtCore import Slot, QEvent
from PySide6.QtUiTools import loadUiType
from PySide6.QtWidgets import QDialog, QFileDialog
from crystalfly.thread.image_reader import ImageReaderThread
ImportFileType, _ = loadUiType(str(Path(__file__).parent.joinpath("import_file.ui")))
class ImportFile(QDialog, ImportFileType):
def __init__(self):
super(ImportFile, self).__init__()
self.image_read_thread = None
self.setupUi(self)
self.browse_file.clicked.connect(self.browse_file_handler)
self.accepted.connect(self.load_image_file)
def showEvent(self, event: QEvent) -> None:
self.clear_form()
def clear_form(self):
self.file_path_input.clear()
self.size_x_spin.clear()
self.size_y_spin.clear()
self.size_z_spin.clear()
self.data_type_combobox.setCurrentIndex(0)
@Slot()
def load_image_file(self):
file_data = {
"file_path": self.file_path_input.text(),
"data_type": self.data_type_combobox.currentText(),
"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)
# self.image_read_thread.loadedSignal.connect(self.set_image)
self.image_read_thread.start()
@Slot()
def browse_file_handler(self):
dialog = QFileDialog(self)
filepath = dialog.getOpenFileName()
if filepath[0]:
self.file_path_input.setText(filepath[0])

View File

@ -0,0 +1,208 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>500</width>
<height>259</height>
</rect>
</property>
<property name="windowTitle">
<string>文件导入</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout" columnstretch="1,5,1">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>文件路径</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="file_path_input"/>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="browse_file">
<property name="text">
<string>浏览</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="title">
<string>size</string>
</property>
<layout class="QGridLayout" name="gridLayout_2" columnstretch="1,3,1,3">
<property name="horizontalSpacing">
<number>32</number>
</property>
<item row="0" column="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>y</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="size_x_spin">
<property name="maximum">
<number>100000</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>x</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QSpinBox" name="size_y_spin">
<property name="maximum">
<number>100000</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>z</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="size_z_spin">
<property name="maximum">
<number>100000</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_3" columnstretch="1,6">
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>数据类型</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="data_type_combobox">
<property name="editable">
<bool>false</bool>
</property>
<item>
<property name="text">
<string>int 8</string>
</property>
</item>
<item>
<property name="text">
<string>uint 8</string>
</property>
</item>
<item>
<property name="text">
<string>int 16</string>
</property>
</item>
<item>
<property name="text">
<string>uint 16</string>
</property>
</item>
<item>
<property name="text">
<string>int 32</string>
</property>
</item>
<item>
<property name="text">
<string>uint 32</string>
</property>
</item>
<item>
<property name="text">
<string>float</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Dialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Dialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,39 @@
from pathlib import Path
from PySide6.QtCore import Slot
from PySide6.QtUiTools import loadUiType
from PySide6.QtWidgets import QMainWindow
from crystalfly.ui.import_file import ImportFile
from crystalfly.ui.vtk_viewer import VTKImageViewer
MainWindowType, _ = loadUiType(str(Path(__file__).parent.joinpath("main_window.ui")))
class MainWindow(QMainWindow, MainWindowType):
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
self.file_open_dialog = ImportFile()
self.file_open.triggered.connect(self.handle_file_open)
self.init_four_pane()
def init_four_pane(self):
coronal = VTKImageViewer()
coronal.image_viewer.SetSliceOrientationToYZ()
sagittal = VTKImageViewer()
sagittal.image_viewer.SetSliceOrientationToXZ()
transverse = VTKImageViewer()
transverse.image_viewer.SetSliceOrientationToXY()
# self.gridLayout.addWidget()
self.gridLayout_2.addWidget(coronal)
self.gridLayout_3.addWidget(sagittal)
self.gridLayout_4.addWidget(transverse)
@Slot()
def cell_click(self):
print("clicked")
@Slot()
def handle_file_open(self):
self.file_open_dialog.exec()

View File

@ -0,0 +1,166 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Crystalfly</string>
</property>
<property name="styleSheet">
<string notr="true"># background-color: rgb(50, 50, 50);</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,4">
<item>
<widget class="QWidget" name="widget" native="true">
<property name="styleSheet">
<string notr="true">border-color: rgb(195, 195, 195);</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>工具栏</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QGridLayout" name="four_pane_grid">
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="1">
<widget class="QWidget" name="widget_2" native="true">
<property name="styleSheet">
<string notr="true">border: 1px solid rgb(195, 195, 195);</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
</layout>
</widget>
</item>
<item row="0" column="2">
<widget class="QWidget" name="widget_3" native="true">
<property name="styleSheet">
<string notr="true">border: 1px solid rgb(195, 195, 195);
margin-left: -1px;</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
</layout>
</widget>
</item>
<item row="1" column="2">
<widget class="QWidget" name="widget_5" native="true">
<property name="styleSheet">
<string notr="true">border: 1px solid rgb(195, 195, 195);
margin-left: -1px;
margin-top: -1px;</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QWidget" name="widget_4" native="true">
<property name="styleSheet">
<string notr="true">border: 1px solid rgb(195, 195, 195);
margin-top: -1px;</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menu">
<property name="title">
<string>文件</string>
</property>
<addaction name="file_open"/>
</widget>
<widget class="QMenu" name="menu_2">
<property name="title">
<string>工具</string>
</property>
</widget>
<addaction name="menu"/>
<addaction name="menu_2"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="file_open">
<property name="text">
<string>打开</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,51 @@
# noinspection PyUnresolvedReferences
# import vtkmodules.vtkRenderingContextOpenGL2
from PySide6.QtGui import QCloseEvent
from vtkmodules.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
from vtkmodules.vtkInteractionImage import vtkImageViewer2
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleImage
from crystalfly.model.image_reader import image_reader_model
class VTKImageViewer(QVTKRenderWindowInteractor):
def __init__(self):
super().__init__()
self.render_window = self.GetRenderWindow()
# image viewer
self.image_viewer = vtkImageViewer2()
# self.image_viewer.SetRenderWindow(self.render_window)
# 交互
self.interactor_style = vtkInteractorStyleImage()
self.iren = self.render_window.GetInteractor()
self.iren.SetInteractorStyle(self.interactor_style)
self.interactor_style.AddObserver("MouseWheelForwardEvent", self.mouse_wheel_forward_event)
self.interactor_style.AddObserver("MouseWheelBackwardEvent", self.mouse_wheel_backward_event)
self.iren.Initialize()
image_reader_model.loadedSignal.connect(self.set_image)
def set_image(self, image):
if self.image_viewer.GetRenderWindow() is not None:
self.image_viewer.SetRenderWindow(self.render_window)
self.image_viewer.SetInputData(image)
self.image_viewer.Render()
print("setImage")
def mouse_wheel_forward_event(self, a, b):
if self.image_viewer.GetSlice() < self.image_viewer.GetSliceMax():
print(self.image_viewer.GetSlice())
self.image_viewer.SetSlice(self.image_viewer.GetSlice() + 1)
self.image_viewer.Render()
def mouse_wheel_backward_event(self, a, b):
if self.image_viewer.GetSlice() > self.image_viewer.GetSliceMin():
print(self.image_viewer.GetSlice())
self.image_viewer.SetSlice(self.image_viewer.GetSlice() - 1)
self.image_viewer.Render()
def closeEvent(self, evt: QCloseEvent):
super().closeEvent(evt)
self.Finalize()