目录

1  基本数据结构Image

2  窗宽窗位mitkLevelWindow定义类

3 窗宽窗位自动设定算法

4  窗宽窗位的属性设置LevelWindowProperty 类

5  mitkDisplayActionEventFunctions类中DisplayActionEventFunctions触发窗宽窗位改变

6 DisplaySetLevelWindowEvent类得到窗体交互新增的窗宽窗位值

7 QmitkLevelWindowWidgetContextMenu

8 QmitkLineEditLevelWindowWidget

9 QmitkSliderLevelWindowWidget

10 QmitkLevelWindowWidget

11 LevelWindowManager

12  多视图窗体中创建窗宽窗位控件


交互的核心控件是QmitkSliderLevelWindowWidget

控件修改值通过DisplaySetLevelWindowEvent类,以如下方式添加:

level += displayActionEvent->GetLevel();
      window += displayActionEvent->GetWindow();

1  基本数据结构Image

/*** initialize new (or re-initialize) image information by @a itkimage,* a templated itk-image.* Only the header is used, not the data vector! Use* SetVolume(itkimage->GetBufferPointer()) to set the data vector.** @param itkimage* @param channels* @param tDim override time dimension in @a itkimage (if >0 and <)* @param sDim override z-space dimension in @a itkimage (if >0 and <)*/template <typename itkImageType>void InitializeByItk(const itkImageType *itkimage, int channels = 1, int tDim = -1, int sDim = -1){if (itkimage == nullptr)return;MITK_DEBUG << "Initializing MITK image from ITK image.";// build array with dimensions in each direction with at least 4 entriesm_Dimension = itkimage->GetImageDimension();unsigned int i, *tmpDimensions = new unsigned int[m_Dimension > 4 ? m_Dimension : 4];for (i = 0; i < m_Dimension; ++i)tmpDimensions[i] = itkimage->GetLargestPossibleRegion().GetSize().GetSize()[i];if (m_Dimension < 4){unsigned int *p;for (i = 0, p = tmpDimensions + m_Dimension; i < 4 - m_Dimension; ++i, ++p)*p = 1;}// overwrite number of slices if sDim is setif ((m_Dimension > 2) && (sDim >= 0))tmpDimensions[2] = sDim;// overwrite number of time points if tDim is setif ((m_Dimension > 3) && (tDim >= 0))tmpDimensions[3] = tDim;// rough initialization of Image// mitk::PixelType importType = ImportItkPixelType( itkimage::PixelType );Initialize(MakePixelType<itkImageType>(itkimage->GetNumberOfComponentsPerPixel()), m_Dimension, tmpDimensions, channels);const typename itkImageType::SpacingType &itkspacing = itkimage->GetSpacing();MITK_DEBUG << "ITK spacing " << itkspacing;// access spacing of itk::ImageVector3D spacing;FillVector3D(spacing, itkspacing[0], 1.0, 1.0);if (m_Dimension >= 2)spacing[1] = itkspacing[1];if (m_Dimension >= 3)spacing[2] = itkspacing[2];// access origin of itk::ImagePoint3D origin;const typename itkImageType::PointType &itkorigin = itkimage->GetOrigin();MITK_DEBUG << "ITK origin " << itkorigin;FillVector3D(origin, itkorigin[0], 0.0, 0.0);if (m_Dimension >= 2)origin[1] = itkorigin[1];if (m_Dimension >= 3)origin[2] = itkorigin[2];// access direction of itk::Imagm_PixelType = new mitk::PixelType(type);e and include spacingconst typename itkImageType::DirectionType &itkdirection = itkimage->GetDirection();MITK_DEBUG << "ITK direction " << itkdirection;mitk::Matrix3D matrix;matrix.SetIdentity();unsigned int j, itkDimMax3 = (m_Dimension >= 3 ? 3 : m_Dimension);// check if spacing has no zero entry and itkdirection has no zero columnsbool itkdirectionOk = true;mitk::ScalarType columnSum;for (j = 0; j < itkDimMax3; ++j){columnSum = 0.0;for (i = 0; i < itkDimMax3; ++i){columnSum += fabs(itkdirection[i][j]);}if (columnSum < mitk::eps){itkdirectionOk = false;}if ((spacing[j] < -mitk::eps) // (normally sized) negative value&&(j == 2) && (m_Dimensions[2] == 1)){// Negative spacings can occur when reading single DICOM slices with ITK via GDCMIO// In these cases spacing is not determined by ITK correctly (because it distinguishes correctly// between slice thickness and inter slice distance -- slice distance is meaningless for// single slices).// I experienced that ITK produced something meaningful nonetheless because it is// evaluating the tag "(0018,0088) Spacing between slices" as a fallback. This tag is not// reliable (http://www.itk.org/pipermail/insight-users/2005-September/014711.html)// but gives at least a hint.// In real world cases I experienced that this tag contained the correct inter slice distance// with a negative sign, so we just invert such negative spacings.MITK_WARN << "Illegal value of itk::Image::GetSpacing()[" << j << "]=" << spacing[j]<< ". Using inverted value " << -spacing[j];spacing[j] = -spacing[j];}else if (spacing[j] < mitk::eps) // value near zero{MITK_ERROR << "Illegal value of itk::Image::GetSpacing()[" << j << "]=" << spacing[j]<< ". Using 1.0 instead.";spacing[j] = 1.0;}}if (itkdirectionOk == false){MITK_ERROR << "Illegal matrix returned by itk::Image::GetDirection():" << itkdirection<< " Using identity instead.";for (i = 0; i < itkDimMax3; ++i)for (j = 0; j < itkDimMax3; ++j)if (i == j)matrix[i][j] = spacing[j];elsematrix[i][j] = 0.0;}else{for (i = 0; i < itkDimMax3; ++i)for (j = 0; j < itkDimMax3; ++j)matrix[i][j] = itkdirection[i][j] * spacing[j];}// re-initialize PlaneGeometry with origin and directionPlaneGeometry *planeGeometry = static_cast<PlaneGeometry *>(GetSlicedGeometry(0)->GetPlaneGeometry(0));planeGeometry->SetOrigin(origin);planeGeometry->GetIndexToWorldTransform()->SetMatrix(matrix);// re-initialize SlicedGeometry3DSlicedGeometry3D *slicedGeometry = GetSlicedGeometry(0);slicedGeometry->InitializeEvenlySpaced(planeGeometry, m_Dimensions[2]);slicedGeometry->SetSpacing(spacing);// re-initialize TimeGeometryProportionalTimeGeometry::Pointer timeGeometry = ProportionalTimeGeometry::New();timeGeometry->Initialize(slicedGeometry, m_Dimensions[3]);SetTimeGeometry(timeGeometry);// clean-updelete[] tmpDimensions;this->Initialize();}

2  窗宽窗位mitkLevelWindow定义类

  /*** @brief The LevelWindow class Class to store level/window values.** Current min and max value are stored in m_LowerWindowBound and m_UpperWindowBound.* m_DefaultLevel amd m_DefaultWindow store the initial Level/Window values for the image.* m_DefaultRangeMin and m_DefaultRangeMax store the initial minrange and maxrange for the image.** The finite maximum and minimum of valid value range is stored in m_RangeMin and m_RangeMax.* If deduced from an image by default the minimum or maximum of it statistics is used. If one* of these values are infinite the 2nd extrimum (which is guaranteed to be finite), will be used.** See documentation of SetAuto for information on how the level window is initialized from an image.** @ingroup DataManagement** @note If you want to apply the mitk::LevelWindow to an mitk::Image, make sure* to use the mitk::LevelWindowProperty and set the mitk::RenderingModeProperty* to a mode which supports level window (e.g. LEVELWINDOW_COLOR).* Make sure to check the documentation of the mitk::RenderingModeProperty. For a* code example how to use the mitk::LevelWindowProperty check the* mitkImageVtkMapper2DLevelWindowTest.cpp in Core/Code/Testing.*/class MITKCORE_EXPORT LevelWindow{public:LevelWindow(ScalarType level = 127.5, ScalarType window = 255.0);LevelWindow(const mitk::LevelWindow &levWin);virtual ~LevelWindow();......

3 窗宽窗位自动设定算法


/*!
This method initializes a mitk::LevelWindow from an mitk::Image. The algorithm is as follows:Default to taking the central image slice for quick analysis.Compute the smallest (minValue), second smallest (min2ndValue), second largest (max2ndValue), and
largest (maxValue) data value by traversing the pixel values only once. In the
same scan it also computes the count of minValue values and maxValue values.
After that a basic histogram with specific information about the
extremes is complete.If minValue == maxValue, the center slice is uniform and the above scan is repeated for
the complete image, not just one sliceNext, special cases of images with only 1, 2 or 3 distinct data values
have hand assigned level window ranges.Next the level window is set relative to the inner range IR = lengthOf([min2ndValue, max2ndValue])For count(minValue) > 20% the smallest values are frequent and should be
distinct from the min2ndValue and larger values (minValue may be std:min, may signify
something special) hence the lower end of the level window is set to min2ndValue - 0.5 * IRFor count(minValue) <= 20% the smallest values are not so important and can
blend with the next ones => min(level window) = min2ndValueAnd analog for max(level window):
count(max2ndValue) > 20%:  max(level window) = max2ndValue + 0.5 * IR
count(max2ndValue) < 20%:  max(level window) = max2ndValueIn both 20%+ cases the level window bounds are clamped to the [minValue, maxValue] rangeIn consequence the level window maximizes contrast with minimal amount of
computation and does do useful things if the data contains std::min or
std:max values or has only 1 or 2 or 3 data values.
*/
void mitk::LevelWindow::SetAuto(const mitk::Image *image,bool /*tryPicTags*/,bool guessByCentralSlice,unsigned selectedComponent)
{if (IsFixed())return;if (image == nullptr || !image->IsInitialized())return;if (itk::IOComponentEnum::FLOAT == image->GetPixelType().GetComponentType()||  itk::IOComponentEnum::DOUBLE == image->GetPixelType().GetComponentType()){m_IsFloatingImage = true;}else{m_IsFloatingImage = false;}const mitk::Image *wholeImage = image;ScalarType minValue = 0.0;ScalarType maxValue = 0.0;ScalarType min2ndValue = 0.0;ScalarType max2ndValue = 0.0;mitk::ImageSliceSelector::Pointer sliceSelector = mitk::ImageSliceSelector::New();if (guessByCentralSlice){sliceSelector->SetInput(image);sliceSelector->SetSliceNr(image->GetDimension(2) / 2);sliceSelector->SetTimeNr(image->GetDimension(3) / 2);sliceSelector->SetChannelNr(image->GetDimension(4) / 2);sliceSelector->Update();image = sliceSelector->GetOutput();if (image == nullptr || !image->IsInitialized())return;minValue = image->GetStatistics()->GetScalarValueMin(0, selectedComponent);maxValue = image->GetStatistics()->GetScalarValueMaxNoRecompute();min2ndValue = image->GetStatistics()->GetScalarValue2ndMinNoRecompute();max2ndValue = image->GetStatistics()->GetScalarValue2ndMaxNoRecompute();if (minValue == maxValue){// guessByCentralSlice seems to have failed, lets look at all dataimage = wholeImage;minValue = image->GetStatistics()->GetScalarValueMin(0, selectedComponent);maxValue = image->GetStatistics()->GetScalarValueMaxNoRecompute();min2ndValue = image->GetStatistics()->GetScalarValue2ndMinNoRecompute();max2ndValue = image->GetStatistics()->GetScalarValue2ndMaxNoRecompute();}}else{const_cast<Image *>(image)->Update();minValue = image->GetStatistics()->GetScalarValueMin(0, selectedComponent);maxValue = image->GetStatistics()->GetScalarValueMaxNoRecompute(0);min2ndValue = image->GetStatistics()->GetScalarValue2ndMinNoRecompute(0);max2ndValue = image->GetStatistics()->GetScalarValue2ndMaxNoRecompute(0);for (unsigned int i = 1; i < image->GetDimension(3); ++i){ScalarType minValueTemp = image->GetStatistics()->GetScalarValueMin(i, selectedComponent);if (minValue > minValueTemp)minValue = minValueTemp;ScalarType maxValueTemp = image->GetStatistics()->GetScalarValueMaxNoRecompute(i);if (maxValue < maxValueTemp)maxValue = maxValueTemp;ScalarType min2ndValueTemp = image->GetStatistics()->GetScalarValue2ndMinNoRecompute(i);if (min2ndValue > min2ndValueTemp)min2ndValue = min2ndValueTemp;ScalarType max2ndValueTemp = image->GetStatistics()->GetScalarValue2ndMaxNoRecompute(i);if (max2ndValue > max2ndValueTemp)max2ndValue = max2ndValueTemp;}}// Fix for bug# 344 Level Window wird bei Eris Cut bildern nicht richtig gesetztif (image->GetPixelType().GetPixelType() == itk::IOPixelEnum::SCALAR &&image->GetPixelType().GetComponentType() == itk::IOComponentEnum::INT && image->GetPixelType().GetBpe() >= 8){// the windows compiler complains about ambiguous 'pow' call, therefore static casting to (double, int)if (minValue == -(pow((double)2.0, static_cast<int>(image->GetPixelType().GetBpe() / 2)))){minValue = min2ndValue;}}// End fixuniform imageif (minValue == maxValue){minValue = maxValue - 1;}else{// Due to bug #8690 level window now is no longer of fixed range by default but the range adapts according to// levelwindow interaction// This is done because the range should be a little bit larger from the beginning so that the scale doesn't start// to resize right from the beginningdouble additionalRange = 0.15 * (maxValue - minValue);minValue -= additionalRange;maxValue += additionalRange;}if (!std::isfinite(minValue)){minValue = image->GetStatistics()->GetScalarValue2ndMinNoRecompute(0);}if (!std::isfinite(maxValue)){maxValue = image->GetStatistics()->GetScalarValue2ndMaxNoRecompute(0);}SetRangeMinMax(minValue, maxValue);SetDefaultBoundaries(minValue, maxValue);size_t numPixelsInDataset = image->GetDimensions()[0];for (decltype(image->GetDimension()) k = 1; k < image->GetDimension(); ++k)numPixelsInDataset *= image->GetDimensions()[k];const auto minCount = image->GetStatistics()->GetCountOfMinValuedVoxelsNoRecompute();const auto maxCount = image->GetStatistics()->GetCountOfMaxValuedVoxelsNoRecompute();const auto minCountFraction = minCount / static_cast<ScalarType>(numPixelsInDataset);const auto maxCountFraction = maxCount / static_cast<ScalarType>(numPixelsInDataset);binary imageif (min2ndValue == maxValue){// noop; full range is fine}triple value image, put middle value in center of gray level rampelse if (min2ndValue == max2ndValue){ScalarType minDelta = std::min(min2ndValue - minValue, maxValue - min2ndValue);minValue = min2ndValue - minDelta;maxValue = min2ndValue + minDelta;}// now we can assume more than three distict scalar valueselse{ScalarType innerRange = max2ndValue - min2ndValue;if (minCountFraction > 0.2)  lots of min values -> make different from rest, but not miles away{ScalarType halfInnerRangeGapMinValue = min2ndValue - innerRange / 2.0;minValue = std::max(minValue, halfInnerRangeGapMinValue);}else  few min values -> focus on innerRange{minValue = min2ndValue;}if (maxCountFraction > 0.2)  lots of max values -> make different from rest{ScalarType halfInnerRangeGapMaxValue = max2ndValue + innerRange / 2.0;maxValue = std::min(maxValue, halfInnerRangeGapMaxValue);}else  few max values -> focus on innerRange{maxValue = max2ndValue;}}SetWindowBounds(minValue, maxValue);SetDefaultLevelWindow((maxValue - minValue) / 2 + minValue, maxValue - minValue);
}

4  窗宽窗位的属性设置LevelWindowProperty 类


namespace mitk
{
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4522)
#endif/*** @brief The LevelWindowProperty class Property for the mitk::LevelWindow** @ingroup DataManagement** @note If you want to apply the mitk::LevelWindowProperty to an mitk::Image,* make sure to set the mitk::RenderingModeProperty to a mode which supports* level window (e.g. LEVELWINDOW_COLOR). Make sure to check the documentation* of the mitk::RenderingModeProperty. For a code example how to use the* mitk::LevelWindowProperty check the mitkImageVtkMapper2DLevelWindowTest.cpp* in Core/Code/Testing.*/class MITKCORE_EXPORT LevelWindowProperty : public BaseProperty{protected:LevelWindow m_LevWin;LevelWindowProperty();LevelWindowProperty(const LevelWindowProperty &other);LevelWindowProperty(const mitk::LevelWindow &levWin);public:mitkClassMacro(LevelWindowProperty, BaseProperty);itkFactorylessNewMacro(Self);itkCloneMacro(Self) mitkNewMacro1Param(LevelWindowProperty, const mitk::LevelWindow &);typedef LevelWindow ValueType;~LevelWindowProperty() override;const mitk::LevelWindow &GetLevelWindow() const;const mitk::LevelWindow &GetValue() const;void SetLevelWindow(const LevelWindow &levWin);void SetValue(const ValueType &levWin);std::string GetValueAsString() const override;using BaseProperty::operator=;private:// purposely not implementedLevelWindowProperty &operator=(const LevelWindowProperty &);itk::LightObject::Pointer InternalClone() const override;bool IsEqual(const BaseProperty &property) const override;bool Assign(const BaseProperty &property) override;};#ifdef _MSC_VER
#pragma warning(pop)
#endif} // namespace mitk

5  mitkDisplayActionEventFunctions类中DisplayActionEventFunctions触发窗宽窗位改变

    /*** @brief Returns an 'std::function' that can be used  to react on the 'DisplaySetLevelWindowEvent'.*   The function sets the 'levelwindow' property of the topmost visible image that is display by the sending renderer.*   The level and window value for this property were previously determined by the mouse interaction event.*/MITKCORE_EXPORT StdFunctionCommand::ActionFunction SetLevelWindowAction();mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::SetLevelWindowAction()
{auto actionFunction = [](const itk::EventObject& displayInteractorEvent){if (DisplaySetLevelWindowEvent().CheckEvent(&displayInteractorEvent)){const DisplaySetLevelWindowEvent* displayActionEvent = dynamic_cast<const DisplaySetLevelWindowEvent*>(&displayInteractorEvent);const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender();if (nullptr == sendingRenderer){return;}// get the the topmost visible image of the sending rendererDataStorage::Pointer storage = sendingRenderer->GetDataStorage();DataStorage::SetOfObjects::ConstPointer allImageNodes = storage->GetSubset(NodePredicateDataType::New("Image"));Point3D worldposition;const auto* positionEvent = dynamic_cast<const InteractionPositionEvent*>(displayActionEvent->GetInteractionEvent());sendingRenderer->DisplayToWorld(positionEvent->GetPointerPositionOnScreen(), worldposition);auto globalCurrentTimePoint = sendingRenderer->GetTime();DataNode::Pointer node = FindTopmostVisibleNode(allImageNodes, worldposition, globalCurrentTimePoint, sendingRenderer);if (node.IsNull()){return;}LevelWindow levelWindow = LevelWindow();node->GetLevelWindow(levelWindow);ScalarType level = levelWindow.GetLevel();ScalarType window = levelWindow.GetWindow();level += displayActionEvent->GetLevel();window += displayActionEvent->GetWindow();levelWindow.SetLevelWindow(level, window);auto* levelWindowProperty = dynamic_cast<LevelWindowProperty*>(node->GetProperty("levelwindow"));if (nullptr != levelWindowProperty){levelWindowProperty->SetLevelWindow(levelWindow);RenderingManager::GetInstance()->RequestUpdateAll();}}};

6 DisplaySetLevelWindowEvent类得到窗体交互新增的窗宽窗位值

class MITKCORE_EXPORT DisplaySetLevelWindowEvent : public DisplayActionEvent{public:typedef DisplaySetLevelWindowEvent Self;typedef DisplayActionEvent Superclass;DisplaySetLevelWindowEvent() : Superclass() {}DisplaySetLevelWindowEvent(InteractionEvent* interactionEvent, ScalarType level, ScalarType window): Superclass(interactionEvent), m_Level(level), m_Window(window){}~DisplaySetLevelWindowEvent() override {}const char* GetEventName() const override { return "DisplaySetLevelWindowEvent"; }bool CheckEvent(const itk::EventObject *e) const override { return dynamic_cast<const Self *>(e) != nullptr; }itk::EventObject* MakeObject() const override { return new Self(GetInteractionEvent(), m_Level, m_Window); }ScalarType GetLevel() const { return m_Level; }ScalarType GetWindow() const { return m_Window; }DisplaySetLevelWindowEvent(const Self& s) : Superclass(s), m_Level(s.GetLevel()), m_Window(s.GetWindow()) {};private:ScalarType m_Level;ScalarType m_Window;};

7 QmitkLevelWindowWidgetContextMenu


/*** \ingroup QmitkModule* \brief Provides a contextmenu for Level/Window functionality.** Either creates* a new contextmenu with standard functions or adds Level/Window standard* functions to an predefined contextmenu.*/
class MITKQTWIDGETS_EXPORT QmitkLevelWindowWidgetContextMenu : public QWidget
{Q_OBJECTpublic:/// constructorQmitkLevelWindowWidgetContextMenu(QWidget *parent, Qt::WindowFlags f = nullptr);~QmitkLevelWindowWidgetContextMenu() override;

8 QmitkLineEditLevelWindowWidget

/*** \ingroup QmitkModule* \brief Provides a widget with two lineedit fields, one to change the* window value of the current image and one to change the level value of* the current image.*/
class MITKQTWIDGETS_EXPORT QmitkLineEditLevelWindowWidget : public QWidget
{Q_OBJECTpublic:/// constructorQmitkLineEditLevelWindowWidget(QWidget *parent = nullptr, Qt::WindowFlags f = nullptr);/// destructor~QmitkLineEditLevelWindowWidget() override;/// inputfield for level valueQLineEdit *m_LevelInput;/// inputfield for window valueQLineEdit *m_WindowInput;

9 QmitkSliderLevelWindowWidget


#ifndef QMITKSLIDERLEVELWINDOWWIDGET_H
#define QMITKSLIDERLEVELWINDOWWIDGET_H#include <MitkQtWidgetsExports.h>#include <QWidget>
#include <mitkLevelWindowManager.h>class QmitkLevelWindowWidgetContextMenu;/*** \ingroup QmitkModule** \brief Provides a widget with a slider to change the level and* window value of the current image.** This documentation actually refers to the QmitkLevelWindowWidget* and is only put in this class due to technical issues (should be* moved later).** The QmitkLevelWindowWidget is a kind of container for a* QmitkSliderLevelWindowWidget (this is the cyan bar above the text* input fields) and a QmitkLineEditLevelWindowWidget (with two text* input fields). It holds a reference to a mitk::LevelWindowManager* variable, which keeps the LevelWindowProperty of the currently* selected image. Level/Window is manipulated by the text inputs and* the Slider to adjust brightness/contrast of a single image. All* changes on the slider or in the text input fields affect the current* image by giving new values to LevelWindowManager. LevelWindowManager* then sends a signal to tell other listeners about changes.** Which image is changed is determined by mitkLevelWindowManager. If* m_AutoTopMost is true, always the topmost image in data tree (layer* property) is affected by changes. The image which is affected by* changes can also be changed by QmitkLevelWindowWidgetContextMenu,* the context menu for QmitkSliderLevelWindowWidget and* QmitkLineEditLevelWindowWidget. There you have the possibility to* set a certain image or always the topmost image in the data tree* (layer property) to be affected by changes.** The internal mitk::LevelWindow variable contains a range that is* valid for a given image. It should not be possible to move the* level/window parameters outside this range. The range can be changed* and reset to its default values by QmitkLevelWindowWidgetContextMenu,* the context menu for QmitkSliderLevelWindowWidget and* QmitkLineEditLevelWindowWidget.** Now for the behaviour of the text inputs: The upper one contains the* value of the level (brightness), the lower one shows the window (contrast).** The behaviour of the cyan bar is more obvious: the scale in the* background shows the valid range. The cyan bar in front displays the* currently selected level/window setting. You can change the level by* dragging the bar with the left mouse button or clicking somewhere inside* the scalerange with the left mouse button. The window is changed by* moving the mouse on the upper or lower bound of the bar until the cursor* becomes an vertical double-arrowed symbol. Then you can change the* windowsize by clicking the left mouse button and move the mouse upwards* or downwards. The bar becomes greater upwards as well as downwards. If* you want to change the size of the window in only one direction you* have to press the CTRL-key while doing the same as mentioned above.* This information is also presented by a tooltip text when moving the* mouse on the upper or lower bound of the bar.*/
class MITKQTWIDGETS_EXPORT QmitkSliderLevelWindowWidget : public QWidget
{Q_OBJECTpublic:/// constructorQmitkSliderLevelWindowWidget(QWidget *parent = nullptr, Qt::WindowFlags f = nullptr);/// destructor~QmitkSliderLevelWindowWidget() override;/// sets the manager who is responsible to collect and deliver changes on Level/Windowvoid SetLevelWindowManager(mitk::LevelWindowManager *levelWindowManager);/// sets the DataStorage which holds all image-nodesvoid SetDataStorage(mitk::DataStorage *ds);/// returns the manager who is responsible to collect and deliver changes on Level/Windowmitk::LevelWindowManager *GetManager();mitk::LevelWindow m_LevelWindow;/// manager who is responsible to collect and deliver changes on Level/Windowmitk::LevelWindowManager::Pointer m_Manager;private:/// creates the context menu for this widget from class QmitkLevelWindowWidgetContextMenuvoid contextMenuEvent(QContextMenuEvent *) override;/// change notifications from the mitkLevelWindowManagervoid OnPropertyModified(const itk::EventObject &e);protected:/// recalculate the size and position of the slider barvirtual void Update();/*!* helper for drawing the component*/QRect m_Rect;/*!* helper for drawing the component*/QPoint m_StartPos;bool m_Resize;bool m_Bottom;bool m_MouseDown;bool m_Leftbutton;bool m_CtrlPressed;int m_MoveHeight;bool m_ScaleVisible;QRect m_LowerBound;QRect m_UpperBound;unsigned long m_ObserverTag;bool m_IsObserverTagSet;QFont m_Font;/*!*  data structure which creates the context menu for QmitkLineEditLevelWindowWidget*/QmitkLevelWindowWidgetContextMenu *m_Contextmenu;/*!* repaint the slider and the scale*/void paintEvent(QPaintEvent *e) override;/*!* method implements the component behavior** checks if cursor is on upper or lower bound of slider bar and changes cursor symbol** checks if left mouse button is pressed and if CTRL is pressed and changes sliderbar in move-direction accordingly*/void mouseMoveEvent(QMouseEvent *mouseEvent) override;void enterEvent(QEvent *event) override;/*!*  registers events when a mousebutton is pressed** if leftbutton is pressed m_Leftbutton is set to true** also checks if CTRL is pressed and sets the bool variable m_CtrlPressed*/void mousePressEvent(QMouseEvent *mouseEvent) override;/*!*  sets the variable m_MouseDown to false*/void mouseReleaseEvent(QMouseEvent *mouseEvent) override;/*!* causes an update of the sliderbar when resizing the window*/void resizeEvent(QResizeEvent *event) override;protected Q_SLOTS:/** @brief Hide the scale if "Hide Scale" is selected in the context menu*/void HideScale();/** @brief Shows the scale if "Show Scale" is selected in the context menu*/void ShowScale();
};#endif // QMITKSLIDERLEVELWINDOWWIDGET_H

10 QmitkLevelWindowWidget

#include "QmitkLevelWindowWidget.h"
#include "QmitkSliderLevelWindowWidget.h"QmitkLevelWindowWidget::QmitkLevelWindowWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f)
{this->setupUi(this);m_Manager = mitk::LevelWindowManager::New();SliderLevelWindowWidget->SetLevelWindowManager(m_Manager.GetPointer());LineEditLevelWindowWidget->SetLevelWindowManager(m_Manager.GetPointer());
}void QmitkLevelWindowWidget::SetDataStorage(mitk::DataStorage *ds)
{m_Manager->SetDataStorage(ds);
}mitk::LevelWindowManager *QmitkLevelWindowWidget::GetManager()
{return m_Manager.GetPointer();
}

11 LevelWindowManager


#ifndef MITKLEVELWINDOWMANAGER_H
#define MITKLEVELWINDOWMANAGER_H// mitk core
#include "mitkBaseProperty.h"
#include "mitkDataStorage.h"
#include "mitkLevelWindowProperty.h"//  c++
#include <map>
#include <utility>namespace mitk
{/**@brief Provides access to the LevelWindowProperty object and LevelWindow of the "current" image.- provides a LevelWindowProperty for purposes like GUI editors- this property comes from one of two possible sources- either something (e.g. the application) sets the property because of some user selection- OR the "Auto top-most" logic is used to search a DataStorage for the image with the highest "layer" propertyvalueChanges on Level/Window can be set with SetLevelWindow() and will affect either the topmost layer image,if IsAutoTopMost() returns true, or an image which is set by SetLevelWindowProperty(LevelWindowProperty::PointerlevelWindowProperty).Additionally the changes on Level/Window will affect one or multiple selected images, if IsSelectedImages() returns true.Only one of the two different modes can be enabled at the same time.Changes to Level/Window, when another image gets active or by SetLevelWindow(const LevelWindow& levelWindow),will be sent to all listeners by Modified().DataStorageChanged() listens to the DataStorage for new or removed images. Depending on the currently enabled mode,the new image becomes active or not. If an image is removed from the DataStorage and m_AutoTopMost is false,there is a check to proof, if the active image is still available. If not, then m_AutoTopMost becomes true.Note that this class is not thread safe at the moment!*/class MITKCORE_EXPORT LevelWindowManager : public itk::Object{public:mitkClassMacroItkParent(LevelWindowManager, itk::Object);itkFactorylessNewMacro(Self);itkCloneMacro(Self);void SetDataStorage(DataStorage* dataStorage);DataStorage *GetDataStorage();/*** @brief (Re-)Initialize the LevelWindowManager by setting the topmost image.*        Use the removedNode parameter if a node was removed.** @param autoTopMost    Set the topmost layer image to be affected by changes, if true.* @param removedNode    A node was removed from the data storage if != nullptr.*/void SetAutoTopMostImage(bool autoTopMost, const DataNode *removedNode = nullptr);/*** @brief (Re-)Initialize the LevelWindowManager by setting the selected images.*         Use the removedNode parameter if a node was removed.** @param selectedImagesMode  Set the selected images to be affected by changes, if true.* @param removedNode         A node was removed from the data storage if != nullptr.*/void SetSelectedImages(bool selectedImagesMode, const DataNode *removedNode = nullptr);void RecalculateLevelWindowForSelectedComponent(const itk::EventObject&);/*** @brief Update the level window.*        This function is called if a property of a data node is changed.*        Relevant properties are defined in the protected 'ObserverToPropertyValueMap'-members.*/void Update(const itk::EventObject&);/*** @brief Update the level window.*        This function is only called if the 'selected' property of a data node is changed.*        This is done in order to avoid finding the correct image each time a node is selected but*        the 'm_SelectedImages' bool value is set to false (as the normal 'Update'-function would do).*        Changes of the 'selected' property happen quite a lot so this should not slow down the application.*/void UpdateSelected(const itk::EventObject&);/*** @brief Set a specific LevelWindowProperty; all changes will affect the image belonging to this property.* @throw mitk::Exception Throw an exception if the there is no image in the data storage which belongs to this*        property.*/void SetLevelWindowProperty(LevelWindowProperty::Pointer levelWindowProperty);/***   @brief Set new Level/Window values and inform all listeners about changes.*/void SetLevelWindow(const LevelWindow &levelWindow);/*** @brief Return the current LevelWindowProperty object from the image that is affected by changes.** @return The current LevelWindowProperty*/LevelWindowProperty::Pointer GetLevelWindowProperty() const;/*** @brief Return Level/Window values for the current image** @return The LevelWindow value for the current image.*/const LevelWindow &GetLevelWindow() const;/*** @brief Return true, if level window changes will affect the topmost layer image.** @return Return the member value that denotes the auto-topmost mode.*/bool IsAutoTopMost() const;/*** @brief Return true, if level window changes will affect the currently selected images.** @return Return the member value that denotes the selected-images mode.*/bool IsSelectedImages() const;/*** @brief This method is called when a node is added to the data storage.*        A listener on the data storage is used to call this method automatically after a node was added.* @throw mitk::Exception Throws an exception if something is wrong, e.g. if the number of observers differs from*        the number of nodes.*/void DataStorageAddedNode(const DataNode *dataNode = nullptr);/*** @brief This method is called when a node is removed from the data storage.*        A listener on the data storage is used to call this method automatically before a node will be removed.* @throw mitk::Exception Throws an exception if something is wrong, e.g. if the number of observers differs from*        the number of nodes.*/void DataStorageRemovedNode(const DataNode *dataNode = nullptr);/*** @brief Change notifications from mitkLevelWindowProperty.*/void OnPropertyModified(const itk::EventObject&);/*** @brief Return the currently active image.** @return The member variable holding the currently active image.*/Image *GetCurrentImage() const;/*** @brief Return the number of observers for data node's "visible" property.*        This basically returns the number of relevant nodes to observe.** @return The current number of observers which are registered in this object.*/int GetNumberOfObservers() const;/*** @brief Return all nodes in the data storage that have the following properties:*   - "binary" == false*   - "levelwindow"*   - DataType == Image / DiffusionImage / TensorImage / OdfImage / ShImage*@ return The filtered list of relevant nodes in the data storage*/DataStorage::SetOfObjects::ConstPointer GetRelevantNodes() const;private:LevelWindowManager();~LevelWindowManager() override;DataStorage::Pointer m_DataStorage;LevelWindowProperty::Pointer m_LevelWindowProperty;typedef std::pair<unsigned long, DataNode::Pointer> PropDataPair;typedef std::map<PropDataPair, BaseProperty::Pointer> ObserverToPropertyValueMap;ObserverToPropertyValueMap m_ObserverToVisibleProperty;ObserverToPropertyValueMap m_ObserverToLayerProperty;ObserverToPropertyValueMap m_ObserverToRenderingModeProperty;ObserverToPropertyValueMap m_ObserverToDisplayedComponentProperty;ObserverToPropertyValueMap m_ObserverToLevelWindowImageProperty;ObserverToPropertyValueMap m_ObserverToSelectedProperty;void UpdateObservers();void ClearPropertyObserverMaps();void CreatePropertyObserverMaps();bool HasLevelWindowRenderingMode(DataNode *dataNode) const;// This variable holds a data node which will be deleted from the datastorage immediately.const DataNode *m_NodeMarkedToDelete;bool m_AutoTopMost;bool m_SelectedImagesMode;unsigned long m_PropertyModifiedTag;Image *m_CurrentImage;std::vector<DataNode::Pointer> m_DataNodesForLevelWindow;bool m_IsPropertyModifiedTagSet;bool m_LevelWindowMutex;};
}#endif // MITKLEVELWINDOWMANAGER_H

12  多视图窗体中创建窗宽窗位控件

// create level window slider on the right sideif (nullptr == m_Impl->m_LevelWindowWidget){m_Impl->m_LevelWindowWidget = new QmitkLevelWindowWidget(parent);m_Impl->m_LevelWindowWidget->setObjectName(QString::fromUtf8("levelWindowWidget"));QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);sizePolicy.setHorizontalStretch(0);sizePolicy.setVerticalStretch(0);sizePolicy.setHeightForWidth(m_Impl->m_LevelWindowWidget->sizePolicy().hasHeightForWidth());m_Impl->m_LevelWindowWidget->setSizePolicy(sizePolicy);m_Impl->m_LevelWindowWidget->setMaximumWidth(50);}

MITK中窗宽窗位相关代码相关推荐

  1. 使用pydicom实现Dicom文件读取与CT图像窗宽窗位调整

    1. 前言 为了能够在Labelme上对Dicom图像进行编辑,这里对python环境下Dicom文件的读取进行了研究.在Dicom图像中CT的窗宽窗位是一个很重要的概念,但是找了半天在pydicom ...

  2. CT图像之Hu值变换与窗宽窗位调整

    今天通过分析实验结果,完善了之前的预处理代码,借此博文分享给大家,另外 点击此处可以查看预处理的完整代码,欢迎大家一起来完善. 最重要的是,欢迎大家的批评指正,您的建议和意见将会是我成长源泉. 接下来 ...

  3. ITK (1)窗宽窗位的意义与设置

    背景与意义 医学图像与传统可视化图像相比,其具有更大的"灰度"范围.如,普通图像(灰度图像)的灰度范围一般是256级(即图像中最亮的点的灰度值定义为0,最亮的定义为255,也就是2 ...

  4. X线DR医学图像 --- 直方图的窗宽窗位调整(Matlab篇)

    X线图像直方图的窗宽窗位的调整 图像的直方图显示了图像的灰阶分布.说白了就是,显示了图像当中每一个点的亮度分布情况(整个图像当中比较亮的点有多少个,黑的点又有多少个.反之,也可以看出某个点是落在了亮的 ...

  5. 8bit黑白图像的灰度值范围是_窗宽窗位对基于互信息的医学图像

    窗宽窗位对基于互信息的医学图像 摘 要:基于互信息的配准方法具有自动化程度高.配准精度高等优点,近来已成为医学图像处理领域的热点.基于互信息的配准方法实质上是一种对灰度进行统计和计算的方法,因此同一图 ...

  6. 医学图像处理涉及到的窗宽窗位 1

    先说一下CT值是什么 CT图像反映的是人体对X射线吸收的系数,但我们关心的是各组织结构的密度差异,即相对密度,如果某组织发生病变,其密度就会发生变化,但由于比较吸收系数非常繁琐,于是亨氏把组织器官对X ...

  7. vtk窗宽窗位,以及图像反白思路

    普通图像的灰度范围一般是256级,而医学图像基于其特殊性,灰度级较普通图像会高很多.人体组织在CT上能分辨出2000个不同的灰度,而人眼只能分辨16个灰度,将这2000个CT值用16阶灰度反应的话,人 ...

  8. matlab设置固定的窗宽窗位,python实现CT窗宽窗位的调整(即指定HU值保存图像)...

    最近一直在做实验,所以好久没有更新了,先把上周做的一些小的实验贴出来供大家分享. 在医生诊断时,是会将CT图像调整成不同的窗来处理的.比如说肺部CT吧,肺窗(窗宽为2000,窗位为-400)用于看小的 ...

  9. python nii 图像读取,转换成CT 值,设置窗宽窗位,保存成png 图像

    import numpy as np import os # 遍历文件夹 import nibabel as nib # nii格式一般都会用到这个包 import imageio # 转换成图像ce ...

最新文章

  1. [A Dangerous Maze LightOJ - 1027 ][概率题]
  2. Exchange ActiveSync
  3. python操作目录_详解python中的文件与目录操作
  4. 在Ubuntu中安装VMD
  5. CentOs7安装apache以及遇到的问题
  6. python的网页解析器_python 之网页解析器
  7. 休眠锁定模式– PESSIMISTIC_FORCE_INCREMENT锁定模式如何工作
  8. 雨滴桌面时间插件_真香!这 3 款软件,让你的电脑桌面清爽又高效!
  9. 小D课堂 - 零基础入门SpringBoot2.X到实战_第三节SpringBoot热部署devtool和配置文件自动注入实战_15、SpringBoot2.x配置文件讲解...
  10. mysql carnation_RDS mysql5.6 数据库还原到本地
  11. AppBox v6.0中实现子页面和父页面的复杂交互
  12. 三极管饱和时内部状态再探
  13. 浅析游戏音效中的虚拟音效
  14. 斯坦福极简经济学 读书笔记
  15. “智造”转型:IBM协助福耀玻璃抢占市场先机
  16. [C++程序设计](入门级题解)统计天数
  17. Python金融数据分析入门到实战-视频课程
  18. 朋友圈集赞,简洁壁纸,玩游戏学git
  19. Spring Security 配置白名单访问后,仍然报错403
  20. Asterisk模块编写指南

热门文章

  1. php框架列举,列举PHP的Yii 2框架的开发优势
  2. 查看linux版本是多少位
  3. OHEM,Focal loss,GHM loss二分类pytorch代码实现(减轻难易样本不均衡问题)
  4. Akka 指南 之「消息传递可靠性」
  5. php青蛙跳井代码,四川招警考试行测答题技巧:青蛙跳井问题全解析
  6. 【Unity3d】 制作游戏主菜单 GUI
  7. bootstrap-table固定表头固定列
  8. Netty 大文件传输
  9. Python: 使用xlrd读取Excel文件
  10. 哈工大软件过程与工具----UML图