├── CMakeLists.txt ├── main.cxx ├── mainwindow.cxx ├── mainwindow.h └── mainwindow.ui /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | if(POLICY CMP0020) 4 | cmake_policy(SET CMP0020 NEW) 5 | endif() 6 | 7 | PROJECT(medicalQT) 8 | 9 | SET(VTK_DIR D:/VTK/VTK-8.1.2-bin) 10 | 11 | find_package(VTK REQUIRED) 12 | include(${VTK_USE_FILE}) 13 | 14 | if(${VTK_VERSION} VERSION_GREATER "6" AND VTK_QT_VERSION VERSION_GREATER "4") 15 | # Instruct CMake to run moc automatically when needed. 16 | set(CMAKE_AUTOMOC ON) 17 | find_package(Qt5Widgets REQUIRED QUIET) 18 | else() 19 | find_package(Qt4 REQUIRED) 20 | include(${QT_USE_FILE}) 21 | endif() 22 | 23 | include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) 24 | 25 | file(GLOB UI_FILES *.ui) 26 | file(GLOB QT_WRAP *.h) 27 | file(GLOB CXX_FILES *.cxx) 28 | 29 | if(${VTK_VERSION} VERSION_GREATER "6" AND VTK_QT_VERSION VERSION_GREATER "4") 30 | qt5_wrap_ui(UISrcs ${UI_FILES} ) 31 | # CMAKE_AUTOMOC in ON so the MOC headers will be automatically wrapped. 32 | add_executable(medicalQT MACOSX_BUNDLE 33 | ${CXX_FILES} ${UISrcs} ${QT_WRAP}) 34 | qt5_use_modules(medicalQT Core Gui) 35 | target_link_libraries(medicalQT ${VTK_LIBRARIES}) 36 | else() 37 | QT4_WRAP_UI(UISrcs ${UI_FILES}) 38 | QT4_WRAP_CPP(MOCSrcs ${QT_WRAP}) 39 | add_executable(medicalQT MACOSX_BUNDLE ${CXX_FILES} ${UISrcs} ${MOCSrcs}) 40 | target_link_libraries(medicalQT ${VTK_LIBRARIES}) 41 | endif() 42 | -------------------------------------------------------------------------------- /main.cxx: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | #include 5 | #include "QVTKOpenGLWidget.h" 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | //需要确保为VTK渲染创建适当的OpenGL上下文。 10 | QSurfaceFormat::setDefaultFormat(QVTKOpenGLWidget::defaultFormat()); 11 | 12 | // QT 13 | QApplication a(argc, argv); 14 | MainWindow w; 15 | w.show(); 16 | 17 | return a.exec(); 18 | } 19 | -------------------------------------------------------------------------------- /mainwindow.cxx: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "vtkGenericOpenGLRenderWindow.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | 38 | #include"vtkCommand.h" 39 | #include"vtkSliderWidget.h" 40 | #include"vtkSliderRepresentation2D.h" 41 | #include"vtkProperty.h" 42 | 43 | //test 44 | #include 45 | #include 46 | #include 47 | 48 | #include 49 | #include 50 | 51 | #include 52 | #include 53 | #include 54 | #include 55 | 56 | #include 57 | #include 58 | 59 | #include 60 | 61 | #include 62 | 63 | #include 64 | #include 65 | 66 | //切片状态信息 67 | class StatusMessage { 68 | public: 69 | static std::string Format(int slice, int maxSlice) { 70 | std::stringstream tmp; 71 | tmp << " Slice Number " << slice + 1 << "/" << maxSlice + 1; 72 | return tmp.str(); 73 | } 74 | }; 75 | 76 | //切片交互方式 77 | class myVtkInteractorStyleImage : public vtkInteractorStyleImage 78 | { 79 | public: 80 | static myVtkInteractorStyleImage* New(); 81 | vtkTypeMacro(myVtkInteractorStyleImage, vtkInteractorStyleImage); 82 | 83 | protected: 84 | vtkImageViewer2* _ImageViewer; 85 | vtkTextMapper* _StatusMapper; 86 | int _Slice; 87 | int _MinSlice; 88 | int _MaxSlice; 89 | 90 | public: 91 | void SetImageViewer(vtkImageViewer2* imageViewer) { 92 | _ImageViewer = imageViewer; 93 | _MinSlice = imageViewer->GetSliceMin(); 94 | _MaxSlice = imageViewer->GetSliceMax(); 95 | _Slice = _MaxSlice/2; 96 | cout << "Slicer: Min = " << _MinSlice << ", Max = " << _MaxSlice << std::endl; 97 | } 98 | 99 | void SetStatusMapper(vtkTextMapper* statusMapper) { 100 | _StatusMapper = statusMapper; 101 | } 102 | 103 | 104 | protected: 105 | void MoveSliceForward() { 106 | if(_Slice < _MaxSlice) { 107 | _Slice += 1; 108 | cout << "MoveSliceForward::Slice = " << _Slice << std::endl; 109 | _ImageViewer->SetSlice(_Slice); 110 | std::string msg = StatusMessage::Format(_Slice, _MaxSlice); 111 | _StatusMapper->SetInput(msg.c_str()); 112 | _ImageViewer->Render(); 113 | } 114 | } 115 | 116 | void MoveSliceBackward() { 117 | if(_Slice > _MinSlice) { 118 | _Slice -= 1; 119 | cout << "MoveSliceBackward::Slice = " << _Slice << std::endl; 120 | _ImageViewer->SetSlice(_Slice); 121 | std::string msg = StatusMessage::Format(_Slice, _MaxSlice); 122 | _StatusMapper->SetInput(msg.c_str()); 123 | _ImageViewer->Render(); 124 | } 125 | } 126 | 127 | 128 | virtual void OnKeyDown() { 129 | std::string key = this->GetInteractor()->GetKeySym(); 130 | if(key.compare("Up") == 0) { 131 | //cout << "Up arrow key was pressed." << endl; 132 | MoveSliceForward(); 133 | } 134 | else if(key.compare("Down") == 0) { 135 | //cout << "Down arrow key was pressed." << endl; 136 | MoveSliceBackward(); 137 | } 138 | // forward event 139 | vtkInteractorStyleImage::OnKeyDown(); 140 | } 141 | 142 | 143 | virtual void OnMouseWheelForward() { 144 | //std::cout << "Scrolled mouse wheel forward." << std::endl; 145 | MoveSliceForward(); 146 | // don't forward events, otherwise the image will be zoomed 147 | // in case another interactorstyle is used (e.g. trackballstyle, ...) 148 | // vtkInteractorStyleImage::OnMouseWheelForward(); 149 | } 150 | 151 | 152 | virtual void OnMouseWheelBackward() { 153 | //std::cout << "Scrolled mouse wheel backward." << std::endl; 154 | if(_Slice > _MinSlice) { 155 | MoveSliceBackward(); 156 | } 157 | // don't forward events, otherwise the image will be zoomed 158 | // in case another interactorstyle is used (e.g. trackballstyle, ...) 159 | // vtkInteractorStyleImage::OnMouseWheelBackward(); 160 | } 161 | }; 162 | 163 | vtkStandardNewMacro(myVtkInteractorStyleImage); 164 | 165 | /* //使用滑块选择切片.......... 166 | class sliceSliderCallback:: public vtkCommand 167 | { 168 | public 169 | static sliceSliderCallback *New() 170 | { 171 | return new sliceSliderCallback; 172 | } 173 | void Execute(vtkObject *caller, unsigned long, void *) 174 | { 175 | vtkSliderWidget *sliderWidget = reinterpret_cast(caller); 176 | this->sliderer->SetsliSlice(value); 177 | } 178 | sliceSliderCallback():sliderer(nullptr) {} 179 | } */ 180 | 181 | MainWindow::MainWindow(QWidget *parent) : 182 | QMainWindow(parent), 183 | ui(new Ui::MainWindow) 184 | { 185 | ui->setupUi(this); 186 | 187 | //cout << "begin" << endl; 188 | 189 | vtkNew renderWindowLeft; 190 | this->ui->qvtkWidgetLeft->SetRenderWindow(renderWindowLeft); 191 | 192 | vtkNew renderWindowRight; 193 | this->ui->qvtkWidgetRight->SetRenderWindow(renderWindowRight); 194 | 195 | vtkNew renderWindowDLeft; 196 | this->ui->qvtkWidgetDLeft->SetRenderWindow(renderWindowDLeft); 197 | 198 | vtkNew renderWindowDRight; 199 | this->ui->qvtkWidgetDRight->SetRenderWindow(renderWindowDRight); 200 | 201 | connect(this->ui->action_close,SIGNAL(triggered()), this, SLOT(closeThis())); 202 | 203 | connect(this->ui->action_input, SIGNAL(triggered()), this, SLOT(input())); 204 | 205 | connect(this->ui->action_exportInf, SIGNAL(triggered()),this, SLOT(exportInf())); 206 | 207 | connect(this->ui->action_anatomyView, SIGNAL(triggered()),this, SLOT(anatomyView())); 208 | 209 | connect(this->ui->action_exportSTL, SIGNAL(triggered()),this, SLOT(exportSTL())); 210 | 211 | connect(this->ui->MarchingCubes, SIGNAL(triggered()), this, SLOT(modelMaker_marchingCubes())); 212 | 213 | connect(this->ui->DividingCubes, SIGNAL(triggered()),this, SLOT(model_autoRepair())); 214 | } 215 | 216 | 217 | MainWindow::~MainWindow() 218 | { 219 | delete ui; 220 | } 221 | 222 | 223 | void MainWindow::closeThis() 224 | { 225 | this->close(); 226 | } 227 | 228 | 229 | void MainWindow::input() 230 | { 231 | // read DICOM 232 | QDir dir; 233 | QString file_path = QFileDialog::getExistingDirectory( this, "请选择DICOM文件所在文件夹"); 234 | if ( file_path.isEmpty() == true ) return; 235 | 236 | // 支持带中文路径的读取 237 | QByteArray ba = file_path.toLocal8Bit(); 238 | const char *file_path_str = ba.data(); 239 | 240 | QString file_path_str_q; 241 | file_path_str_q = file_path_str; 242 | ui->text_inf->append("Choose File:\n" + file_path_str_q); 243 | 244 | vtkSmartPointer DICOMreader = vtkSmartPointer::New(); 245 | DICOMreader->SetDirectoryName(file_path_str);//DICOM所在文件夹 246 | DICOMreader->Update(); 247 | 248 | this->reader = DICOMreader; 249 | } 250 | 251 | 252 | void MainWindow::exportInf() 253 | { 254 | vtkImageData* readerImg = nullptr; 255 | readerImg = this->reader->GetOutput(); 256 | 257 | //确认读取到文件并输出文件信息 258 | readerImg->GetDimensions(this->dim); 259 | if ( dim[0] > 2 || dim[1] > 2 || dim[2] > 2 ) 260 | { 261 | 262 | QString dim0 = QString::number(dim[0]); 263 | QString dim1 = QString::number(dim[1]); 264 | QString dim2 = QString::number(dim[2]); 265 | QString space = " "; 266 | ui->text_inf->append("Dimensions:" + space + dim0 + space + dim1 + space + dim2); 267 | 268 | QString fileExtensions = this->reader-> GetFileExtensions(); 269 | ui->text_inf->append("fileExtensions: " + fileExtensions); 270 | 271 | QString descriptiveName = this->reader->GetDescriptiveName(); 272 | ui->text_inf->append("descriptiveName: " + descriptiveName); 273 | 274 | double* pixelSpacing = this->reader->GetPixelSpacing(); 275 | QString pixelS = QString::number(*pixelSpacing,10,5); 276 | ui->text_inf->append("pixelSpacing: " + pixelS); 277 | 278 | int width = this->reader->GetWidth(); 279 | QString wid = QString::number(width); 280 | ui->text_inf->append("width: " + wid); 281 | 282 | int height = this->reader->GetHeight(); 283 | QString heig = QString::number(height); 284 | ui->text_inf->append("height: " + heig); 285 | 286 | float* imagePositionPatient = this->reader->GetImagePositionPatient(); 287 | QString imPP = QString::number(*imagePositionPatient,10,5); 288 | ui->text_inf->append("imagePositionPatient: " + imPP); 289 | 290 | float* imageOrientationPatient = this->reader->GetImageOrientationPatient(); 291 | QString imOP = QString::number(*imageOrientationPatient,10,5); 292 | ui->text_inf->append("imageOrientationPatient: " + imOP); 293 | 294 | int bitsAllocated = this->reader->GetBitsAllocated(); 295 | QString bitsA = QString::number(bitsAllocated); 296 | ui->text_inf->append("bitsAllocated: " + bitsA); 297 | 298 | int pixelRepresentation = this->reader->GetPixelRepresentation(); 299 | QString pixelR = QString::number(pixelRepresentation); 300 | ui->text_inf->append("pixelRepresentation: " + pixelR); 301 | 302 | int numberOfComponents = this->reader->GetNumberOfComponents(); 303 | QString numberO = QString::number(numberOfComponents); 304 | ui->text_inf->append("numberOfComponents: " + numberO); 305 | 306 | QString transferSyntaxUID = this->reader->GetTransferSyntaxUID(); 307 | ui->text_inf->append("transferSyntaxUID: " + transferSyntaxUID); 308 | 309 | float rescaleSlope = this->reader->GetRescaleSlope(); 310 | QString rescaleS = QString::number(rescaleSlope, 10, 5); 311 | ui->text_inf->append("rescaleSlope: " + rescaleS); 312 | 313 | float rescaleOffset = this->reader->GetRescaleOffset(); 314 | QString rescaleO = QString::number(rescaleOffset, 10, 5); 315 | ui->text_inf->append("rescaleOffset: " + rescaleO); 316 | 317 | QString patientName = this->reader->GetPatientName(); 318 | ui->text_inf->append("patientName: " + patientName); 319 | 320 | QString studyUID = this->reader->GetStudyUID(); 321 | ui->text_inf->append("studyUID: " + studyUID); 322 | 323 | QString studyID = this->reader->GetStudyID(); 324 | ui->text_inf->append("studyID: " + studyID); 325 | 326 | float gantryAngle = this->reader->GetGantryAngle(); 327 | QString gantryA = QString::number(gantryAngle, 10, 5); 328 | ui->text_inf->append("gantryAngle: " + gantryA); 329 | } 330 | } 331 | 332 | void MainWindow::anatomyView() 333 | { 334 | //横断面、矢状面、冠状面视图 335 | //用vtkImageViewer2获取数据各个方向的切片 336 | //横断面面视图 337 | vtkSmartPointer imageViewerLeft = 338 | vtkSmartPointer::New(); 339 | imageViewerLeft->SetInputConnection(this->reader->GetOutputPort()); 340 | imageViewerLeft->SetSliceOrientationToXY(); 341 | imageViewerLeft->SetSlice(dim[2]/2); 342 | imageViewerLeft->SetRenderWindow(ui->qvtkWidgetLeft->GetRenderWindow()); 343 | //矢状面视图 344 | vtkSmartPointer imageViewerRight = 345 | vtkSmartPointer::New(); 346 | imageViewerRight->SetInputConnection(this->reader->GetOutputPort()); 347 | imageViewerRight->SetSliceOrientationToXZ(); 348 | imageViewerRight->SetSlice(dim[0]/2); 349 | imageViewerRight->SetRenderWindow(ui->qvtkWidgetRight->GetRenderWindow()); 350 | //冠状面视图 351 | vtkSmartPointer imageViewerDLeft = 352 | vtkSmartPointer::New(); 353 | imageViewerDLeft->SetInputConnection(this->reader->GetOutputPort()); 354 | imageViewerDLeft->SetSlice(dim[1]/2); 355 | imageViewerDLeft->SetSliceOrientationToYZ(); 356 | imageViewerDLeft->SetRenderWindow(ui->qvtkWidgetDLeft->GetRenderWindow()); 357 | 358 | //横断面当前切片数 359 | vtkSmartPointer sliceTextProp1 = vtkSmartPointer::New(); 360 | sliceTextProp1->SetFontFamilyToCourier(); 361 | sliceTextProp1->SetFontSize(15); 362 | sliceTextProp1->SetVerticalJustificationToBottom(); 363 | sliceTextProp1->SetJustificationToLeft(); 364 | 365 | vtkSmartPointer sliceTextMapper1 = vtkSmartPointer::New(); 366 | std::string msg1 = StatusMessage::Format(dim[2]/2, imageViewerLeft->GetSliceMax()); 367 | sliceTextMapper1->SetInput(msg1.c_str()); 368 | sliceTextMapper1->SetTextProperty(sliceTextProp1); 369 | 370 | vtkSmartPointer sliceTextActor1 = vtkSmartPointer::New(); 371 | sliceTextActor1->SetMapper(sliceTextMapper1); 372 | sliceTextActor1->SetPosition(90, 10); 373 | 374 | //冠状面当前切片数 375 | vtkSmartPointer sliceTextProp2 = vtkSmartPointer::New(); 376 | sliceTextProp2->SetFontFamilyToCourier(); 377 | sliceTextProp2->SetFontSize(15); 378 | sliceTextProp2->SetVerticalJustificationToBottom(); 379 | sliceTextProp2->SetJustificationToLeft(); 380 | 381 | vtkSmartPointer sliceTextMapper2 = vtkSmartPointer::New(); 382 | std::string msg2 = StatusMessage::Format(dim[0]/2, imageViewerRight->GetSliceMax()); 383 | sliceTextMapper2->SetInput(msg2.c_str()); 384 | sliceTextMapper2->SetTextProperty(sliceTextProp2); 385 | 386 | vtkSmartPointer sliceTextActor2 = vtkSmartPointer::New(); 387 | sliceTextActor2->SetMapper(sliceTextMapper2); 388 | sliceTextActor2->SetPosition(90, 10); 389 | 390 | //矢状面当前切片数 391 | vtkSmartPointer sliceTextProp3 = vtkSmartPointer::New(); 392 | sliceTextProp3->SetFontFamilyToCourier(); 393 | sliceTextProp3->SetFontSize(15); 394 | sliceTextProp3->SetVerticalJustificationToBottom(); 395 | sliceTextProp3->SetJustificationToLeft(); 396 | 397 | vtkSmartPointer sliceTextMapper3 = vtkSmartPointer::New(); 398 | std::string msg3 = StatusMessage::Format(dim[1]/2, imageViewerDLeft->GetSliceMax()); 399 | sliceTextMapper3->SetInput(msg3.c_str()); 400 | sliceTextMapper3->SetTextProperty(sliceTextProp3); 401 | 402 | vtkSmartPointer sliceTextActor3 = vtkSmartPointer::New(); 403 | sliceTextActor3->SetMapper(sliceTextMapper3); 404 | sliceTextActor3->SetPosition(90, 10); 405 | 406 | //提示文本 407 | vtkSmartPointer usageTextProp = vtkSmartPointer::New(); 408 | usageTextProp->SetFontFamilyToCourier(); 409 | usageTextProp->SetFontSize(14); 410 | usageTextProp->SetVerticalJustificationToTop(); 411 | usageTextProp->SetJustificationToLeft(); 412 | 413 | vtkSmartPointer usageTextMapper = vtkSmartPointer::New(); 414 | usageTextMapper->SetInput("- Slice with mouse wheel or Up/Down-Key\n- Zoom with pressed right mouse button\n while dragging\n- adjust the window width with pressed\n left mouse button while dragging"); 415 | usageTextMapper->SetTextProperty(usageTextProp); 416 | 417 | vtkSmartPointer usageTextActor = vtkSmartPointer::New(); 418 | usageTextActor->SetMapper(usageTextMapper); 419 | usageTextActor->GetPositionCoordinate()->SetCoordinateSystemToNormalizedDisplay(); 420 | usageTextActor->GetPositionCoordinate()->SetValue( 0.05, 0.95); 421 | 422 | //切片方向文本 423 | vtkSmartPointer transverseTextProp = vtkSmartPointer::New(); 424 | transverseTextProp->SetFontFamilyToCourier(); 425 | transverseTextProp->SetFontSize(12); 426 | transverseTextProp->SetVerticalJustificationToBottom(); 427 | transverseTextProp->SetJustificationToLeft(); 428 | 429 | vtkSmartPointer transverseTextMapper = vtkSmartPointer::New(); 430 | transverseTextMapper->SetInput("transverse"); 431 | transverseTextMapper->SetTextProperty(transverseTextProp); 432 | transverseTextMapper->GetTextProperty()->SetColor(0.1, 0.1, 0.1); 433 | 434 | vtkSmartPointer transverseTextActor = vtkSmartPointer::New(); 435 | transverseTextActor->SetMapper(transverseTextMapper); 436 | transverseTextActor->SetPosition(5, 10); 437 | 438 | //交互 439 | //窗口交互器 440 | vtkSmartPointer renderWindowInteractor1 = 441 | vtkSmartPointer::New(); 442 | vtkSmartPointer renderWindowInteractor2 = 443 | vtkSmartPointer::New(); 444 | vtkSmartPointer renderWindowInteractor3 = 445 | vtkSmartPointer::New(); 446 | //交互风格 447 | vtkSmartPointer myInteractorStyle1 = 448 | vtkSmartPointer::New(); 449 | myInteractorStyle1->SetImageViewer(imageViewerLeft); 450 | myInteractorStyle1->SetStatusMapper(sliceTextMapper1); 451 | 452 | vtkSmartPointer myInteractorStyle2 = 453 | vtkSmartPointer::New(); 454 | myInteractorStyle2->SetImageViewer(imageViewerRight); 455 | myInteractorStyle2->SetStatusMapper(sliceTextMapper2); 456 | 457 | vtkSmartPointer myInteractorStyle3 = 458 | vtkSmartPointer::New(); 459 | myInteractorStyle3->SetImageViewer(imageViewerDLeft); 460 | myInteractorStyle3->SetStatusMapper(sliceTextMapper3); 461 | //将交互风格添加到窗口交互器 462 | imageViewerLeft->SetupInteractor(renderWindowInteractor1); 463 | renderWindowInteractor1->SetInteractorStyle(myInteractorStyle1); 464 | imageViewerRight->SetupInteractor(renderWindowInteractor2); 465 | renderWindowInteractor2->SetInteractorStyle(myInteractorStyle2); 466 | imageViewerDLeft->SetupInteractor(renderWindowInteractor3); 467 | renderWindowInteractor3->SetInteractorStyle(myInteractorStyle3); 468 | 469 | //把文本添加到绘制窗口 470 | imageViewerLeft->GetRenderer()->AddActor2D(sliceTextActor1); 471 | imageViewerRight->GetRenderer()->AddActor2D(sliceTextActor2); 472 | imageViewerDLeft->GetRenderer()->AddActor2D(sliceTextActor3); 473 | imageViewerLeft->GetRenderer()->AddActor2D(usageTextActor); 474 | imageViewerLeft->GetRenderer()->AddActor2D(transverseTextActor); 475 | 476 | //渲染 477 | imageViewerLeft->Render(); 478 | imageViewerRight->Render(); 479 | imageViewerDLeft->Render(); 480 | renderWindowInteractor1->Start(); 481 | renderWindowInteractor2->Start(); 482 | renderWindowInteractor3->Start(); 483 | } 484 | 485 | void MainWindow::modelMaker_marchingCubes() 486 | { 487 | //三维重建 488 | /* //高斯平滑 489 | vtkSmartPointer smooth = 490 | vtkSmartPointer::New(); 491 | smooth->SetDimensionality(3); 492 | smooth->SetInputConnection(reader->GetOutputPort()); 493 | smooth->SetStandardDeviations(1.75, 1.75, 0.0); 494 | smooth->SetRadiusFactor(1);*/ 495 | 496 | //移动立方体法 497 | vtkSmartPointer mcubes = 498 | vtkSmartPointer::New(); 499 | mcubes->SetInputConnection(this->reader->GetOutputPort()); 500 | mcubes->SetValue(0, 99); 501 | 502 | /* //连通域着色 503 | vtkSmartPointer connectivityFilter = 504 | vtkSmartPointer::New(); 505 | connectivityFilter->SetInputConnection(mcubes->GetOutputPort()); 506 | connectivityFilter->SetExtractionModeToAllRegions(); 507 | connectivityFilter->ColorRegionsOn(); 508 | connectivityFilter->Update(); */ 509 | 510 | //生成actor 511 | vtkSmartPointer mcubesMapper = 512 | vtkSmartPointer::New(); 513 | mcubesMapper->SetInputConnection(mcubes->GetOutputPort()); 514 | mcubesMapper->SetScalarRange(mcubes->GetOutput()->GetPointData()->GetArray("RegionId")->GetRange()); 515 | mcubesMapper->Update(); 516 | 517 | vtkSmartPointer mcubesActor = 518 | vtkSmartPointer::New(); 519 | mcubesActor->SetMapper(mcubesMapper); 520 | 521 | // VTK Renderer 522 | vtkSmartPointer drightRenderer = 523 | vtkSmartPointer::New(); 524 | drightRenderer->AddActor(mcubesActor); 525 | 526 | // VTK/Qt wedded 527 | ui->qvtkWidgetDRight->GetRenderWindow()->AddRenderer(drightRenderer); 528 | ui->qvtkWidgetDRight->GetRenderWindow()->Render(); 529 | 530 | this->poly_cube = mcubes; 531 | } 532 | 533 | void MainWindow::model_autoRepair() 534 | { 535 | vtkSmartPointer colors = 536 | vtkSmartPointer::New(); 537 | 538 | // Fill the holes 539 | vtkSmartPointer fillHoles = 540 | vtkSmartPointer::New(); 541 | fillHoles->SetInputConnection(this->poly_cube->GetOutputPort()); 542 | fillHoles->SetHoleSize(100.0); 543 | 544 | // Make the triangle winding order consistent 545 | vtkSmartPointer normals = 546 | vtkSmartPointer::New(); 547 | normals->SetInputConnection(fillHoles->GetOutputPort()); 548 | normals->ConsistencyOn(); 549 | normals->SplittingOff(); 550 | normals->Update(); 551 | normals->GetOutput()->GetPointData()-> 552 | SetNormals(this->poly_cube->GetOutput()->GetPointData()->GetNormals()); 553 | 554 | // How many added cells 555 | vtkIdType numOriginalCells = this->poly_cube->GetOutput()->GetNumberOfCells(); 556 | vtkIdType numNewCells = normals->GetOutput()->GetNumberOfCells(); 557 | 558 | // Iterate over the original cells 559 | vtkSmartPointer it = normals->GetOutput()->NewCellIterator(); 560 | vtkIdType numCells = 0; 561 | for (it->InitTraversal(); 562 | !it->IsDoneWithTraversal() && numCells < numOriginalCells; 563 | it->GoToNextCell(), ++numCells) 564 | { 565 | } 566 | std::cout << "Num original: " << numOriginalCells 567 | << ", Num new: " << numNewCells 568 | << ", Num added: " << numNewCells - numOriginalCells << std::endl; 569 | vtkSmartPointer holePolyData = 570 | vtkSmartPointer::New(); 571 | holePolyData->Allocate(normals->GetOutput(), numNewCells - numOriginalCells); 572 | holePolyData->SetPoints(normals->GetOutput()->GetPoints()); 573 | 574 | vtkSmartPointer cell = 575 | vtkSmartPointer::New(); 576 | 577 | // The remaining cells are the new ones from the hole filler 578 | for (; 579 | !it->IsDoneWithTraversal(); 580 | it->GoToNextCell(), numCells) 581 | { 582 | it->GetCell(cell); 583 | holePolyData->InsertNextCell(it->GetCellType(), cell->GetPointIds()); 584 | } 585 | 586 | // We have to use ConnectivtyFilter and not 587 | // PolyDataConnectivityFilter since the later does not create 588 | // RegionIds cell data. 589 | vtkSmartPointer connectivity = 590 | vtkSmartPointer::New(); 591 | connectivity->SetInputData(holePolyData); 592 | connectivity->SetExtractionModeToAllRegions(); 593 | connectivity->ColorRegionsOn(); 594 | connectivity->Update(); 595 | std::cout << "Found " 596 | << connectivity->GetNumberOfExtractedRegions() 597 | << " holes" << std::endl; 598 | 599 | // Visualize 600 | 601 | // Create a mapper and actor for the fill polydata 602 | vtkSmartPointer filledMapper = 603 | vtkSmartPointer::New(); 604 | filledMapper->SetInputConnection(connectivity->GetOutputPort()); 605 | filledMapper->SetScalarModeToUseCellData(); 606 | filledMapper->SetScalarRange( 607 | connectivity->GetOutput()->GetCellData()->GetArray("RegionId")->GetRange()); 608 | vtkSmartPointer filledActor = 609 | vtkSmartPointer::New(); 610 | filledActor->SetMapper(filledMapper); 611 | filledActor->GetProperty()->SetDiffuseColor( 612 | colors->GetColor3d("Peacock").GetData()); 613 | 614 | // Create a mapper and actor for the original polydata 615 | //减少网格中的三角面片数量 616 | vtkSmartPointer decimate = vtkSmartPointer::New(); 617 | decimate->SetInputConnection(this->poly_cube->GetOutputPort()); 618 | decimate->SetTargetReduction(0.9); 619 | decimate->SetAbsoluteError(0.0005); 620 | decimate->SetFeatureAngle(30); 621 | decimate->SetErrorIsAbsolute(1); 622 | decimate->AccumulateErrorOn(); 623 | 624 | // decimate->SplittingOff(); 625 | vtkSmartPointer originalMapper = 626 | vtkSmartPointer::New(); 627 | originalMapper->SetInputConnection(decimate->GetOutputPort()); 628 | 629 | vtkSmartPointer backfaceProp = 630 | vtkSmartPointer::New(); 631 | backfaceProp->SetDiffuseColor(colors->GetColor3d("Banana").GetData()); 632 | 633 | vtkSmartPointer originalActor = 634 | vtkSmartPointer::New(); 635 | originalActor->SetMapper(originalMapper); 636 | originalActor->SetBackfaceProperty(backfaceProp); 637 | originalActor->GetProperty()->SetDiffuseColor( 638 | colors->GetColor3d("Flesh").GetData()); 639 | originalActor->GetProperty()->SetRepresentationToWireframe(); 640 | 641 | // VTK Renderer 642 | vtkSmartPointer drightRenderer = 643 | vtkSmartPointer::New(); 644 | drightRenderer->AddActor(originalActor); 645 | drightRenderer->AddActor(filledActor); 646 | 647 | // VTK/Qt wedded 648 | ui->qvtkWidgetDRight->GetRenderWindow()->AddRenderer(drightRenderer); 649 | ui->qvtkWidgetDRight->GetRenderWindow()->Render(); 650 | } 651 | 652 | void MainWindow::exportSTL() 653 | { 654 | //导出stl文件用于3D打印 655 | std::string filename = "out.stl"; 656 | vtkSTLWriter *stlWriter = vtkSTLWriter::New(); 657 | stlWriter->SetFileName(filename.c_str()); 658 | stlWriter->SetInputConnection(this->poly_repair->GetOutputPort()); 659 | stlWriter->Write(); 660 | } 661 | 662 | 663 | 664 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace Ui { 11 | class MainWindow; 12 | } 13 | 14 | class MainWindow : public QMainWindow 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | explicit MainWindow(QWidget *parent = nullptr); 20 | ~MainWindow(); 21 | 22 | private slots: 23 | void closeThis(); 24 | void input(); 25 | void exportInf(); 26 | void anatomyView(); 27 | void exportSTL(); 28 | void modelMaker_marchingCubes(); 29 | void model_autoRepair(); 30 | 31 | private: 32 | Ui::MainWindow *ui; 33 | vtkSmartPointer reader = vtkSmartPointer::New(); 34 | vtkSmartPointer poly_cube = vtkSmartPointer::New(); 35 | vtkSmartPointer poly_repair = vtkSmartPointer::New(); 36 | int dim[3]; 37 | }; 38 | 39 | #endif // MAINWINDOW_H 40 | -------------------------------------------------------------------------------- /mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 967 10 | 813 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 13 21 | 12 22 | 911 23 | 721 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 0 53 | 0 54 | 967 55 | 17 56 | 57 | 58 | 59 | 60 | 文件 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 三维可视化 71 | 72 | 73 | 74 | 面绘制 75 | 76 | 77 | 78 | 79 | 80 | 81 | 体绘制 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 模型编辑 93 | 94 | 95 | 96 | 97 | 图像分割 98 | 99 | 100 | 101 | 102 | 关于 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 关闭 115 | 116 | 117 | 118 | 119 | 剖分立方体算法 120 | 121 | 122 | 123 | 124 | 光线投射算法 125 | 126 | 127 | 128 | 129 | 3D纹理映射算法 130 | 131 | 132 | 133 | 134 | 最大密度投影算法 135 | 136 | 137 | 138 | 139 | 文件信息 140 | 141 | 142 | 143 | 144 | 切片视图 145 | 146 | 147 | 148 | 149 | 导入DICOM 150 | 151 | 152 | 153 | 154 | 移动立方体算法 155 | 156 | 157 | 158 | 159 | 导出STL 160 | 161 | 162 | 163 | 164 | 165 | 166 | QVTKOpenGLWidget 167 | QWidget 168 |
QVTKOpenGLWidget.h
169 |
170 |
171 | 172 | 173 |
174 | --------------------------------------------------------------------------------