diff --git a/src/src/Rendering/Viewer/DICOMImageViewer.cxx b/src/src/Rendering/Viewer/DICOMImageViewer.cxx index 6bdbfab..e8e61b2 100644 --- a/src/src/Rendering/Viewer/DICOMImageViewer.cxx +++ b/src/src/Rendering/Viewer/DICOMImageViewer.cxx @@ -53,6 +53,30 @@ namespace { if(idx == 1) return 0; return idx; } + + void prepareTransferFunction(vtkDiscretizableColorTransferFunction *table, vtkImageProperty *prop, + const std::vector> &vector) { + + double min = prop->GetColorLevel() - prop->GetColorWindow() * 0.5; + double max = prop->GetColorLevel() + prop->GetColorWindow() * 0.5; + int size = table->GetSize(); + + table->RemoveAllPoints(); + for (int i = 0; i < size; i++) { + table->AddRGBPoint(min + vector[i][0] * prop->GetColorWindow(), + vector[i][1], vector[i][2], vector[i][3], vector[i][4], vector[i][5]); + } + table->DiscretizeOn(); + // vtkNew wise; + // wise->AddPoint(min - 0.05, 0.0); + // wise->AddPoint(min, table->GetAlpha()); + // wise->AddPoint(max, table->GetAlpha()); + // //wise->AddPoint(max + 0.05, 0.0); + // wise->ClampingOn(); //Default is On + // table->SetScalarOpacityFunction(wise); + // table->EnableOpacityMappingOn(); +} + } vtkStandardNewMacro(DICOMImageViewer); @@ -65,8 +89,8 @@ DICOMImageViewer::DICOMImageViewer() FusionMapper(nullptr), Interactor(nullptr), InteractorStyle(nullptr), OpacityActor(nullptr), cornerAnnotation(FastCornerAnnotationActor::New()), bar(nullptr), ViewID(0), SliceIJK(-1), SlicePlane(-1), FirstRender(1), Slice(0), loadedMeasureSlice(0), - currentPresetIndex(1), Fusion(false), firstFusion(true), FusionOpacity(0.5), list(nullptr), - measureStore(MeasureStore::Instance()), + currentPresetIndex(1), Fusion(false), firstFusion(true), + FusionOpacity(0.5), list(nullptr), measureStore(MeasureStore::Instance()), rulerActive(false){ this->ImageMapper->SliceAtFocalPointOn(); this->ImageMapper->SliceFacesCameraOn(); @@ -298,6 +322,8 @@ void DICOMImageViewer::InstallPipeline() { this, &DICOMImageViewer::RemoveMeasures); this->InteractorStyle->AddObserver(DraggableStyleEvents::SliceEvent, this, &DICOMImageViewer::ChangeSlice); + this->InteractorStyle->AddObserver(vtkCommand::EventIds::WindowLevelEvent, this, + &DICOMImageViewer::ChangeWindowLevel); //for convert vtkEvent to Qt signal this->InteractorStyle->AddObserver(DraggableStyleEvents::SlicedEvent, this, @@ -683,6 +709,35 @@ void DICOMImageViewer::SetColorLevel(double s) { this->ImageActor->GetProperty()->SetColorLevel(s); } +void DICOMImageViewer::ChangeWindowLevel(vtkObject *, unsigned long eventid, void *calldata) +{ + if (!vtkDiscretizableColorTransferFunction::SafeDownCast(ImageActor->GetProperty()->GetLookupTable())) return; + auto values = ColorMapReader::DefaultPresets()->GetPresetValues(mColorPreset.data()); + vtkNew table; + for (int i = 0; i + 3 < values.size(); i += 4) + { + table->AddRGBPoint(values[i], values[i + 1], values[i + 2], values[i + 3]); + } + double *nancolor = ColorMapReader::DefaultPresets()->GetPresetNanColor(mColorPreset.data()); + if (nancolor) + { + table->SetNanColor(nancolor); + } + if (table) + { + int size = table->GetSize(); + fusion_tf_vector.clear(); + for (int i = 0; i < size; i++) { + double v[6] = {0, 0, 0, 0, 0, 0}; + table->GetNodeValue(i, v); + std::vector nt = {v[0], v[1], v[2], v[3], v[4], v[5]}; + fusion_tf_vector.push_back(nt); + } + prepareTransferFunction(table, ImageActor->GetProperty(), fusion_tf_vector); + } + ImageActor->GetProperty()->SetLookupTable(table); +} + void DICOMImageViewer::SetNegativeMode(bool negative) { if (negative) { double window = this->ImageActor->GetProperty()->GetColorWindow(); @@ -703,7 +758,58 @@ void DICOMImageViewer::SetNegativeMode(bool negative) { } } -void DICOMImageViewer::SetLookupTable(vtkLookupTable *lut) { +void DICOMImageViewer::SetLookupTable(const QString &aTableName) +{ + if (aTableName == "gray") + { + mColorPreset = "gray"; + this->SetLookupTable(nullptr); + } + else if (aTableName == "neg") + { + mColorPreset = "grayneg"; + double window = this->ImageActor->GetProperty()->GetColorWindow(); + double level = this->ImageActor->GetProperty()->GetColorLevel(); + + vtkNew lut; + lut->SetRange(level - 0.5 * window, level + 0.5 * window); // image intensity range + lut->SetValueRange(1.0, 0.0); // from black to white + lut->SetHueRange(0.0, 0.0); + lut->SetSaturationRange(0.0, 0.0); + //lookupTable->SetRampToLinear(); + lut->Build(); + this->SetLookupTable(lut); + } + else + { + if (aTableName == "jet") + { + mColorPreset = "Jet"; + auto values = ColorMapReader::DefaultPresets()->GetPresetValues(mColorPreset.data()); + vtkNew table; + for (int i = 0; i + 3 < values.size(); i += 4) { + table->AddRGBPoint(values[i], values[i + 1], values[i + 2], values[i + 3]); + } + double *nancolor = ColorMapReader::DefaultPresets()->GetPresetNanColor(mColorPreset.data()); + if (nancolor) { + table->SetNanColor(nancolor); + } + int size = table->GetSize(); + fusion_tf_vector.clear(); + for (int i = 0; i < size; i++) { + double v[6] = {0, 0, 0, 0, 0, 0}; + table->GetNodeValue(i, v); + std::vector nt = {v[0], v[1], v[2], v[3], v[4], v[5]}; + fusion_tf_vector.push_back(nt); + } + prepareTransferFunction(table, ImageActor->GetProperty(), fusion_tf_vector); + this->SetLookupTable(table); + } + } + this->Render(); +} + +void DICOMImageViewer::SetLookupTable(vtkScalarsToColors *lut) { this->ImageActor->GetProperty()->SetLookupTable(lut); } @@ -840,28 +946,6 @@ void prepareLookTable(vtkLookupTable *table) { table->UseBelowRangeColorOn(); } -void prepareTransferFunction(vtkDiscretizableColorTransferFunction *table, vtkImageProperty *prop, - const std::vector> &vector) { - - double min = prop->GetColorLevel() - prop->GetColorWindow() * 0.5; - double max = prop->GetColorLevel() + prop->GetColorWindow() * 0.5; - int size = table->GetSize(); - - table->RemoveAllPoints(); - for (int i = 0; i < size; i++) { - table->AddRGBPoint(min + vector[i][0] * prop->GetColorWindow(), - vector[i][1], vector[i][2], vector[i][3], vector[i][4], vector[i][5]); - } - vtkNew wise; - wise->AddPoint(min - 0.05, 0.0); - wise->AddPoint(min, table->GetAlpha()); - wise->AddPoint(max, table->GetAlpha()); - //wise->AddPoint(max + 0.05, 0.0); - wise->ClampingOn(); //Default is On - table->SetScalarOpacityFunction(wise); - table->EnableOpacityMappingOn(); -} - void DICOMImageViewer::SetFusionColorTable(vtkScalarsToColors *table) { if (!FusionActor) return; PrepareFusionColorTable(table, true); diff --git a/src/src/Rendering/Viewer/DICOMImageViewer.h b/src/src/Rendering/Viewer/DICOMImageViewer.h index 6edbb0b..ce2ed00 100644 --- a/src/src/Rendering/Viewer/DICOMImageViewer.h +++ b/src/src/Rendering/Viewer/DICOMImageViewer.h @@ -162,9 +162,13 @@ public: virtual void SetColorLevel(double s); + void ChangeWindowLevel(vtkObject *, unsigned long eventid, void *calldata); + void SetNegativeMode(bool negative); - void SetLookupTable(vtkLookupTable *lut); + void SetLookupTable(const QString& aTableName); + + void SetLookupTable(vtkScalarsToColors *lut); //@} //@{ @@ -452,6 +456,7 @@ private: vtkNew ModelToWorldMatrix; DicomCornerInfo m_cornerInfo; + std::string mColorPreset; uint ViewID; int SliceIJK; int SlicePlane; diff --git a/src/src/UI/Widget/ImageView/dicomimageview.cpp b/src/src/UI/Widget/ImageView/dicomimageview.cpp index 5fe87e4..6d2cb91 100644 --- a/src/src/UI/Widget/ImageView/dicomimageview.cpp +++ b/src/src/UI/Widget/ImageView/dicomimageview.cpp @@ -23,7 +23,7 @@ DicomImageView::DicomImageView(QWidget *parent) : QFrame(parent), mGLRenWin(vtkSmartPointer::New()), mImageViewer(nullptr), mSeries(nullptr), mScrollBar(new ClickableScrollBar(Qt::Orientation::Vertical, this)), mTitleBar(createMyTitleBar()), mGLWidget(new QVTKOpenGLNativeWidget), mVcrToolbar(nullptr), mVcrController(nullptr), - mOverlayView(nullptr), mBaseView(nullptr), mIsCine(false), mIsNegative(false), + mOverlayView(nullptr), mBaseView(nullptr), mTableName("gray"),mIsCine(false), mIsNegative(false), mIsOverlay(false), mIsSlotInited(false),mCurrentRAngle(0) { //main container @@ -176,6 +176,7 @@ void DicomImageView::loadSeries(SeriesImageSet *series) { .arg(time) .arg(series->GetProperty()->GetSeriesDescription())); mImageViewer->SetInputData(mSeries->GetData()); + setColorTable("gray"); mIsFirstRenderAfterLoad = true; if(mSeries->GetOverlayData()) { @@ -606,6 +607,19 @@ void DicomImageView::negativeWindow() { } } +void DicomImageView::setColorTable(const QString &aTableName) +{ + if (hasSeries()) { + mImageViewer->SetLookupTable(aTableName); + mTableName = aTableName; + } +} + +QString DicomImageView::getColorTable() +{ + return mTableName; +} + void DicomImageView::hFlipImage() { if (hasSeries()) { int slice = mImageViewer->GetSlice(); diff --git a/src/src/UI/Widget/ImageView/dicomimageview.h b/src/src/UI/Widget/ImageView/dicomimageview.h index f31d965..1b7598e 100644 --- a/src/src/UI/Widget/ImageView/dicomimageview.h +++ b/src/src/UI/Widget/ImageView/dicomimageview.h @@ -162,6 +162,12 @@ public: //Negative void negativeWindow(); + //colortable + void setColorTable(const QString& aTableName); + + QString getColorTable(); + + //MPR void setReconPlane(int plane); @@ -339,6 +345,8 @@ private: DicomImageView *mOverlayView; DicomImageView *mBaseView; + QString mTableName; + bool mIsCine; bool mIsNegative; bool mIsOverlay; diff --git a/src/src/UI/Widget/ToolBar/DefaultToolBar.cpp b/src/src/UI/Widget/ToolBar/DefaultToolBar.cpp index 63f6bed..7fd9fff 100644 --- a/src/src/UI/Widget/ToolBar/DefaultToolBar.cpp +++ b/src/src/UI/Widget/ToolBar/DefaultToolBar.cpp @@ -6,6 +6,9 @@ #include #include #include "Rendering/Measure/Measure.h" +#include "UI/Widget/ImageView/DicomImageView.h" +#include "UI/Manager/ImageViewManager.h" + #include "Common/QGlobals.h" #include "ExportToolButton.h" @@ -70,6 +73,13 @@ void DefaultToolBar::setViewManager(ImageViewManager *aManager) mBtnSave->setImageViewManager(mImageViewManager); } +void DefaultToolBar::changePseudoColor(bool on) +{ + QAction* action = qobject_cast(sender()); + QString table = action->property("table").toString(); + emit setPseudoColor(table); +} + QAction* DefaultToolBar::addButton(QToolButton* button, const char* objectName) { button->setObjectName(objectName); button->setToolButtonStyle(Qt::ToolButtonIconOnly); @@ -274,9 +284,27 @@ void DefaultToolBar::initModeButtons() { QMenu *m = new QMenu(this); m->addAction(tr("Custom window width and level"), this, &DefaultToolBar::customWindow); - auto action = m->addAction(tr("Negative"), this, &DefaultToolBar::negativeWindow); - action->setCheckable(true); - action->setChecked(false); + m->addSeparator(); + + mPseudocolorGroup = new QActionGroup(this); + auto actionGray = m->addAction(tr("gray"), this, &DefaultToolBar::changePseudoColor); + actionGray->setCheckable(true); + actionGray->setChecked(true); + actionGray->setActionGroup(mPseudocolorGroup); + actionGray->setProperty("table","gray"); + + auto actionNeg = m->addAction(tr("Negative"), this, &DefaultToolBar::changePseudoColor); + actionNeg->setCheckable(true); + actionNeg->setChecked(false); + actionNeg->setActionGroup(mPseudocolorGroup); + actionNeg->setProperty("table","neg"); + + auto actionJet = m->addAction(tr("Jet"), this, &DefaultToolBar::changePseudoColor); + actionJet->setCheckable(true); + actionJet->setChecked(false); + actionJet->setActionGroup(mPseudocolorGroup); + actionJet->setProperty("table","jet"); + mBtnWindow->setPopupMode(QToolButton::MenuButtonPopup); mBtnWindow->setMenu(m); @@ -488,7 +516,14 @@ void DefaultToolBar::initMPRButton(){ void DefaultToolBar::resetNeedCheckFunctionButtons(){ mBtnMPR->setEnabled(false); mBtnFusion->setEnabled(false); - + for(auto var : mPseudocolorGroup->actions()) + { + if (var->property("table").toString() == mImageViewManager->getCurrentView()->getColorTable()) + { + var->setChecked(true); + break; + } + } // SyncHelper::setSyncState(DIS_SYNC); // syncStateChanged(); } diff --git a/src/src/UI/Widget/ToolBar/DefaultToolBar.h b/src/src/UI/Widget/ToolBar/DefaultToolBar.h index 206bb2e..538bde0 100644 --- a/src/src/UI/Widget/ToolBar/DefaultToolBar.h +++ b/src/src/UI/Widget/ToolBar/DefaultToolBar.h @@ -20,7 +20,7 @@ public: void resetNeedCheckFunctionButtons(); void updateNeedCheckFunctionButtons(ViewFunctionState state); void setViewManager(ImageViewManager* aManager); - + void changePseudoColor(bool on = false); signals: void openFile(); void openFolder(); @@ -29,7 +29,6 @@ signals: void showGrid(QToolButton* btn); void modeChanged(int mode); void customWindow(); - void negativeWindow(); void fusion(bool on = false); void cine(bool on = false); void changeReconPlane(int plane); @@ -37,7 +36,7 @@ signals: void parentWindowStateChange(Qt::WindowState state); void parentWindowClose(); void parentWindowLanguageChange(); - + void setPseudoColor(const QString& aTable); void transform(TransFormType type); void showMeta(); void volumeRendering(); @@ -101,6 +100,7 @@ private: QAction *mActionHidePatData; QAction* mSyncActions[3]={nullptr,nullptr,nullptr}; QAction* mMPRActions[3]={nullptr,nullptr,nullptr}; + QActionGroup *mPseudocolorGroup; ImageViewManager* mImageViewManager; }; diff --git a/src/src/UI/Window/QDicomViewer.cpp b/src/src/UI/Window/QDicomViewer.cpp index dfb9e51..a582b35 100644 --- a/src/src/UI/Window/QDicomViewer.cpp +++ b/src/src/UI/Window/QDicomViewer.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "Common/Helper/OrientationHelper.h" @@ -140,12 +141,7 @@ void QDicomViewer::initViewOperation() { m_customwin->exec(); }); // negative window - connect(ui->toolBar, &DefaultToolBar::negativeWindow, [=]() { - DicomImageView *curV = ui->viewContainer->getViewManager()->getCurrentView(); - if (curV != nullptr && curV->hasSeries()) { - curV->negativeWindow(); - } - }); + connect(ui->toolBar, &DefaultToolBar::setPseudoColor, this, &QDicomViewer::changeColorTable); // fusion connect(ui->toolBar, &DefaultToolBar::fusion, ui->viewContainer->getViewManager(), &ImageViewManager::switchFusion); @@ -306,6 +302,14 @@ void QDicomViewer::openDICOMFromPACS(int err, std::string dirName) { } } +void QDicomViewer::changeColorTable(const QString& aTable) +{ + DicomImageView *curV = ui->viewContainer->getViewManager()->getCurrentView(); + if (curV != nullptr && curV->hasSeries()) { + curV->setColorTable(aTable); + } +} + //TODO: 覆盖逻辑和增加逻辑待补充 void QDicomViewer::openDICOM(const std::string &dicomName, SeriesOpenMode openMode) { diff --git a/src/src/UI/Window/QDicomViewer.h b/src/src/UI/Window/QDicomViewer.h index 7d9e09d..e921d9f 100644 --- a/src/src/UI/Window/QDicomViewer.h +++ b/src/src/UI/Window/QDicomViewer.h @@ -27,6 +27,7 @@ public: public slots: void Slot_ToolbarVisibilityChanged(bool); void openDICOMFromPACS(int,std::string); + void changeColorTable(const QString& aTable); private: Ui::QDicomViewerClass *ui;