├── .gitignore ├── LICENSE ├── README.md ├── resources ├── evolution.gif ├── heart.png ├── initial_contour.gif ├── preprocessing.gif ├── schematic_1.png ├── schematic_2.png └── schematic_3.png └── src ├── CMakeLists.txt ├── GUI ├── GACControlPanel.cpp ├── GACControlPanel.h ├── GACControlPanel.ui ├── Thumbnail.cpp ├── Thumbnail.h ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── vtkImageInteractionCallback.cpp └── vtkImageInteractionCallback.h ├── Logic ├── GACDriver.cpp ├── GACDriver.h ├── MyThread.cpp └── MyThread.h ├── Model ├── GACParameters.cpp ├── GACParameters.h ├── ImageData.cpp └── ImageData.h ├── main.cpp ├── resources ├── iconfinder_pause_2561367.svg ├── iconfinder_play_2561370.svg ├── iconfinder_rewind_2561378.svg └── iconfinder_skip-forward_2561275.svg └── test.png /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Wen-Ya Lin (林温雅) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | Spoken-Digit Recognizer 4 | 5 |

Level-Set Visualizer

6 |
7 | Visualize image segmentation based on level set method. 8 |
9 |

10 | 11 |

12 | 13 | 14 | 15 | 16 | 17 |

18 | 19 | 20 | ## Table of contents 21 | * [Application Demo](#application-demo) 22 | * [Introduction](#introduction) 23 | * [Built With](#built-with) 24 | * [Installation](#installation) 25 | * [Acknowledgments](#acknowledgments) 26 | 27 | ## Application Demo 28 | ### [Level-Set Visualizer – Demo (YouTube)](https://www.youtube.com/watch?v=uTrr98JsRps) 29 | 30 | ## Introduction 31 | This application perform image segmentation by following steps: 32 | 33 | * Load Image & Start Level-Set Mode 34 | * Preprocessing 35 | * Initial Contour 36 | * Start Evolution 37 | 38 | 39 | ### Preprocessing 40 | - Edge detection by [Anisotropic Diffusion](https://itk.org/Doxygen/html/classitk_1_1CurvatureAnisotropicDiffusionImageFilter.html), [Gaussian Gradient](https://itk.org/Doxygen/html/classitk_1_1GradientMagnitudeRecursiveGaussianImageFilter.html), [Sigmoid Scaling](https://itk.org/Doxygen/html/classitk_1_1SigmoidImageFilter.html) 41 | - Control over some edge detection parameters 42 | 43 | 44 |

45 | preprocessing 46 |

47 | 48 | ### Initial Contour 49 | - Done by [Fast Marching](https://itk.org/Doxygen/html/classitk_1_1FastMarchingImageFilter.html), support multiple bubbles 50 |

51 | initial contour 52 |

53 | 54 | ### Start Evolution 55 | - Support media-like control (play/pause/step/rewind) & anchor iteration 56 | - Control over 3 parameters based on [Geodesic Active Contour (GAC)](https://itk.org/Doxygen/html/classitk_1_1GeodesicActiveContourLevelSetImageFilter.html) 57 |

58 | evolution.gif 59 |

60 | 61 | ## Built With 62 | 63 | 64 | * [ITK 4.12](https://itk.org/ITK/resources/legacy_releases.html) - Image Processing Algorithms (w/ module `ITKVtkGlue`) 65 | * [VTK 8.2](https://vtk.org/download/) - Image Display 66 | * [Qt 5.6](https://doc.qt.io/archives/qt-5.6/index.html) - GUI framework 67 | 68 | ## Installation 69 | 70 | Before running the following command, modify `QT_HOME`, `ITK_DIR`, and `VTK_DIR` in [CMakeLists.txt](https://github.com/wenyalintw/Level-Set-Visualizer/blob/master/src/CMakeLists.txt) 71 | 72 | ```sh 73 | $ mkdir build 74 | $ cd build 75 | $ cmake ../src 76 | $ make -j4 77 | ``` 78 | 79 | ## Acknowledgments 80 | - This application is inspired by [ITK-SNAP](http://www.itksnap.org/pmwiki/pmwiki.php) 81 | - Processing pipeline & [test.png](https://github.com/wenyalintw/Level-Set-Visualizer/tree/master/src/test.png) modified from [ITK GAC Example](https://itk.org/ITKExamples/src/Segmentation/LevelSets/SegmentWithGeodesicActiveContourLevelSet/Documentation.html) 82 | - [heart.png](https://github.com/wenyalintw/Level-Set-Visualizer/tree/master/resources/heart.png) modified from [ICONFINDER](https://www.iconfinder.com/icons/44697/cardiology_heart_organ_icon) 83 | 84 | ###### MIT License (2019), Wen-Ya Lin 85 | 86 | -------------------------------------------------------------------------------- /resources/evolution.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenyalintw/Level-Set-Visualizer/36646f6b24fd0386b4f82e01bcfa0bf0e88fa9eb/resources/evolution.gif -------------------------------------------------------------------------------- /resources/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenyalintw/Level-Set-Visualizer/36646f6b24fd0386b4f82e01bcfa0bf0e88fa9eb/resources/heart.png -------------------------------------------------------------------------------- /resources/initial_contour.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenyalintw/Level-Set-Visualizer/36646f6b24fd0386b4f82e01bcfa0bf0e88fa9eb/resources/initial_contour.gif -------------------------------------------------------------------------------- /resources/preprocessing.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenyalintw/Level-Set-Visualizer/36646f6b24fd0386b4f82e01bcfa0bf0e88fa9eb/resources/preprocessing.gif -------------------------------------------------------------------------------- /resources/schematic_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenyalintw/Level-Set-Visualizer/36646f6b24fd0386b4f82e01bcfa0bf0e88fa9eb/resources/schematic_1.png -------------------------------------------------------------------------------- /resources/schematic_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenyalintw/Level-Set-Visualizer/36646f6b24fd0386b4f82e01bcfa0bf0e88fa9eb/resources/schematic_2.png -------------------------------------------------------------------------------- /resources/schematic_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenyalintw/Level-Set-Visualizer/36646f6b24fd0386b4f82e01bcfa0bf0e88fa9eb/resources/schematic_3.png -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(Level-Set-Visualizer) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | 6 | 7 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") 8 | 9 | ###### Local DIR ##### 10 | set(QT_HOME "/Users/apple/Desktop/Qt5.6/5.6/clang_64") 11 | set(ITK_DIR "/usr/local/lib/cmake/ITK-4.12") 12 | set(VTK_DIR "/usr/local/lib/cmake/vtk-8.2") 13 | 14 | 15 | ### Qt 16 | set(CMAKE_PREFIX_PATH ${QT_HOME}) 17 | set(PROJECT_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) 18 | set(CMAKE_INCLUDE_CURRENT_DIR on) 19 | # AUTOMOC和自動生成ui_xxx.h有關!on了就先不要去用qt5_wrap_ui 20 | set(CMAKE_AUTOMOC on) 21 | set(CMAKE_AUTOUIC on) 22 | set(CMAKE_AUTORCC on) 23 | # 根據所需尋找所需package 24 | find_package(Qt5 REQUIRED Core Widgets UiTools Xml Network Qml Quick) 25 | 26 | ### ITK & VTK 27 | find_package(ITK REQUIRED) 28 | include(${ITK_USE_FILE}) 29 | if (ITKVtkGlue_LOADED) 30 | find_package(VTK REQUIRED) 31 | include(${VTK_USE_FILE}) 32 | else() 33 | find_package(ItkVtkGlue REQUIRED) 34 | include(${ItkVtkGlue_USE_FILE}) 35 | set(Glue ItkVtkGlue) 36 | endif() 37 | 38 | 39 | # https://stackoverflow.com/questions/13703647/how-to-properly-add-include-directories-with-cmake 40 | FILE(GLOB GUIsources 41 | ${CMAKE_SOURCE_DIR}/GUI/*.h 42 | ${CMAKE_SOURCE_DIR}/GUI/*.cpp 43 | ${CMAKE_SOURCE_DIR}/GUI/*.ui 44 | ) 45 | FILE(GLOB Modelsources 46 | ${CMAKE_SOURCE_DIR}/Model/*.h 47 | ${CMAKE_SOURCE_DIR}/Model/*.cpp 48 | ) 49 | FILE(GLOB Logicsources 50 | ${CMAKE_SOURCE_DIR}/Logic/*.h 51 | ${CMAKE_SOURCE_DIR}/Logic/*.cpp 52 | ) 53 | 54 | add_executable(${PROJECT_NAME} main.cpp ${GUIsources} ${Modelsources} ${Logicsources}) 55 | 56 | include_directories(${CMAKE_SOURCE_DIR}/GUI/) 57 | include_directories(${CMAKE_SOURCE_DIR}/Model/) 58 | include_directories(${CMAKE_SOURCE_DIR}/Logic/) 59 | 60 | target_link_libraries(${PROJECT_NAME} ${Glue} ${VTK_LIBRARIES} ${ITK_LIBRARIES}) 61 | target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Widgets Qt5::Gui Qt5::UiTools Qt5::Xml Qt5::Network Qt5::Qml Qt5::Quick) 62 | 63 | FILE(COPY resources DESTINATION ${CMAKE_BINARY_DIR}) 64 | FILE(COPY test.png DESTINATION ${CMAKE_BINARY_DIR}) -------------------------------------------------------------------------------- /src/GUI/GACControlPanel.cpp: -------------------------------------------------------------------------------- 1 | #include "GACControlPanel.h" 2 | #include "ui_GACControlPanel.h" 3 | 4 | #include "GACDriver.h" 5 | #include "GACParameters.h" 6 | #include "MyThread.h" 7 | #include "ImageData.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | GACControlPanel::GACControlPanel(QWidget *parent) : 14 | QDockWidget(parent), 15 | ui(new Ui::GACControlPanel) 16 | { 17 | ui->setupUi(this); 18 | } 19 | 20 | GACControlPanel::GACControlPanel(QWidget *parent, GACDriver* gacDriver) : 21 | QDockWidget(parent), 22 | ui(new Ui::GACControlPanel) 23 | { 24 | ui->setupUi(this); 25 | m_GACDriver = gacDriver; 26 | 27 | QString::number(m_GACDriver->m_gacparameters->m_propagationScaling); 28 | 29 | ui->propogationSlider->setValue(int(m_GACDriver->m_gacparameters->m_propagationScaling*2)); 30 | ui->curvatureSlider->setValue(int(m_GACDriver->m_gacparameters->m_curvatureScaling*2)); 31 | ui->advectionSlider->setValue(int(m_GACDriver->m_gacparameters->m_advectionScaling*2)); 32 | 33 | ui->propogationEdit->setText(QString::number(m_GACDriver->m_gacparameters->m_propagationScaling)); 34 | ui->curvatureEdit->setText(QString::number(m_GACDriver->m_gacparameters->m_curvatureScaling)); 35 | ui->advectionEdit->setText(QString::number(m_GACDriver->m_gacparameters->m_advectionScaling)); 36 | 37 | connect(ui->stepList, SIGNAL(itemSelectionChanged()), this, SLOT(change_page())); 38 | 39 | connect(m_GACDriver, SIGNAL(iterationChange()), this, SLOT(iteration_change())); 40 | 41 | connect(m_GACDriver, SIGNAL(filterReset()), this, SLOT(filter_reset())); 42 | 43 | ui->stepList->setCurrentRow(0); 44 | // 讓x,y填滿widget 45 | ui->bubbleTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); 46 | 47 | ui->rewindButton->setIcon(QIcon(qApp->applicationDirPath() + "/resources/iconfinder_rewind_2561378.svg")); 48 | ui->playpauseButton->setIcon(QIcon(qApp->applicationDirPath() + "/resources/iconfinder_play_2561370.svg")); 49 | ui->stepButton->setIcon(QIcon(qApp->applicationDirPath() + "/resources/iconfinder_skip-forward_2561275.svg")); 50 | 51 | ui->sigmaSlider->setValue(int(m_GACDriver->m_gacparameters->m_sigma*10)); 52 | ui->alphaSlider->setValue(int(m_GACDriver->m_gacparameters->m_alpha*10)); 53 | ui->betaSlider->setValue(int(m_GACDriver->m_gacparameters->m_beta*10)); 54 | ui->sigmaEdit->setText(QString::number(m_GACDriver->m_gacparameters->m_sigma)); 55 | ui->alphaEdit->setText(QString::number(m_GACDriver->m_gacparameters->m_alpha)); 56 | ui->betaEdit->setText(QString::number(m_GACDriver->m_gacparameters->m_beta)); 57 | 58 | 59 | ui->aditerSlider->setValue(int(m_GACDriver->m_gacparameters->m_aditer)); 60 | ui->conductanceSlider->setValue(int(m_GACDriver->m_gacparameters->m_conductance)); 61 | ui->aditerEdit->setText(QString::number(m_GACDriver->m_gacparameters->m_aditer)); 62 | ui->conductanceEdit->setText(QString::number(m_GACDriver->m_gacparameters->m_conductance)); 63 | 64 | show_edgeimage(); 65 | } 66 | 67 | void GACControlPanel::filter_reset() { 68 | ui->loadanchorButton->setEnabled(false); 69 | ui->loadanchorButton->setText("No Anchor Iteration"); 70 | } 71 | 72 | void GACControlPanel::iteration_change() { 73 | ui->iterationEdit->setText(QString::number(m_GACDriver->m_gacparameters->m_anchorIter + 74 | m_GACDriver->geodesicActiveContour->GetElapsedIterations())); 75 | } 76 | 77 | void GACControlPanel::change_page() { 78 | 79 | int index = ui->stepList->currentIndex().row(); 80 | ui->stepStack->setCurrentIndex(index); 81 | } 82 | 83 | 84 | GACControlPanel::~GACControlPanel() 85 | { 86 | delete ui; 87 | } 88 | 89 | 90 | void GACControlPanel::on_stepspinBox_valueChanged(int stepsize) { 91 | m_GACDriver->m_stepsize = stepsize; 92 | } 93 | 94 | void GACControlPanel::on_aditerSlider_valueChanged(int x) { 95 | m_GACDriver->m_gacparameters->m_aditer = x; 96 | ui->aditerEdit->setText(QString::number(m_GACDriver->m_gacparameters->m_aditer)); 97 | show_edgeimage(); 98 | } 99 | 100 | void GACControlPanel::on_conductanceSlider_valueChanged(int x) { 101 | m_GACDriver->m_gacparameters->m_conductance = x; 102 | ui->conductanceEdit->setText(QString::number(m_GACDriver->m_gacparameters->m_conductance)); 103 | show_edgeimage(); 104 | } 105 | 106 | void GACControlPanel::on_sigmaSlider_valueChanged(int x) { 107 | // 因Slider都是整數,這邊除以10以0.1為一單位 108 | m_GACDriver->m_gacparameters->m_sigma = x/10.; 109 | ui->sigmaEdit->setText(QString::number(m_GACDriver->m_gacparameters->m_sigma)); 110 | show_edgeimage(); 111 | } 112 | 113 | void GACControlPanel::on_alphaSlider_valueChanged(int x) { 114 | m_GACDriver->m_gacparameters->m_alpha = x/10.; 115 | ui->alphaEdit->setText(QString::number(m_GACDriver->m_gacparameters->m_alpha)); 116 | show_edgeimage(); 117 | } 118 | 119 | void GACControlPanel::on_betaSlider_valueChanged(int x) { 120 | m_GACDriver->m_gacparameters->m_beta = x/10.; 121 | ui->betaEdit->setText(QString::number(m_GACDriver->m_gacparameters->m_beta)); 122 | show_edgeimage(); 123 | } 124 | 125 | void GACControlPanel::on_propogationSlider_valueChanged(int x) { 126 | // 因Slider都是整數,這邊除以2以0.5為一單位 127 | m_GACDriver->m_gacparameters->m_propagationScaling = x/2.; 128 | m_GACDriver->set_gac_parameter(); 129 | ui->propogationEdit->setText(QString::number(m_GACDriver->m_gacparameters->m_propagationScaling)); 130 | } 131 | 132 | 133 | void GACControlPanel::on_curvatureSlider_valueChanged(int x ) { 134 | m_GACDriver->m_gacparameters->m_curvatureScaling = x/2.; 135 | m_GACDriver->set_gac_parameter(); 136 | ui->curvatureEdit->setText(QString::number(m_GACDriver->m_gacparameters->m_curvatureScaling)); 137 | } 138 | 139 | void GACControlPanel::on_advectionSlider_valueChanged(int x) { 140 | m_GACDriver->m_gacparameters->m_advectionScaling = x/2.; 141 | m_GACDriver->set_gac_parameter(); 142 | ui->advectionEdit->setText(QString::number(m_GACDriver->m_gacparameters->m_advectionScaling)); 143 | } 144 | 145 | void GACControlPanel::on_playpauseButton_toggled(bool status){ 146 | if (status){ 147 | if(!m_gacthread){ 148 | m_GACDriver->initial_gacfilter(); 149 | m_GACDriver->threshold_filtering(); 150 | m_gacthread = new MyThread(this, m_GACDriver); 151 | } 152 | m_gacthread->play_evaluation(); 153 | ui->playpauseButton->setIcon(QIcon(qApp->applicationDirPath() + "/resources/iconfinder_pause_2561367.svg")); 154 | } 155 | else{ 156 | // 因按下stop到響應整個停下來,大概還會讓程式偷跑2~3個iter,所以要呼叫iteration_changed更新到最新狀態,並顯示 157 | m_gacthread->stop_evaluation(); 158 | iteration_change(); 159 | m_GACDriver->display_update(); 160 | m_GACDriver->m_stepanchor = m_GACDriver->geodesicActiveContour->GetElapsedIterations(); 161 | ui->playpauseButton->setIcon(QIcon(qApp->applicationDirPath() + "/resources/iconfinder_play_2561370.svg")); 162 | } 163 | } 164 | 165 | void GACControlPanel::on_rewindButton_clicked(){ 166 | m_GACDriver->reset_gacfilter(); 167 | } 168 | 169 | void GACControlPanel::on_stepButton_clicked(){ 170 | if(!m_gacthread){ 171 | m_GACDriver->initial_gacfilter(); 172 | m_GACDriver->threshold_filtering(); 173 | m_gacthread = new MyThread(this, m_GACDriver); 174 | } 175 | // check if it is playing 176 | if (ui->playpauseButton->isChecked()){ 177 | ui->playpauseButton->click(); 178 | } 179 | for (int i=0; im_stepsize; i++){ 180 | m_GACDriver->run_segmentation(); 181 | } 182 | } 183 | 184 | 185 | void GACControlPanel::show_edgeimage(){ 186 | m_GACDriver->set_edge_parameters(); 187 | auto inputimage = m_GACDriver->m_imagedata->unsignedchar2float(m_GACDriver->m_imagedata->m_readimage); 188 | m_GACDriver->smoothing_filtering(inputimage); 189 | m_GACDriver->gradient_filtering(m_GACDriver->m_gacparameters->m_smoothingImage); 190 | m_GACDriver->sigmoid_filtering(m_GACDriver->m_gacparameters->m_gradientImage); 191 | } 192 | 193 | void GACControlPanel::on_edgeButton_clicked(){ 194 | // 移到下一頁 195 | ui->stepList->setCurrentRow(1); 196 | } 197 | 198 | void GACControlPanel::on_pickbubbleButton_clicked(){ 199 | 200 | QMessageBox::information(this, tr("instruction"), tr("Click On Image to Specify Initial Contour"), QMessageBox::Ok); 201 | // m_GACDriver->m_mainwindow->setCursor(Qt::CrossCursor); 202 | m_GACDriver->m_mainwindow->ui->qvtkopenglWidget->setCursor(Qt::CrossCursor); 203 | 204 | m_Connections = vtkEventQtSlotConnect::New(); 205 | m_Connections->Connect(m_GACDriver->m_mainwindow->ui->qvtkopenglWidget->GetRenderWindow()->GetInteractor(), 206 | vtkCommand::LeftButtonPressEvent, 207 | m_GACDriver, 208 | SLOT(seed_record())); 209 | connect(m_GACDriver, SIGNAL(seedClicked()), this, SLOT(seed_insert())); 210 | 211 | m_GACDriver->initial_bubble_image(); 212 | // ui->edgeBox->click(); 213 | } 214 | 215 | void GACControlPanel::seed_insert(){ 216 | ui->bubbleTable->insertRow(ui->bubbleTable->rowCount()); 217 | int x = m_GACDriver->m_gacparameters->m_seedPosX; 218 | int y = m_GACDriver->m_gacparameters->m_seedPosY; 219 | ui->bubbleTable->setItem(ui->bubbleTable->rowCount()-1,0, 220 | new QTableWidgetItem(QString::number(x))); 221 | ui->bubbleTable->setItem(ui->bubbleTable->rowCount()-1,1, 222 | new QTableWidgetItem(QString::number(y))); 223 | 224 | m_GACDriver->create_bubble_image(); 225 | 226 | if (ui->bubbleTable->rowCount() == 1){ 227 | ui->edgeBox->click(); 228 | ui->bubbleButton->setEnabled(true); 229 | m_GACDriver->create_bubble_image(); 230 | } 231 | } 232 | 233 | 234 | void GACControlPanel::on_bubbleButton_clicked() { 235 | auto inputimage = m_GACDriver->m_imagedata->unsignedchar2float(m_GACDriver->m_imagedata->m_readimage); 236 | 237 | const int bubble_number = ui->bubbleTable->rowCount(); 238 | 239 | m_GACDriver->node_list.resize(bubble_number); 240 | 241 | for (int i = 0; inode_list.size(); i++){ 242 | m_GACDriver->seedPosition[0] = ui->bubbleTable->item(i,0)->text().toInt(); 243 | m_GACDriver->seedPosition[1] = ui->bubbleTable->item(i,1)->text().toInt(); 244 | m_GACDriver->node_list[i].SetValue(m_GACDriver->m_gacparameters->m_seedValue); 245 | m_GACDriver->node_list[i].SetIndex(m_GACDriver->seedPosition); 246 | } 247 | 248 | m_GACDriver->fastmarching_filtering(inputimage); 249 | ui->stepList->setCurrentRow(2); 250 | 251 | m_Connections->Disconnect(m_GACDriver->m_mainwindow->ui->qvtkopenglWidget->GetRenderWindow()->GetInteractor(), 252 | vtkCommand::LeftButtonPressEvent, 253 | m_GACDriver, 254 | SLOT(seed_record())); 255 | m_GACDriver->m_mainwindow->ui->qvtkopenglWidget->setCursor(Qt::ArrowCursor); 256 | 257 | } 258 | 259 | void GACControlPanel::on_originalBox_clicked(bool checked) { 260 | if (checked){ 261 | m_GACDriver->m_imagedata->m_background_image = m_GACDriver->m_imagedata->m_readimage; 262 | ui->edgeBox->setCheckable(false); 263 | } 264 | else { 265 | if (m_GACDriver->m_imagedata->m_background_image == m_GACDriver->m_imagedata->m_readimage) { 266 | m_GACDriver->m_imagedata->m_background_image = nullptr; 267 | ui->edgeBox->setCheckable(true); 268 | } 269 | } 270 | // TODO better display method 271 | m_GACDriver->m_mainwindow->displayImage(); 272 | } 273 | 274 | void GACControlPanel::on_edgeBox_clicked(bool checked) { 275 | if (checked){ 276 | m_GACDriver->caster_filtering(); 277 | m_GACDriver->caster->SetInput(m_GACDriver->m_gacparameters->m_sigmoidImage); 278 | m_GACDriver->m_imagedata->m_background_image = m_GACDriver->caster->GetOutput(); 279 | ui->originalBox->setCheckable(false); 280 | } 281 | else { 282 | if (m_GACDriver->m_imagedata->m_background_image == m_GACDriver->caster->GetOutput()) { 283 | m_GACDriver->m_imagedata->m_background_image = nullptr; 284 | ui->originalBox->setCheckable(true); 285 | } 286 | } 287 | m_GACDriver->m_mainwindow->displayImage(); 288 | } 289 | 290 | void GACControlPanel::on_setanchorButton_clicked() { 291 | m_GACDriver->save_anchorimage(); 292 | ui->loadanchorButton->setText("Back to Iteraion "+ui->iterationEdit->text()); 293 | ui->loadanchorButton->setEnabled(true); 294 | } 295 | 296 | void GACControlPanel::on_loadanchorButton_clicked() { 297 | m_GACDriver->load_anchorimage(); 298 | iteration_change(); 299 | } 300 | 301 | void GACControlPanel::on_quitButton_clicked() { 302 | ui->playpauseButton->setChecked(false); 303 | m_GACDriver->save_anchorimage(); 304 | m_GACDriver->m_mainwindow->show_gacThumbnail(); 305 | m_GACDriver->m_imagedata->m_background_image->DisconnectPipeline(); 306 | m_GACDriver->m_imagedata->m_background_image = nullptr; 307 | m_GACDriver->m_mainwindow->displayImage(); 308 | this->setAttribute(Qt::WA_DeleteOnClose, false); 309 | this->close(); 310 | } 311 | -------------------------------------------------------------------------------- /src/GUI/GACControlPanel.h: -------------------------------------------------------------------------------- 1 | #ifndef GACControlPanel_H 2 | #define GACControlPanel_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "MyThread.h" 9 | 10 | class GACDriver; 11 | class MyThread; 12 | 13 | 14 | namespace Ui { 15 | class GACControlPanel; 16 | } 17 | 18 | class GACControlPanel : public QDockWidget 19 | { 20 | Q_OBJECT 21 | 22 | public: 23 | explicit GACControlPanel(QWidget *parent = nullptr); 24 | explicit GACControlPanel(QWidget *parent = nullptr, GACDriver* gacDriver = nullptr); 25 | ~GACControlPanel(); 26 | 27 | //private: 28 | public: 29 | Ui::GACControlPanel *ui; 30 | 31 | public: 32 | GACDriver* m_GACDriver = nullptr; 33 | MyThread* m_gacthread = nullptr; 34 | 35 | vtkEventQtSlotConnect* m_Connections; 36 | 37 | // void display_bubble(); 38 | 39 | public slots: 40 | void change_page(); 41 | void on_rewindButton_clicked(); 42 | void on_edgeButton_clicked(); 43 | void on_pickbubbleButton_clicked(); 44 | void on_bubbleButton_clicked(); 45 | void on_originalBox_clicked(bool); 46 | void on_edgeBox_clicked(bool); 47 | 48 | void on_setanchorButton_clicked(); 49 | void on_loadanchorButton_clicked(); 50 | 51 | void on_quitButton_clicked(); 52 | 53 | void on_playpauseButton_toggled(bool); 54 | 55 | void on_stepButton_clicked(); 56 | 57 | void on_propogationSlider_valueChanged(int); 58 | void on_curvatureSlider_valueChanged(int); 59 | void on_advectionSlider_valueChanged(int); 60 | void on_stepspinBox_valueChanged(int); 61 | 62 | void on_sigmaSlider_valueChanged(int); 63 | void on_alphaSlider_valueChanged(int); 64 | void on_betaSlider_valueChanged(int); 65 | 66 | void on_aditerSlider_valueChanged(int); 67 | void on_conductanceSlider_valueChanged(int); 68 | 69 | void seed_insert(); 70 | void iteration_change(); 71 | void filter_reset(); 72 | void show_edgeimage(); 73 | 74 | }; 75 | 76 | #endif // GACControlPanel_H 77 | -------------------------------------------------------------------------------- /src/GUI/GACControlPanel.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | GACControlPanel 4 | 5 | 6 | 7 | 0 8 | 0 9 | 442 10 | 718 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | DockWidget 21 | 22 | 23 | 24 | 25 | 0 26 | 0 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 0 37 | 0 38 | 39 | 40 | 41 | 42 | 180 43 | 60 44 | 45 | 46 | 47 | 48 | 75 49 | false 50 | true 51 | false 52 | false 53 | PreferDefault 54 | 55 | 56 | 57 | Qt::NoFocus 58 | 59 | 60 | Qt::LeftToRight 61 | 62 | 63 | QAbstractItemView::SelectItems 64 | 65 | 66 | Qt::ElideRight 67 | 68 | 69 | 70 | Step1: Preprocessing 71 | 72 | 73 | 74 | 75 | Step2: Initial Contour 76 | 77 | 78 | 79 | 80 | Step3: Start Evolution 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | Background Image 91 | 92 | 93 | 94 | 95 | 96 | 97 | Original Image 98 | 99 | 100 | 101 | 102 | 103 | 104 | Edge Image 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 0 115 | 0 116 | 117 | 118 | 119 | 1 120 | 121 | 122 | 123 | 124 | 125 | 126 | Qt::Vertical 127 | 128 | 129 | QSizePolicy::Fixed 130 | 131 | 132 | 133 | 20 134 | 20 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | Confirm Edge Detection Image 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 0 154 | 0 155 | 156 | 157 | 158 | <html><head/><body><p>Click for Details of Edge Detection Steps:<br/><a href="https://itk.org/Doxygen/html/classitk_1_1CurvatureAnisotropicDiffusionImageFilter.html"><span style=" text-decoration: underline; color:#0000ff;">(1) Anisotropic Diffusion</span></a><br/><a href="https://itk.org/Doxygen/html/classitk_1_1GradientMagnitudeRecursiveGaussianImageFilter.html"><span style=" text-decoration: underline; color:#0000ff;">(2) Gaussian Gradient</span></a><br/><a href="https://itk.org/Doxygen/html/classitk_1_1SigmoidImageFilter.html"><span style=" text-decoration: underline; color:#0000ff;">(3) Sigmoid Scaling</span></a></p></body></html> 159 | 160 | 161 | Qt::RichText 162 | 163 | 164 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 165 | 166 | 167 | true 168 | 169 | 170 | Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse 171 | 172 | 173 | 174 | 175 | 176 | 177 | Qt::Vertical 178 | 179 | 180 | 181 | 20 182 | 40 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | QFrame {background-color : OldLace; } 191 | 192 | 193 | QFrame::StyledPanel 194 | 195 | 196 | QFrame::Sunken 197 | 198 | 199 | 200 | 201 | 202 | QLabel { background: Moccasin } 203 | 204 | 205 | Edge Detection Parameters 206 | 207 | 208 | Qt::AlignCenter 209 | 210 | 211 | 212 | 213 | 214 | 215 | (1)iterations 216 | 217 | 218 | 219 | 220 | 221 | 222 | false 223 | 224 | 225 | 226 | 0 227 | 0 228 | 229 | 230 | 231 | 232 | 40 233 | 16777215 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 1 242 | 243 | 244 | 20 245 | 246 | 247 | 1 248 | 249 | 250 | 1 251 | 252 | 253 | 5 254 | 255 | 256 | Qt::Horizontal 257 | 258 | 259 | 260 | 261 | 262 | 263 | (1)Conductance 264 | 265 | 266 | 267 | 268 | 269 | 270 | false 271 | 272 | 273 | 274 | 0 275 | 0 276 | 277 | 278 | 279 | 280 | 40 281 | 16777215 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 1 290 | 291 | 292 | 30 293 | 294 | 295 | 1 296 | 297 | 298 | 5 299 | 300 | 301 | 9 302 | 303 | 304 | Qt::Horizontal 305 | 306 | 307 | QSlider::NoTicks 308 | 309 | 310 | 311 | 312 | 313 | 314 | (2)Sigma(σ) 315 | 316 | 317 | 318 | 319 | 320 | 321 | false 322 | 323 | 324 | 325 | 0 326 | 0 327 | 328 | 329 | 330 | 331 | 40 332 | 16777215 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 1 341 | 342 | 343 | 100 344 | 345 | 346 | 1 347 | 348 | 349 | 5 350 | 351 | 352 | 10 353 | 354 | 355 | Qt::Horizontal 356 | 357 | 358 | QSlider::NoTicks 359 | 360 | 361 | 362 | 363 | 364 | 365 | (3)Alpha(α) 366 | 367 | 368 | 369 | 370 | 371 | 372 | false 373 | 374 | 375 | 376 | 0 377 | 0 378 | 379 | 380 | 381 | 382 | 40 383 | 16777215 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | -100 392 | 393 | 394 | -1 395 | 396 | 397 | 1 398 | 399 | 400 | 1 401 | 402 | 403 | -3 404 | 405 | 406 | Qt::Horizontal 407 | 408 | 409 | 410 | 411 | 412 | 413 | (3)Beta(β) 414 | 415 | 416 | 417 | 418 | 419 | 420 | false 421 | 422 | 423 | 424 | 0 425 | 0 426 | 427 | 428 | 429 | 430 | 40 431 | 16777215 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 0 440 | 441 | 442 | 100 443 | 444 | 445 | 1 446 | 447 | 448 | 5 449 | 450 | 451 | 20 452 | 453 | 454 | Qt::Horizontal 455 | 456 | 457 | 458 | 459 | label_7 460 | sigmaEdit 461 | sigmaSlider 462 | label_9 463 | alphaEdit 464 | alphaSlider 465 | label_10 466 | betaEdit 467 | betaSlider 468 | label_11 469 | conductanceSlider 470 | label_12 471 | conductanceEdit 472 | aditerSlider 473 | aditerEdit 474 | label_13 475 | 476 | 477 | 478 | 479 | 480 | Qt::Vertical 481 | 482 | 483 | QSizePolicy::Fixed 484 | 485 | 486 | 487 | 20 488 | 20 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | Qt::Vertical 501 | 502 | 503 | QSizePolicy::Fixed 504 | 505 | 506 | 507 | 20 508 | 20 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | Click to Pick Initial Bubbles 517 | 518 | 519 | 520 | 521 | 522 | 523 | QAbstractScrollArea::AdjustIgnored 524 | 525 | 526 | false 527 | 528 | 529 | 100 530 | 531 | 532 | true 533 | 534 | 535 | false 536 | 537 | 538 | false 539 | 540 | 541 | false 542 | 543 | 544 | false 545 | 546 | 547 | 548 | x 549 | 550 | 551 | 552 | 553 | y 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | false 562 | 563 | 564 | Confirm Initial Bubbles 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | Qt::Vertical 576 | 577 | 578 | QSizePolicy::Expanding 579 | 580 | 581 | 582 | 20 583 | 40 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | QFrame {background-color : OldLace; } 592 | 593 | 594 | QFrame::StyledPanel 595 | 596 | 597 | QFrame::Sunken 598 | 599 | 600 | 601 | 602 | 603 | Propogation 604 | 605 | 606 | 607 | 608 | 609 | 610 | false 611 | 612 | 613 | 614 | 0 615 | 0 616 | 617 | 618 | 619 | 620 | 40 621 | 16777215 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | -100 630 | 631 | 632 | 100 633 | 634 | 635 | 1 636 | 637 | 638 | 5 639 | 640 | 641 | 20 642 | 643 | 644 | Qt::Horizontal 645 | 646 | 647 | QSlider::NoTicks 648 | 649 | 650 | 651 | 652 | 653 | 654 | Curvature 655 | 656 | 657 | 658 | 659 | 660 | 661 | false 662 | 663 | 664 | 665 | 0 666 | 0 667 | 668 | 669 | 670 | 671 | 40 672 | 16777215 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | -100 681 | 682 | 683 | 100 684 | 685 | 686 | 1 687 | 688 | 689 | 5 690 | 691 | 692 | 20 693 | 694 | 695 | Qt::Horizontal 696 | 697 | 698 | 699 | 700 | 701 | 702 | Advection 703 | 704 | 705 | 706 | 707 | 708 | 709 | false 710 | 711 | 712 | 713 | 0 714 | 0 715 | 716 | 717 | 718 | 719 | 40 720 | 16777215 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | -100 729 | 730 | 731 | 100 732 | 733 | 734 | 1 735 | 736 | 737 | 5 738 | 739 | 740 | 20 741 | 742 | 743 | Qt::Horizontal 744 | 745 | 746 | 747 | 748 | 749 | 750 | QLabel { background: Moccasin } 751 | 752 | 753 | Curve Evolution Parameters 754 | 755 | 756 | Qt::AlignCenter 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | Qt::Horizontal 769 | 770 | 771 | QSizePolicy::Expanding 772 | 773 | 774 | 775 | 40 776 | 20 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | /*在class name前面加個"點",就不會讓stylesheet影響其內的其他元件*/ 785 | .QFrame{ 786 | border-top: 0px; 787 | border-left: 0px; 788 | border-right: 0px; 789 | border-bottom: 5px solid Wheat; 790 | border-style: double ; 791 | } 792 | 793 | 794 | QFrame::Box 795 | 796 | 797 | 798 | 0 799 | 800 | 801 | 802 | 803 | true 804 | 805 | 806 | 807 | 0 808 | 0 809 | 810 | 811 | 812 | QLabel{} 813 | 814 | 815 | QFrame::Raised 816 | 817 | 818 | 0 819 | 820 | 821 | Current Iterations 822 | 823 | 824 | false 825 | 826 | 827 | 828 | 829 | 830 | 831 | false 832 | 833 | 834 | 835 | 0 836 | 0 837 | 838 | 839 | 840 | 841 | 80 842 | 16777215 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | Qt::Horizontal 854 | 855 | 856 | QSizePolicy::Expanding 857 | 858 | 859 | 860 | 40 861 | 20 862 | 863 | 864 | 865 | 866 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | Qt::Horizontal 874 | 875 | 876 | QSizePolicy::Expanding 877 | 878 | 879 | 880 | 40 881 | 20 882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 0 891 | 0 892 | 893 | 894 | 895 | 896 | 50 897 | 50 898 | 899 | 900 | 901 | 902 | 50 903 | 50 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | Qt::Horizontal 915 | 916 | 917 | QSizePolicy::Fixed 918 | 919 | 920 | 921 | 10 922 | 20 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 | 0 932 | 0 933 | 934 | 935 | 936 | 937 | 50 938 | 50 939 | 940 | 941 | 942 | 943 | 50 944 | 50 945 | 946 | 947 | 948 | Qt::NoFocus 949 | 950 | 951 | 952 | 953 | 954 | true 955 | 956 | 957 | 958 | 959 | 960 | 961 | Qt::Horizontal 962 | 963 | 964 | QSizePolicy::Fixed 965 | 966 | 967 | 968 | 10 969 | 20 970 | 971 | 972 | 973 | 974 | 975 | 976 | 977 | 978 | 0 979 | 0 980 | 981 | 982 | 983 | 984 | 50 985 | 50 986 | 987 | 988 | 989 | 990 | 50 991 | 50 992 | 993 | 994 | 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1 1003 | 1004 | 1005 | 1 1006 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | Qt::Horizontal 1013 | 1014 | 1015 | QSizePolicy::Expanding 1016 | 1017 | 1018 | 1019 | 40 1020 | 20 1021 | 1022 | 1023 | 1024 | 1025 | 1026 | 1027 | 1028 | 1029 | 1030 | Qt::NoFocus 1031 | 1032 | 1033 | Set Anchor Iteraion 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | false 1041 | 1042 | 1043 | Qt::NoFocus 1044 | 1045 | 1046 | No Anchor Iteration 1047 | 1048 | 1049 | 1050 | 1051 | 1052 | 1053 | Qt::Vertical 1054 | 1055 | 1056 | QSizePolicy::Fixed 1057 | 1058 | 1059 | 1060 | 20 1061 | 20 1062 | 1063 | 1064 | 1065 | 1066 | 1067 | 1068 | 1069 | Quit 1070 | 1071 | 1072 | 1073 | 1074 | 1075 | 1076 | 1077 | 1078 | 1079 | 1080 | Qt::Horizontal 1081 | 1082 | 1083 | 1084 | 1085 | 1086 | 1087 | 1088 | 1089 | 1090 | 1091 | 1092 | -------------------------------------------------------------------------------- /src/GUI/Thumbnail.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 温雅 on 2019-05-15. 3 | // 4 | 5 | #include "Thumbnail.h" 6 | 7 | bool Thumbnail::clickable = false; 8 | 9 | Thumbnail::Thumbnail(QWidget* parent, Qt::WindowFlags f) 10 | : QLabel(parent) { 11 | } 12 | 13 | Thumbnail::~Thumbnail() {} 14 | 15 | void Thumbnail::mousePressEvent(QMouseEvent* event) { 16 | if(clickable){ 17 | emit clicked(); 18 | } 19 | } -------------------------------------------------------------------------------- /src/GUI/Thumbnail.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 温雅 on 2019-05-15. 3 | // 4 | 5 | #ifndef LEVELSET_VISUALIZER_THUMBNAIL_H 6 | #define LEVELSET_VISUALIZER_THUMBNAIL_H 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | class Thumbnail : public QLabel { 14 | Q_OBJECT 15 | 16 | public: 17 | explicit Thumbnail(QWidget* parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()); 18 | ~Thumbnail(); 19 | 20 | signals: 21 | void clicked(); 22 | 23 | protected: 24 | void mousePressEvent(QMouseEvent* event); 25 | 26 | public: 27 | // 3 thumbnail share clickable status, use static 28 | static bool clickable; 29 | 30 | }; 31 | 32 | #endif //LEVELSET_VISUALIZER_THUMBNAIL_H 33 | -------------------------------------------------------------------------------- /src/GUI/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ImageData.h" 3 | #include "GACDriver.h" 4 | #include "GACControlPanel.h" 5 | #include "Thumbnail.h" 6 | #include "GACParameters.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | 38 | MainWindow::MainWindow(QWidget *parent) : 39 | QMainWindow(parent), 40 | ui(new Ui::MainWindow) 41 | { 42 | ui->setupUi(this); 43 | m_imagedata = new ImageData(this); 44 | m_Connections = vtkEventQtSlotConnect::New(); 45 | m_Connections->Connect(ui->qvtkopenglWidget->GetRenderWindow()->GetInteractor(), 46 | vtkCommand::MouseMoveEvent, 47 | this, 48 | SLOT(updateCoords(vtkObject*))); 49 | 50 | // qApp就是現在的application,用來檢測在螢幕間切換的pixel問題 51 | connect(qApp->topLevelWindows().first(), SIGNAL(screenChanged(QScreen*)), this, SLOT(screenChanged())); 52 | 53 | m_signalMapper = new QSignalMapper(this); 54 | connect(ui->originThumbnail, SIGNAL(clicked()), m_signalMapper, SLOT(map())); 55 | connect(ui->edgeThumbnail, SIGNAL(clicked()), m_signalMapper, SLOT(map())); 56 | connect(ui->gacThumbnail, SIGNAL(clicked()), m_signalMapper, SLOT(map())); 57 | m_signalMapper->setMapping(ui->originThumbnail, 0); 58 | m_signalMapper->setMapping(ui->edgeThumbnail, 1); 59 | m_signalMapper->setMapping(ui->gacThumbnail, 2); 60 | 61 | connect(m_signalMapper, SIGNAL(mapped(int)), this, SLOT(display_thumbnail(int))); 62 | } 63 | 64 | MainWindow::~MainWindow() 65 | { 66 | delete ui; 67 | } 68 | 69 | void MainWindow::display_thumbnail(int n){ 70 | switch(n) { 71 | case 0: 72 | m_imagedata->m_frontground_image = m_imagedata->m_readimage; 73 | break; 74 | case 1: 75 | m_imagedata->m_frontground_image = m_GACDriver->caster->GetOutput(); 76 | break; 77 | case 2: 78 | m_imagedata->m_frontground_image = m_GACDriver->thresholder->GetOutput(); 79 | break; 80 | default: 81 | break; 82 | } 83 | displayImage(); 84 | } 85 | 86 | void MainWindow::screenChanged() { 87 | m_devicePixelRatio = ui->qvtkopenglWidget->devicePixelRatio(); 88 | if (m_ImageViewer){ 89 | m_cornerAnnotation->SetMaximumFontSize(20 * m_devicePixelRatio); 90 | displayImage(); 91 | } 92 | } 93 | 94 | void MainWindow::show_originThumbnail() { 95 | UCImageType ::RegionType region; 96 | region = m_imagedata->m_readimage->GetLargestPossibleRegion(); 97 | UCImageType::SizeType size = region.GetSize(); 98 | int rows = size.m_Size[0]; 99 | int cols = size.m_Size[1]; 100 | uchar imagio [cols][rows]; 101 | for(int row = 0; row < rows; row++) 102 | { 103 | for(int col = 0; col < cols; col++) 104 | { 105 | UCImageType::IndexType pixelIndex; 106 | pixelIndex[0] = row; 107 | pixelIndex[1] = col; 108 | imagio[col][row] = m_imagedata->m_readimage->GetPixel(pixelIndex); 109 | } 110 | } 111 | QImage image((uchar*)imagio, rows, cols, rows, QImage::Format_Grayscale8); 112 | int w = ui->originThumbnail->width(); 113 | int h = ui->originThumbnail->height(); 114 | int backlash = ui->originThumbnail->lineWidth()*2; 115 | ui->originThumbnail->setPixmap(QPixmap::fromImage(image).scaled(w-backlash, h-backlash, Qt::IgnoreAspectRatio)); 116 | } 117 | 118 | void MainWindow::show_edgeThumbnail() { 119 | UCImageType ::RegionType region; 120 | region = m_GACDriver->m_gacparameters->m_sigmoidImage->GetLargestPossibleRegion(); 121 | UCImageType::SizeType size = region.GetSize(); 122 | int rows = size.m_Size[0]; 123 | int cols = size.m_Size[1]; 124 | uchar imagio [cols][rows]; 125 | for(int row = 0; row < rows; row++) 126 | { 127 | for(int col = 0; col < cols; col++) 128 | { 129 | UCImageType::IndexType pixelIndex; 130 | pixelIndex[0] = row; 131 | pixelIndex[1] = col; 132 | imagio[col][row] = m_imagedata->m_tempUCedge_image->GetPixel(pixelIndex); 133 | } 134 | } 135 | QImage image((uchar*)imagio, rows, cols, rows, QImage::Format_Grayscale8); 136 | int w = ui->edgeThumbnail->width(); 137 | int h = ui->edgeThumbnail->height(); 138 | int backlash = ui->edgeThumbnail->lineWidth()*2; 139 | ui->edgeThumbnail->setPixmap(QPixmap::fromImage(image).scaled(w-backlash, h-backlash, Qt::IgnoreAspectRatio)); 140 | m_imagedata->m_tempUCedge_image = nullptr; 141 | } 142 | 143 | void MainWindow::show_gacThumbnail() { 144 | // 會到show_gacThumbnail代表已按下GAC_Panel的Quit,顯示後可開啟點選thunmbnail的功能 145 | UCImageType ::RegionType region; 146 | region = m_GACDriver->m_gacparameters->m_anchorImage->GetLargestPossibleRegion(); 147 | UCImageType::SizeType size = region.GetSize(); 148 | int rows = size.m_Size[0]; 149 | int cols = size.m_Size[1]; 150 | uchar imagio [cols][rows]; 151 | for(int row = 0; row < rows; row++) 152 | { 153 | for(int col = 0; col < cols; col++) 154 | { 155 | UCImageType::IndexType pixelIndex; 156 | pixelIndex[0] = row; 157 | pixelIndex[1] = col; 158 | 159 | float p = m_GACDriver->m_gacparameters->m_anchorImage->GetPixel(pixelIndex); 160 | imagio[col][row] = p > -1000 && p < 0 ? 255 : 0; 161 | } 162 | } 163 | QImage image((uchar*)imagio, rows, cols, rows, QImage::Format_Grayscale8); 164 | int w = ui->gacThumbnail->width(); 165 | int h = ui->gacThumbnail->height(); 166 | int backlash = ui->gacThumbnail->lineWidth()*2; 167 | ui->gacThumbnail->setPixmap(QPixmap::fromImage(image).scaled(w-backlash, h-backlash, Qt::IgnoreAspectRatio)); 168 | // thumbnail clickable! 169 | Thumbnail::clickable=true; 170 | } 171 | 172 | void MainWindow::display_setup() 173 | { 174 | //// Display Widget Setup 175 | // frontground 176 | m_ImageViewer = vtkSmartPointer< vtkImageViewer2 >::New(); 177 | m_Renderer = vtkSmartPointer< vtkRenderer >::New(); 178 | m_ImageViewer->SetRenderer(m_Renderer); 179 | m_ImageViewer->SetupInteractor(ui->qvtkopenglWidget->GetRenderWindow()->GetInteractor()); 180 | m_Renderer->SetBackground(0.1,0.3,0.8); 181 | m_ImageViewer->GetImageActor()->InterpolateOff(); 182 | m_ImageViewer->SetSliceOrientationToXY(); 183 | // 用一些opacity或是lookuptable轉換的話,actor會變成translucent mode,在pickprop會有問題,所以強制Opaque 184 | m_ImageViewer->GetImageActor()->SetForceOpaque(1); 185 | 186 | // background 187 | m_BackGroundImageViewer = vtkSmartPointer< vtkImageViewer2 >::New(); 188 | m_BackgroundRenderer = vtkSmartPointer< vtkRenderer >::New(); 189 | m_BackGroundImageViewer->SetRenderer(m_BackgroundRenderer); 190 | m_BackGroundImageViewer->GetImageActor()->InterpolateOff(); 191 | m_BackgroundRenderer->SetBackground(0.1,0.3,0.8); 192 | m_BackgroundRenderer->InteractiveOff(); 193 | m_BackGroundImageViewer->SetSliceOrientationToXY(); 194 | 195 | // for origin at top-left, set two renderer have same Camera to Zoom together 196 | m_Renderer->GetActiveCamera()->SetPosition(0,0,-1); 197 | m_Renderer->GetActiveCamera()->SetViewUp(0,-1,0);// 198 | m_BackgroundRenderer->SetActiveCamera(m_Renderer->GetActiveCamera()); 199 | 200 | } 201 | 202 | void MainWindow::picker_setup() { 203 | //// Pixel-Picking Setup 204 | m_propPicker = vtkSmartPointer::New(); 205 | m_cornerAnnotation = vtkSmartPointer::New(); 206 | m_callback = vtkSmartPointer::New(); 207 | 208 | // Picker to pick pixels 209 | m_propPicker->PickFromListOn(); 210 | // Give the picker a prop to pick 211 | m_propPicker->AddPickList(m_ImageViewer->GetImageActor()); 212 | // Annotate the image with window/level and mouse over pixel information 213 | m_cornerAnnotation->SetLinearFontScaleFactor(2); 214 | m_cornerAnnotation->SetNonlinearFontScaleFactor(1); 215 | // set font size 216 | m_devicePixelRatio = ui->qvtkopenglWidget->devicePixelRatio(); 217 | m_cornerAnnotation->SetMaximumFontSize(20 * m_devicePixelRatio); 218 | m_cornerAnnotation->SetText(0, "Off Image"); 219 | m_cornerAnnotation->GetTextProperty()->SetColor(1, 0, 0); 220 | m_cornerAnnotation->GetTextProperty()->SetBold(true); 221 | // Callback listens to MouseMoveEvents invoked by the interactor's style 222 | m_callback->SetViewer(m_ImageViewer); 223 | m_callback->SetAnnotation(m_cornerAnnotation); 224 | m_callback->SetPicker(m_propPicker); 225 | m_Renderer->AddViewProp(m_cornerAnnotation); 226 | m_ImageViewer->GetInteractorStyle()->AddObserver(vtkCommand::MouseMoveEvent, m_callback); 227 | } 228 | 229 | void MainWindow::on_loadButton_clicked() 230 | { 231 | m_imagedata->loadImage(); 232 | // 確定有load進image,再進行顯示的setup 233 | if (m_readimagechanged){ 234 | // only setup display & pick @ first loading 235 | if (!m_ImageViewer){ 236 | display_setup(); 237 | picker_setup(); 238 | } 239 | if (m_gacpanel_dialog){ 240 | gac_reset(); 241 | // There's a m_Background Renderer issue when loading different image 242 | // use this method to flush the buffer 243 | m_imagedata->m_background_image = nullptr; 244 | m_imagedata->m_background_image = m_imagedata->m_frontground_image; 245 | displayImage(); 246 | } 247 | m_imagedata->m_background_image = nullptr; 248 | displayImage(); 249 | show_originThumbnail(); 250 | Thumbnail::clickable=false; 251 | } 252 | } 253 | 254 | void MainWindow::gac_reset() 255 | { 256 | ui->originThumbnail->setText("original image"); 257 | ui->edgeThumbnail->setText("edge image"); 258 | ui->gacThumbnail->setText("levelset image"); 259 | 260 | // STUPID delete pattern, need to be revised later 261 | if (m_gacpanel_dialog){ 262 | if(m_gacpanel_dialog->m_gacthread){ 263 | if (m_gacpanel_dialog->m_gacthread->myTimer){ 264 | delete m_gacpanel_dialog->m_gacthread->myTimer; 265 | m_gacpanel_dialog->m_gacthread->myTimer = nullptr; 266 | } 267 | delete m_gacpanel_dialog->m_gacthread; 268 | m_gacpanel_dialog->m_gacthread = nullptr; 269 | } 270 | delete m_gacpanel_dialog; 271 | m_gacpanel_dialog = nullptr; 272 | } 273 | if (m_GACDriver){ 274 | if (m_GACDriver->m_gacparameters){ 275 | delete m_GACDriver->m_gacparameters; 276 | m_GACDriver->m_gacparameters = nullptr; 277 | } 278 | delete m_GACDriver; 279 | m_GACDriver = nullptr; 280 | } 281 | } 282 | 283 | void MainWindow::on_saveButton_clicked() 284 | { 285 | m_imagedata->saveImage(); 286 | } 287 | 288 | void MainWindow::displayImage() { 289 | 290 | if (!m_imagedata->m_background_image){ 291 | ui->qvtkopenglWidget->GetRenderWindow()->ClearInRenderStatus(); 292 | itkToVtk->SetInput(m_imagedata->m_frontground_image); 293 | itkToVtk->Update(); 294 | m_ImageViewer->SetInputData(itkToVtk->GetOutput()); 295 | m_ImageViewer->GetImageActor()->GetProperty()->SetInterpolationTypeToNearest(); 296 | 297 | m_ImageViewer->UpdateDisplayExtent(); 298 | m_ImageViewer->SetRenderWindow(ui->qvtkopenglWidget->GetRenderWindow()); 299 | 300 | m_Renderer->ResetCamera(); 301 | ui->qvtkopenglWidget->GetRenderWindow()->Render(); 302 | } 303 | else { 304 | // m_BackgroundRenderer->Clear(); 305 | ui->qvtkopenglWidget->GetRenderWindow()->ClearInRenderStatus(); 306 | itkToVtk->SetInput(m_imagedata->m_frontground_image); 307 | itkToVtk->Update(); 308 | 309 | // Map the scalar values in the image to colors with a lookup table: 310 | vtkSmartPointer lookupTable = 311 | vtkSmartPointer::New(); 312 | 313 | lookupTable->SetNumberOfTableValues(2); 314 | lookupTable->SetRange(0.0, 1.0); 315 | // alpha完全設0也會上pickprop抓不到(沒render),所以給一個給低的值來逼近透明就好 316 | lookupTable->SetTableValue( 0, 0.0, 0.0, 0.0, 0.01 ); //label 0 is almost transparent 317 | lookupTable->SetTableValue( 1, 0.8, 0.1, 0.1, 0.8 ); //label 1 is opaque and green 318 | lookupTable->Build(); 319 | 320 | // Pass the original image and the lookup table to a filter to create a color image: 321 | vtkSmartPointer scalarValuesToColors = 322 | vtkSmartPointer::New(); 323 | scalarValuesToColors->SetLookupTable(lookupTable); 324 | scalarValuesToColors->PassAlphaToOutputOn(); 325 | scalarValuesToColors->SetInputData(itkToVtk->GetOutput()); 326 | scalarValuesToColors->Update(); 327 | 328 | m_ImageViewer->SetInputData(scalarValuesToColors->GetOutput()); 329 | m_ImageViewer->UpdateDisplayExtent(); 330 | m_Renderer->ResetCamera(); 331 | 332 | itkToVtk2->SetInput(m_imagedata->m_background_image); 333 | itkToVtk2->Update(); 334 | 335 | m_BackGroundImageViewer->SetInputData(itkToVtk2->GetOutput()); 336 | m_BackGroundImageViewer->UpdateDisplayExtent(); 337 | m_BackgroundRenderer->ResetCamera(); 338 | 339 | m_BackgroundRenderer->SetLayer(0); 340 | m_Renderer->SetLayer(1); 341 | ui->qvtkopenglWidget->GetRenderWindow()->SetNumberOfLayers(2); 342 | ui->qvtkopenglWidget->GetRenderWindow()->AddRenderer(m_BackgroundRenderer); 343 | ui->qvtkopenglWidget->GetRenderWindow()->AddRenderer(m_Renderer); 344 | ui->qvtkopenglWidget->GetRenderWindow()->Render(); 345 | } 346 | } 347 | 348 | void MainWindow::updateCoords(vtkObject* obj) 349 | { 350 | vtkRenderWindowInteractor* iren = vtkRenderWindowInteractor::SafeDownCast(obj); 351 | int event_pos[2]; 352 | iren->GetEventPosition(event_pos); 353 | QString str; 354 | str.sprintf("Display Window Coordinate: x=%d , y=%d", event_pos[0], event_pos[1]); 355 | ui->statusBar->showMessage(str); 356 | 357 | } 358 | 359 | void MainWindow::on_levelsetButton_clicked() { 360 | if (m_readimagechanged) { 361 | m_GACDriver = new GACDriver(this, m_imagedata); 362 | m_gacpanel_dialog = new GACControlPanel(this, m_GACDriver); 363 | m_gacpanel_dialog->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); 364 | m_gacpanel_dialog->setAllowedAreas(Qt::AllDockWidgetAreas); 365 | addDockWidget(Qt::RightDockWidgetArea, m_gacpanel_dialog); 366 | m_readimagechanged = false; 367 | } 368 | else if (m_gacpanel_dialog){ 369 | addDockWidget(Qt::RightDockWidgetArea, m_gacpanel_dialog); 370 | } 371 | } -------------------------------------------------------------------------------- /src/GUI/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | #include "ui_mainwindow.h" 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | 25 | class ImageData; 26 | class GACDriver; 27 | class GACControlPanel; 28 | 29 | namespace Ui { 30 | class MainWindow; 31 | } 32 | 33 | class MainWindow : public QMainWindow 34 | { 35 | Q_OBJECT 36 | 37 | public: 38 | explicit MainWindow(QWidget *parent = nullptr); 39 | ~MainWindow(); 40 | 41 | public slots: 42 | void on_loadButton_clicked(); 43 | void on_saveButton_clicked(); 44 | void on_levelsetButton_clicked(); 45 | void updateCoords(vtkObject* obj); 46 | void screenChanged(); 47 | void show_originThumbnail(); 48 | void show_edgeThumbnail(); 49 | void show_gacThumbnail(); 50 | void display_thumbnail(int); 51 | 52 | public: 53 | void displayImage(); 54 | void display_setup(); 55 | void picker_setup(); 56 | void gac_reset(); 57 | 58 | public: 59 | Ui::MainWindow *ui; 60 | static const unsigned int Dimension = 2; 61 | using UCPixelType = unsigned char; 62 | using UCImageType = itk::Image< UCPixelType, Dimension >; 63 | using FloatPixelType = float; 64 | using FloatImageType = itk::Image< FloatPixelType, Dimension >; 65 | using ImageToVTKImageFilterType = itk::ImageToVTKImageFilter; 66 | 67 | vtkSmartPointer< vtkImageViewer2 > m_ImageViewer; 68 | vtkSmartPointer< vtkRenderer > m_Renderer; 69 | vtkSmartPointer< vtkImageViewer2 > m_BackGroundImageViewer; 70 | vtkSmartPointer< vtkRenderer > m_BackgroundRenderer; 71 | vtkEventQtSlotConnect* m_Connections; 72 | vtkSmartPointer m_propPicker; 73 | vtkSmartPointer m_cornerAnnotation; 74 | vtkSmartPointer m_callback; 75 | 76 | ImageData* m_imagedata = nullptr; 77 | GACDriver* m_GACDriver = nullptr; 78 | GACControlPanel* m_gacpanel_dialog = nullptr; 79 | QSignalMapper* m_signalMapper = nullptr; 80 | 81 | ImageToVTKImageFilterType::Pointer itkToVtk = ImageToVTKImageFilterType::New(); 82 | ImageToVTKImageFilterType::Pointer itkToVtk2 = ImageToVTKImageFilterType::New(); 83 | 84 | bool m_readimagechanged = false; 85 | int m_devicePixelRatio = 1; 86 | }; 87 | 88 | #endif // MAINWINDOW_H 89 | -------------------------------------------------------------------------------- /src/GUI/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 748 10 | 777 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | PointingHandCursor 24 | 25 | 26 | QPushButton{ 27 | background-color: DodgerBlue; 28 | border-style: outset; 29 | border-width: 2px; 30 | border-radius: 10px; 31 | border-color: beige; 32 | font: bold 14px; 33 | min-width: 10em; 34 | padding: 6px; 35 | } 36 | 37 | 38 | 39 | Save Image 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 0 48 | 0 49 | 50 | 51 | 52 | ArrowCursor 53 | 54 | 55 | 56 | 57 | 58 | 59 | PointingHandCursor 60 | 61 | 62 | QPushButton{ 63 | background-color: #FFEFD5; 64 | border-style: outset; 65 | border-width: 2px; 66 | border-radius: 10px; 67 | border-color: #CD853F; 68 | font: bold 14px; 69 | min-width: 10em; 70 | padding: 6px; 71 | } 72 | 73 | 74 | 75 | Start Level-Set Mode (Geodesic Active Contour) 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 0 84 | 0 85 | 86 | 87 | 88 | 89 | 100 90 | 80 91 | 92 | 93 | 94 | 95 | 100 96 | 80 97 | 98 | 99 | 100 | QFrame::Box 101 | 102 | 103 | level-set image 104 | 105 | 106 | Qt::AlignCenter 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 0 115 | 0 116 | 117 | 118 | 119 | PointingHandCursor 120 | 121 | 122 | QPushButton{ 123 | background-color: red; 124 | border-style: outset; 125 | border-width: 2px; 126 | border-radius: 10px; 127 | border-color: beige; 128 | font: bold 14px; 129 | min-width: 10em; 130 | padding: 6px; 131 | } 132 | 133 | 134 | Load Image 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 0 143 | 0 144 | 145 | 146 | 147 | 148 | 100 149 | 80 150 | 151 | 152 | 153 | 154 | 100 155 | 80 156 | 157 | 158 | 159 | QFrame::Box 160 | 161 | 162 | original image 163 | 164 | 165 | Qt::AlignCenter 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 0 174 | 0 175 | 176 | 177 | 178 | 179 | 100 180 | 80 181 | 182 | 183 | 184 | 185 | 100 186 | 80 187 | 188 | 189 | 190 | QFrame::Box 191 | 192 | 193 | edge image 194 | 195 | 196 | Qt::AlignCenter 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 0 208 | 0 209 | 748 210 | 22 211 | 212 | 213 | 214 | 215 | 216 | 217 | TopToolBarArea 218 | 219 | 220 | false 221 | 222 | 223 | 224 | 225 | 226 | 227 | QVTKOpenGLNativeWidget 228 | QOpenGLWidget 229 |
qvtkopenglnativewidget.h
230 |
231 | 232 | Thumbnail 233 | QLabel 234 |
Thumbnail.h
235 |
236 |
237 | 238 | 239 |
240 | -------------------------------------------------------------------------------- /src/GUI/vtkImageInteractionCallback.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 温雅 on 2019-05-05. 3 | // 4 | 5 | #include "vtkImageInteractionCallback.h" 6 | -------------------------------------------------------------------------------- /src/GUI/vtkImageInteractionCallback.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 温雅 on 2019-05-05. 3 | // 4 | 5 | #ifndef LEVELSET_VISUALIZER_VTKIMAGEINTERACTIONCALLBACK_H 6 | #define LEVELSET_VISUALIZER_VTKIMAGEINTERACTIONCALLBACK_H 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | 31 | // Template for image value reading 32 | template 33 | void vtkValueMessageTemplate(vtkImageData* image, int* position, 34 | std::string& message) 35 | { 36 | T* tuple = ((T*)image->GetScalarPointer(position)); 37 | int components = image->GetNumberOfScalarComponents(); 38 | for (int c = 0; c < components; ++c) 39 | { 40 | message += vtkVariant(tuple[c]).ToString(); 41 | if (c != (components - 1)) 42 | { 43 | message += ", "; 44 | } 45 | } 46 | message += " )"; 47 | } 48 | 49 | // The mouse motion m_callback, to pick the image and recover pixel values 50 | class vtkImageInteractionCallback : public vtkCommand 51 | { 52 | public: 53 | static vtkImageInteractionCallback *New() 54 | { 55 | return new vtkImageInteractionCallback; 56 | } 57 | 58 | vtkImageInteractionCallback() 59 | { 60 | this->Viewer = NULL; 61 | this->Picker = NULL; 62 | this->Annotation = NULL; 63 | } 64 | 65 | ~vtkImageInteractionCallback() 66 | { 67 | this->Viewer = NULL; 68 | this->Picker = NULL; 69 | this->Annotation = NULL; 70 | } 71 | 72 | void SetPicker(vtkPropPicker *picker) 73 | { 74 | this->Picker = picker; 75 | } 76 | 77 | void SetAnnotation(vtkCornerAnnotation *annotation) 78 | { 79 | this->Annotation = annotation; 80 | } 81 | 82 | void SetViewer(vtkImageViewer2 *viewer) 83 | { 84 | this->Viewer = viewer; 85 | } 86 | 87 | virtual void Execute(vtkObject *, unsigned long vtkNotUsed(event), void *) 88 | { 89 | vtkRenderWindowInteractor *interactor = 90 | this->Viewer->GetRenderWindow()->GetInteractor(); 91 | vtkRenderer* renderer = this->Viewer->GetRenderer(); 92 | vtkImageActor* actor = this->Viewer->GetImageActor(); 93 | vtkImageData* image = this->Viewer->GetInput(); 94 | vtkInteractorStyle *style = vtkInteractorStyle::SafeDownCast( 95 | interactor->GetInteractorStyle()); 96 | 97 | #if VTK_MAJOR_VERSION <= 5 98 | image->Update(); 99 | #endif 100 | 101 | int x = interactor->GetEventPosition()[0]; 102 | int y = interactor->GetEventPosition()[1]; 103 | int z = interactor->GetEventPosition()[2]; 104 | 105 | this->Picker->Pick(x, y, 0.0, renderer); 106 | // Pick at the mouse location provided by the interactor 107 | this->Picker->Pick(x, y, 0.0, renderer); 108 | 109 | // There could be other props assigned to this picker, so 110 | // make sure we picked the image actor 111 | vtkAssemblyPath* path = this->Picker->GetPath(); 112 | bool validPick = false; 113 | 114 | if (path) 115 | { 116 | vtkCollectionSimpleIterator sit; 117 | path->InitTraversal(sit); 118 | vtkAssemblyNode *node; 119 | for (int i = 0; i < path->GetNumberOfItems() && !validPick; ++i) 120 | { 121 | node = path->GetNextNode(sit); 122 | if (actor == vtkImageActor::SafeDownCast(node->GetViewProp())) 123 | { 124 | validPick = true; 125 | } 126 | } 127 | } 128 | 129 | if (!validPick) 130 | { 131 | this->Annotation->SetText(0, "Off Image"); 132 | interactor->Render(); 133 | return; 134 | } 135 | 136 | // Get the world coordinates of the pick 137 | double pos[3]; 138 | this->Picker->GetPickPosition(pos); 139 | 140 | 141 | int axis = this->Viewer->GetSliceOrientation(); 142 | switch (axis) 143 | { 144 | case vtkImageViewer2::SLICE_ORIENTATION_XZ: 145 | image_coordinate[0] = vtkMath::Round(pos[0]); 146 | image_coordinate[1] = this->Viewer->GetSlice(); 147 | image_coordinate[2] = vtkMath::Round(pos[2]); 148 | break; 149 | case vtkImageViewer2::SLICE_ORIENTATION_YZ: 150 | image_coordinate[0] = this->Viewer->GetSlice(); 151 | image_coordinate[1] = vtkMath::Round(pos[0]); 152 | image_coordinate[2] = vtkMath::Round(pos[1]); 153 | break; 154 | default: // vtkImageViewer2::SLICE_ORIENTATION_XY 155 | image_coordinate[0] = vtkMath::Round(pos[0]); 156 | image_coordinate[1] = vtkMath::Round(pos[1]); 157 | image_coordinate[2] = this->Viewer->GetSlice(); 158 | break; 159 | } 160 | 161 | std::string message = "Location: ( "; 162 | message += vtkVariant(image_coordinate[0]).ToString(); 163 | message += ", "; 164 | message += vtkVariant(image_coordinate[1]).ToString(); 165 | // message += ", "; 166 | // message += vtkVariant(image_coordinate[2]).ToString(); 167 | message += " )\nValue: ( "; 168 | 169 | switch (image->GetScalarType()) 170 | { 171 | vtkTemplateMacro((vtkValueMessageTemplate(image, 172 | image_coordinate, 173 | message))); 174 | default: 175 | return; 176 | } 177 | 178 | this->Annotation->SetText( 0, message.c_str() ); 179 | interactor->Render(); 180 | } 181 | 182 | public: 183 | int image_coordinate[3]; 184 | 185 | private: 186 | vtkImageViewer2* Viewer; // Pointer to the viewer 187 | vtkPropPicker* Picker; // Pointer to the picker 188 | vtkCornerAnnotation* Annotation; // Pointer to the annotation 189 | }; 190 | 191 | 192 | #endif //LEVELSET_VISUALIZER_VTKIMAGEINTERACTIONCALLBACK_H -------------------------------------------------------------------------------- /src/Logic/GACDriver.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 温雅 on 2019-04-29. 3 | // 4 | 5 | #include "GACDriver.h" 6 | #include "GACParameters.h" 7 | #include "ImageData.h" 8 | #include 9 | 10 | 11 | GACDriver::GACDriver(MainWindow* mainWindow, ImageData* imageData) { 12 | m_gacparameters = new GACParameters(); 13 | m_mainwindow = mainWindow; 14 | m_imagedata = imageData; 15 | // 用caster把Float轉UC再display 16 | caster_filtering(); 17 | } 18 | 19 | void GACDriver::smoothing_filtering(FloatImageType::Pointer inputimage) { 20 | smoothing->SetTimeStep( 0.125 ); 21 | smoothing->SetNumberOfIterations( m_gacparameters->m_aditer ); 22 | smoothing->SetConductanceParameter( m_gacparameters->m_conductance ); 23 | smoothing->SetInput( inputimage ); 24 | m_gacparameters->m_smoothingImage = smoothing->GetOutput(); 25 | 26 | } 27 | 28 | void GACDriver::gradient_filtering(FloatImageType::Pointer inputimage) { 29 | gradientMagnitude->SetInput( inputimage ); 30 | m_gacparameters->m_gradientImage = gradientMagnitude->GetOutput(); 31 | } 32 | 33 | void GACDriver::sigmoid_filtering(FloatImageType::Pointer inputimage) { 34 | sigmoid->SetOutputMinimum( 0.0 ); 35 | sigmoid->SetOutputMaximum( 1.0 ); 36 | sigmoid->SetInput( inputimage ); 37 | m_gacparameters->m_sigmoidImage = sigmoid->GetOutput(); 38 | 39 | // display 40 | caster->SetInput(m_gacparameters->m_sigmoidImage); 41 | m_imagedata->m_frontground_image = caster->GetOutput(); 42 | m_imagedata->m_tempUCedge_image = caster->GetOutput(); 43 | m_mainwindow->displayImage(); 44 | 45 | m_mainwindow->show_edgeThumbnail(); 46 | } 47 | 48 | void GACDriver::fastmarching_filtering(FloatImageType::Pointer inputimage) { 49 | using NodeContainer = FastMarchingFilterType::NodeContainer; 50 | 51 | NodeContainer::Pointer seeds = NodeContainer::New(); 52 | seeds->Initialize(); 53 | for (int i=0; i < node_list.size() ; i++){ 54 | seeds->InsertElement( i, node_list[i] ); 55 | } 56 | 57 | fastMarching->SetTrialPoints( seeds ); 58 | fastMarching->SetSpeedConstant( 1.0 ); 59 | fastMarching->SetOutputSize( inputimage->GetBufferedRegion().GetSize() ); 60 | m_gacparameters->m_fastmarchingImage = fastMarching->GetOutput(); 61 | } 62 | 63 | void GACDriver::initial_gacfilter() { 64 | geodesicActiveContour->SetInput( m_gacparameters->m_fastmarchingImage ); 65 | geodesicActiveContour->SetFeatureImage( m_gacparameters->m_sigmoidImage ); 66 | geodesicActiveContour->SetManualReinitialization(true); 67 | geodesicActiveContour->SetNumberOfIterations(0); 68 | geodesicActiveContour->UpdateLargestPossibleRegion(); 69 | } 70 | 71 | void GACDriver::threshold_filtering() { 72 | thresholder->SetLowerThreshold( -1000.0 ); 73 | thresholder->SetUpperThreshold( 0.0 ); 74 | thresholder->SetOutsideValue( itk::NumericTraits< UCPixelType >::min() ); 75 | thresholder->SetInsideValue( itk::NumericTraits< UCPixelType >::max() ); 76 | thresholder->SetInput( geodesicActiveContour->GetOutput() ); 77 | } 78 | 79 | void GACDriver::reset_gacfilter() { 80 | // delete anchor image 81 | m_gacparameters->m_anchorImage = nullptr; 82 | 83 | set_gac_parameter(); 84 | 85 | geodesicActiveContour->SetInput( m_gacparameters->m_fastmarchingImage ); 86 | geodesicActiveContour->SetStateToUninitialized(); 87 | geodesicActiveContour->SetNumberOfIterations(0); 88 | 89 | display_update(); 90 | emit iterationChange(); 91 | emit filterReset(); 92 | } 93 | 94 | void GACDriver::caster_filtering() { 95 | caster->SetOutputMinimum( itk::NumericTraits< UCPixelType >::min() ); 96 | caster->SetOutputMaximum( itk::NumericTraits< UCPixelType >::max() ); 97 | } 98 | 99 | void GACDriver::run_segmentation(){ 100 | geodesicActiveContour->SetNumberOfIterations(geodesicActiveContour->GetElapsedIterations() + 1); 101 | geodesicActiveContour->UpdateLargestPossibleRegion(); 102 | 103 | if ((geodesicActiveContour->GetElapsedIterations()-m_stepanchor) % m_stepsize==0){ 104 | display_update(); 105 | emit iterationChange(); 106 | } 107 | } 108 | 109 | void GACDriver::display_update(){ 110 | thresholder->Update(); 111 | m_imagedata->m_frontground_image = thresholder->GetOutput(); 112 | m_mainwindow->displayImage(); 113 | } 114 | 115 | void GACDriver::save_anchorimage() { 116 | using DuplicatorType = itk::ImageDuplicator< FloatImageType >; 117 | DuplicatorType::Pointer duplicator = DuplicatorType::New(); 118 | duplicator->SetInputImage(geodesicActiveContour->GetOutput()); 119 | duplicator->Update(); 120 | m_gacparameters->m_anchorImage = duplicator->GetOutput(); 121 | m_gacparameters->m_anchorIter += geodesicActiveContour->GetElapsedIterations(); 122 | load_anchorimage(); 123 | } 124 | 125 | void GACDriver::load_anchorimage() { 126 | geodesicActiveContour->SetStateToUninitialized(); 127 | geodesicActiveContour->SetInput(m_gacparameters->m_anchorImage); 128 | geodesicActiveContour->SetNumberOfIterations(0); 129 | geodesicActiveContour->UpdateLargestPossibleRegion(); 130 | display_update(); 131 | } 132 | 133 | void GACDriver::backgroundimage_changed(){ 134 | m_mainwindow->displayImage(); 135 | } 136 | 137 | void GACDriver::set_gac_parameter(){ 138 | geodesicActiveContour->SetMaximumRMSError( m_gacparameters->m_maximumRMSError ); 139 | geodesicActiveContour->SetPropagationScaling(m_gacparameters->m_propagationScaling); 140 | geodesicActiveContour->SetCurvatureScaling(m_gacparameters->m_curvatureScaling); 141 | geodesicActiveContour->SetAdvectionScaling(m_gacparameters->m_advectionScaling); 142 | m_gacparameters->m_anchorIter=0; 143 | } 144 | 145 | void GACDriver::seed_record(){ 146 | m_gacparameters->m_seedPosX = m_mainwindow->m_callback->image_coordinate[0]; 147 | m_gacparameters->m_seedPosY = m_mainwindow->m_callback->image_coordinate[1]; 148 | emit seedClicked(); 149 | } 150 | 151 | void GACDriver::set_edge_parameters() { 152 | gradientMagnitude->SetSigma( m_gacparameters->m_sigma ); 153 | sigmoid->SetAlpha( m_gacparameters->m_alpha ); 154 | sigmoid->SetBeta( m_gacparameters->m_beta ); 155 | } 156 | 157 | // deprecated 158 | void GACDriver::set_fm_parameters() { 159 | seedPosition[0] = m_gacparameters->m_seedPosX; 160 | seedPosition[1] = m_gacparameters->m_seedPosY; 161 | node.SetValue( m_gacparameters->m_seedValue ); 162 | node.SetIndex( seedPosition ); 163 | } 164 | 165 | void GACDriver::initial_bubble_image(){ 166 | m_gacparameters->m_bubbleImage = UCImageType::New(); 167 | UCImageType::RegionType region = m_imagedata->m_readimage->GetLargestPossibleRegion(); 168 | UCImageType::SizeType size = region.GetSize(); 169 | m_gacparameters->m_bubbleImage->SetRegions(region); 170 | m_gacparameters->m_bubbleImage->Allocate(true); 171 | } 172 | 173 | void GACDriver::create_bubble_image(){ 174 | // Disconnect 175 | m_gacparameters->m_bubbleImage->DisconnectPipeline(); 176 | 177 | UCImageType ::RegionType region = m_gacparameters->m_bubbleImage->GetLargestPossibleRegion(); 178 | UCImageType::SizeType size = region.GetSize(); 179 | 180 | double radius=5; 181 | int x=m_gacparameters->m_seedPosX , y=m_gacparameters->m_seedPosY; 182 | for(int row = 0; row < size.m_Size[0]; row++) 183 | { 184 | for(int col = 0; col < size.m_Size[1]; col++) 185 | { 186 | UCImageType::IndexType pixelIndex; 187 | pixelIndex[0] = row; 188 | pixelIndex[1] = col; 189 | 190 | if ( sqrt(pow(row-x, 2)+pow(col-y, 2)) < radius){ 191 | m_gacparameters->m_bubbleImage->SetPixel(pixelIndex, 255); 192 | } 193 | } 194 | } 195 | m_imagedata->m_frontground_image = m_gacparameters->m_bubbleImage; 196 | m_mainwindow->displayImage(); 197 | } -------------------------------------------------------------------------------- /src/Logic/GACDriver.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 温雅 on 2019-04-29. 3 | // 4 | 5 | #ifndef LEVELSET_VISUALIZER_GACDRIVER_H 6 | #define LEVELSET_VISUALIZER_GACDRIVER_H 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | class GACParameters; 20 | class MainWindow; 21 | class ImageData; 22 | 23 | class GACDriver : public QObject{ 24 | 25 | Q_OBJECT 26 | 27 | public: 28 | GACDriver(MainWindow*, ImageData*); 29 | ~GACDriver() = default; 30 | 31 | public: 32 | static constexpr unsigned int Dimension = 2; 33 | using FloatPixelType = float; 34 | using FloatImageType = itk::Image< FloatPixelType, Dimension >; 35 | using UCPixelType = unsigned char; 36 | using UCImageType = itk::Image< UCPixelType, Dimension >; 37 | using GeodesicActiveContourFilterType = itk::GeodesicActiveContourLevelSetImageFilter< FloatImageType, FloatImageType >; 38 | using SmoothingFilterType = itk::CurvatureAnisotropicDiffusionImageFilter< FloatImageType, FloatImageType >; 39 | using GradientFilterType = itk::GradientMagnitudeRecursiveGaussianImageFilter< FloatImageType, FloatImageType >; 40 | using SigmoidFilterType = itk::SigmoidImageFilter< FloatImageType, FloatImageType >; 41 | using FastMarchingFilterType = itk::FastMarchingImageFilter< FloatImageType, FloatImageType >; 42 | using RescaleFilterType = itk::RescaleIntensityImageFilter< FloatImageType, UCImageType >; 43 | using ThresholdingFilterType = itk::BinaryThresholdImageFilter< FloatImageType, UCImageType >; 44 | using NodeType = FastMarchingFilterType::NodeType; 45 | 46 | public slots: 47 | void run_segmentation(); 48 | void set_gac_parameter(); 49 | void seed_record(); 50 | 51 | signals: 52 | void seedClicked(); 53 | void iterationChange(); 54 | void filterReset(); 55 | 56 | public: 57 | void smoothing_filtering(FloatImageType::Pointer); 58 | void gradient_filtering(FloatImageType::Pointer); 59 | void sigmoid_filtering(FloatImageType::Pointer); 60 | void fastmarching_filtering(FloatImageType::Pointer); 61 | void threshold_filtering(); 62 | void initial_gacfilter(); 63 | void caster_filtering(); 64 | void reset_gacfilter(); 65 | void set_edge_parameters(); 66 | void set_fm_parameters(); 67 | void create_bubble_image(); 68 | void initial_bubble_image(); 69 | void backgroundimage_changed(); 70 | void save_anchorimage(); 71 | void load_anchorimage(); 72 | void display_update(); 73 | 74 | public: 75 | SmoothingFilterType::Pointer smoothing = SmoothingFilterType::New(); 76 | GradientFilterType::Pointer gradientMagnitude = GradientFilterType::New(); 77 | SigmoidFilterType::Pointer sigmoid = SigmoidFilterType::New(); 78 | FastMarchingFilterType::Pointer fastMarching = FastMarchingFilterType::New(); 79 | GeodesicActiveContourFilterType::Pointer geodesicActiveContour = GeodesicActiveContourFilterType::New(); 80 | RescaleFilterType::Pointer caster = RescaleFilterType::New(); 81 | ThresholdingFilterType::Pointer thresholder = ThresholdingFilterType::New(); 82 | FloatImageType::IndexType seedPosition; 83 | NodeType node; 84 | std::vector node_list; 85 | 86 | GACParameters* m_gacparameters = nullptr; 87 | MainWindow* m_mainwindow = nullptr; 88 | ImageData* m_imagedata = nullptr; 89 | 90 | int m_stepsize = 1; 91 | int m_stepanchor = 0; 92 | 93 | }; 94 | 95 | #endif //LEVELSET_VISUALIZER_GACDRIVER_H 96 | -------------------------------------------------------------------------------- /src/Logic/MyThread.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 温雅 on 2019-04-15. 3 | // 4 | 5 | #include "MyThread.h" 6 | #include "GACDriver.h" 7 | #include "ImageData.h" 8 | #include "GACParameters.h" 9 | 10 | MyThread::MyThread(QObject *parent, GACDriver* gacDriver) : QThread(parent) 11 | { 12 | myTimer = new QTimer(this); 13 | m_GACDriver = gacDriver; 14 | QObject::connect(myTimer,SIGNAL(timeout()), m_GACDriver, SLOT(run_segmentation())); 15 | } 16 | 17 | 18 | void MyThread::run(){ 19 | } 20 | 21 | void MyThread::stop_evaluation() { 22 | myTimer->stop(); 23 | } 24 | 25 | void MyThread::play_evaluation() { 26 | myTimer->start(10); 27 | } 28 | 29 | void MyThread::restart_evaluation() { 30 | 31 | m_GACDriver->reset_gacfilter(); 32 | 33 | } 34 | 35 | -------------------------------------------------------------------------------- /src/Logic/MyThread.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 温雅 on 2019-04-15. 3 | // 4 | 5 | #ifndef GACQVTK_MYTHREAD_H 6 | #define GACQVTK_MYTHREAD_H 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | class GACDriver; 14 | 15 | class MyThread : public QThread{ 16 | Q_OBJECT 17 | 18 | public: 19 | MyThread(QObject *parent = 0, GACDriver* = 0); 20 | void run(); 21 | void stop_evaluation(); 22 | void play_evaluation(); 23 | void restart_evaluation(); 24 | 25 | signals: 26 | 27 | public slots: 28 | 29 | 30 | public: 31 | bool STOP{false}; 32 | QTimer* myTimer = nullptr; 33 | GACDriver* m_GACDriver = nullptr; 34 | 35 | public: 36 | static const unsigned int Dimension = 2; 37 | using UCPixelType = unsigned char; 38 | using UCImageType = itk::Image< UCPixelType, Dimension >; 39 | using FloatPixelType = float; 40 | using FloatImageType = itk::Image< FloatPixelType, Dimension >; 41 | 42 | }; 43 | 44 | 45 | #endif //GACQVTK_MYTHREAD_H 46 | -------------------------------------------------------------------------------- /src/Model/GACParameters.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 温雅 on 2019-04-29. 3 | // 4 | 5 | #include "GACParameters.h" 6 | -------------------------------------------------------------------------------- /src/Model/GACParameters.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 温雅 on 2019-04-29. 3 | // 4 | 5 | #ifndef LEVELSET_VISUALIZER_GACPARAMETERS_H 6 | #define LEVELSET_VISUALIZER_GACPARAMETERS_H 7 | 8 | 9 | #include 10 | #include "mainwindow.h" 11 | 12 | class GACParameters { 13 | 14 | public: 15 | GACParameters() = default; 16 | ~GACParameters() = default; 17 | 18 | public: 19 | static constexpr unsigned int Dimension = 2; 20 | using FloatPixelType = float; 21 | using FloatImageType = itk::Image< FloatPixelType, Dimension >; 22 | using UCPixelType = unsigned char; 23 | using UCImageType = itk::Image< UCPixelType, Dimension >; 24 | 25 | public: 26 | int m_seedPosX = 56; 27 | int m_seedPosY = 92; 28 | double m_initialDistance = 5.; 29 | double m_sigma = 1.; 30 | double m_alpha = -0.3; 31 | double m_beta = 2.0; 32 | double m_propagationScaling = 10.; 33 | double m_curvatureScaling = 1.; 34 | double m_advectionScaling = 1.; 35 | double m_maximumRMSError = 0.002; 36 | double m_seedValue = - m_initialDistance; 37 | 38 | int m_radius = 5.; 39 | 40 | int m_aditer = 5; 41 | int m_conductance = 9.0; 42 | int m_anchorIter = 0; 43 | 44 | 45 | FloatImageType::Pointer m_smoothingImage; 46 | FloatImageType::Pointer m_gradientImage; 47 | FloatImageType::Pointer m_sigmoidImage; 48 | FloatImageType::Pointer m_fastmarchingImage; 49 | FloatImageType::Pointer m_anchorImage; 50 | UCImageType::Pointer m_thresholdImage; 51 | UCImageType::Pointer m_bubbleImage; 52 | 53 | }; 54 | 55 | 56 | #endif //LEVELSET_VISUALIZER_GACPARAMETERS_H 57 | -------------------------------------------------------------------------------- /src/Model/ImageData.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 温雅 on 2019-04-29. 3 | // 4 | 5 | #include "ImageData.h" 6 | #include 7 | #include 8 | 9 | #include "mainwindow.h" 10 | 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | ImageData::ImageData(MainWindow *window){ 17 | m_mainwindow = window; 18 | } 19 | 20 | ImageData::~ImageData(){ 21 | 22 | } 23 | 24 | void ImageData::loadImage(){ 25 | 26 | QString fname = QFileDialog::getOpenFileName(m_mainwindow, QObject::tr("Load Image"), qApp->applicationDirPath(), "Image Files (*.jpg *.png *.bmp *.dcm *DCM)"); 27 | qDebug() << fname; 28 | 29 | if (!fname.isNull()) { 30 | QByteArray byteArray = fname.toLocal8Bit(); 31 | const char *inputFileName = byteArray.data(); 32 | 33 | ReaderType::Pointer reader = ReaderType::New(); 34 | reader->SetFileName(inputFileName); 35 | reader->Update(); 36 | 37 | m_readimage = reader->GetOutput(); 38 | 39 | m_frontground_image = m_readimage; 40 | 41 | m_mainwindow->m_readimagechanged = true; 42 | 43 | UCImageType ::RegionType region = m_readimage->GetLargestPossibleRegion(); 44 | UCImageType::SizeType size = region.GetSize(); 45 | 46 | m_imagecenter[0] = size.m_Size[0]/2.; 47 | m_imagecenter[1] = size.m_Size[1]/2.; 48 | 49 | } 50 | else { 51 | m_mainwindow->m_readimagechanged = false; 52 | } 53 | } 54 | 55 | void ImageData::saveImage(){ 56 | QString fname = QFileDialog::getSaveFileName(m_mainwindow, QObject::tr("Save Image"), "", "(*.png)"); 57 | QByteArray byteArray = fname.toLocal8Bit(); 58 | const char *outputFileName = byteArray.data(); 59 | 60 | using WriterType = itk::ImageFileWriter< UCImageType >; 61 | WriterType::Pointer writer = WriterType::New(); 62 | writer->SetFileName(outputFileName); 63 | writer->SetInput(m_frontground_image); 64 | try 65 | { 66 | writer->Update(); 67 | } 68 | catch( itk::ExceptionObject & error ) 69 | { 70 | std::cerr << "Error: " << error << std::endl; 71 | } 72 | } 73 | 74 | ImageData::FloatImageType::Pointer ImageData::unsignedchar2float(UCImageType::Pointer ucimage) { 75 | using RescaleType = itk::RescaleIntensityImageFilter< UCImageType , UCImageType >; 76 | RescaleType::Pointer rescale = RescaleType::New(); 77 | rescale->SetInput( ucimage ); 78 | rescale->SetOutputMinimum( 0 ); 79 | rescale->SetOutputMaximum( itk::NumericTraits< UCPixelType >::max() ); 80 | rescale->Update(); 81 | 82 | using FilterType = itk::CastImageFilter< UCImageType, FloatImageType >; 83 | FilterType::Pointer filter = FilterType::New(); 84 | filter->SetInput( rescale->GetOutput() ); 85 | filter->Update(); 86 | 87 | return filter->GetOutput(); 88 | } -------------------------------------------------------------------------------- /src/Model/ImageData.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 温雅 on 2019-04-29. 3 | // 4 | 5 | #ifndef LEVELSET_VISUALIZER_IMAGEDATA_H 6 | #define LEVELSET_VISUALIZER_IMAGEDATA_H 7 | 8 | #include 9 | #include 10 | 11 | 12 | class MainWindow; 13 | 14 | 15 | class ImageData { 16 | 17 | 18 | public: 19 | ImageData(MainWindow*); 20 | ~ImageData(); 21 | 22 | // image in itk format 23 | public: 24 | static const unsigned int Dimension = 2; 25 | using UCPixelType = unsigned char; 26 | using UCImageType = itk::Image< UCPixelType, Dimension >; 27 | using FloatPixelType = float; 28 | using FloatImageType = itk::Image< FloatPixelType, Dimension >; 29 | using ReaderType = itk::ImageFileReader< UCImageType >; 30 | 31 | float m_imagecenter[2]; 32 | 33 | UCImageType::Pointer m_readimage = nullptr; 34 | UCImageType::Pointer m_background_image = nullptr; 35 | UCImageType::Pointer m_frontground_image = nullptr; 36 | UCImageType::Pointer m_tempUCedge_image = nullptr; 37 | 38 | MainWindow* m_mainwindow = nullptr; 39 | 40 | public: 41 | void loadImage(); 42 | void saveImage(); 43 | FloatImageType::Pointer unsignedchar2float(UCImageType::Pointer); 44 | }; 45 | 46 | 47 | #endif //LEVELSET_VISUALIZER_IMAGEDATA_H 48 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | // needed to ensure appropriate OpenGL context is created for VTK rendering. 11 | QSurfaceFormat::setDefaultFormat(QVTKOpenGLNativeWidget::defaultFormat()); 12 | QApplication a(argc, argv); 13 | 14 | 15 | 16 | QScreen *screen = a.primaryScreen(); 17 | // QFont f = a.font(); 18 | // int pixelSize = (f.pointSize() * screen->logicalDotsPerInch()) / 72; 19 | // double bb = screen->devicePixelRatio(); 20 | // std::cout << bb; 21 | // f.setPointSize(25); 22 | // a.setFont(f); 23 | // int newPixelSize = (f.pointSize() * screen->logicalDotsPerInch()) / 72; 24 | 25 | 26 | 27 | 28 | MainWindow w; 29 | w.show(); 30 | 31 | return a.exec(); 32 | } -------------------------------------------------------------------------------- /src/resources/iconfinder_pause_2561367.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/resources/iconfinder_play_2561370.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/resources/iconfinder_rewind_2561378.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/resources/iconfinder_skip-forward_2561275.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenyalintw/Level-Set-Visualizer/36646f6b24fd0386b4f82e01bcfa0bf0e88fa9eb/src/test.png --------------------------------------------------------------------------------