├── .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 |
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 |
46 |
47 |
48 | ### Initial Contour
49 | - Done by [Fast Marching](https://itk.org/Doxygen/html/classitk_1_1FastMarchingImageFilter.html), support multiple bubbles
50 |
51 |
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 |
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 |
214 |
215 |
216 |
217 | TopToolBarArea
218 |
219 |
220 | false
221 |
222 |
223 |
224 |
225 |
226 |
227 | QVTKOpenGLNativeWidget
228 | QOpenGLWidget
229 |
230 |
231 |
232 | Thumbnail
233 | QLabel
234 |
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
--------------------------------------------------------------------------------