diff --git a/source/FAST/Algorithms/ApplyColormap/ApplyColormap.cpp b/source/FAST/Algorithms/ApplyColormap/ApplyColormap.cpp index a94e7a15b..d5cfbebfa 100644 --- a/source/FAST/Algorithms/ApplyColormap/ApplyColormap.cpp +++ b/source/FAST/Algorithms/ApplyColormap/ApplyColormap.cpp @@ -2,12 +2,13 @@ #include namespace fast { -ApplyColormap::ApplyColormap(Colormap colormap, float minValue, float maxValue) { +ApplyColormap::ApplyColormap(Colormap colormap, float opacity, float minValue, float maxValue) { createInputPort(0, "Image"); createOutputPort(0, "Image"); setColormap(colormap); setMinValue(minValue); setMaxValue(maxValue); + setOpacity(opacity); createOpenCLProgram(Config::getKernelSourcePath() + "/Algorithms/ApplyColormap/ApplyColormap.cl"); } @@ -30,7 +31,7 @@ void ApplyColormap::execute() { if(m_colormap.isGrayscale()) { output = Image::create(input->getSize(), TYPE_UINT8, 1); } else { - if(m_colormap.hasOpacity()) { + if(m_colormap.hasOpacity() || m_opacity < 1.0f) { output = Image::create(input->getSize(), TYPE_UINT8, 4); } else { output = Image::create(input->getSize(), TYPE_UINT8, 3); @@ -44,7 +45,7 @@ void ApplyColormap::execute() { auto outputAccess = output->getOpenCLImageAccess(ACCESS_READ_WRITE, device); if(!m_bufferUpToDate) { - m_colormapBuffer = m_colormap.getAsOpenCLBuffer(device); + m_colormapBuffer = m_colormap.getAsOpenCLBuffer(device, m_opacity); m_bufferUpToDate = true; } @@ -96,6 +97,14 @@ void ApplyColormap::setMaxValue(float maxValue) { setModified(true); } +void ApplyColormap::setOpacity(float opacity) { + if(opacity < 0.0f || opacity > 1.0f) + throw Exception("Opacity must be within range [0, 1] in ApplyColormap"); + + m_opacity = opacity; + setModified(true); +} + bool Colormap::isGrayscale() const { return m_grayscale; } @@ -154,15 +163,38 @@ void Colormap::checkData() const { } } -cl::Buffer Colormap::getAsOpenCLBuffer(OpenCLDevice::pointer device) const { +cl::Buffer Colormap::getAsOpenCLBuffer(OpenCLDevice::pointer device, float opacity) const { if(m_data.empty()) throw Exception("Trying to get OpenCL buffer of empty Colormap"); checkData(); + auto dataToTransfer = m_data; + if(opacity < 1.0f) { + int elements = 4; + if(m_grayscale) { + elements = 2; + } else { + if(m_hasOpacity) + elements = 5; + if(!hasOpacity()) { + // Have to add opacity channel + dataToTransfer = {}; + for(int i = 0; i < m_data.size(); ++i) { + dataToTransfer.push_back(m_data[i]); + if((i+1) % elements == 0) + dataToTransfer.push_back(opacity); + } + } else { + for(int i = elements-1; i < m_data.size(); i += elements) { + dataToTransfer[i] *= opacity; + } + } + } + } return cl::Buffer( device->getContext(), CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, - m_data.size()*sizeof(float), - (void*)m_data.data() + dataToTransfer.size()*sizeof(float), + (void*)dataToTransfer.data() ); } @@ -233,7 +265,7 @@ Colormap Colormap::Inferno(bool withOpacity) { {0.3, Color(80.0f/255, 35.0f/255, 0, 0.1f*enableOpacity)}, {0.4, Color(140.0f/255, 30.0f/255, 0, 0.3f*enableOpacity)}, {0.6, Color(200.0f/255, 160.0f/255, 0, 0.5f*enableOpacity)}, - {0.85, Color(255.0f/255, 255.0f/255, 255.0f/255, 0.8f*enableOpacity)}, + {1.0, Color(255.0f/255, 255.0f/255, 255.0f/255, 0.8f*enableOpacity)}, }, true, true); } diff --git a/source/FAST/Algorithms/ApplyColormap/ApplyColormap.hpp b/source/FAST/Algorithms/ApplyColormap/ApplyColormap.hpp index 787f6f463..83ebd671d 100644 --- a/source/FAST/Algorithms/ApplyColormap/ApplyColormap.hpp +++ b/source/FAST/Algorithms/ApplyColormap/ApplyColormap.hpp @@ -45,12 +45,30 @@ class FAST_EXPORT Colormap { /** * @brief Create an OpenCL buffer from the colormap data. * @param device OpenCL device to transfer data to + * @param opacity Opacity to apply to colormap. If lower than 1 opacity will be added to the colormap. + * If the colormap already has opacity, this opacity will be multiplied with the existing opacity. * @return OpenCL buffer */ - cl::Buffer getAsOpenCLBuffer(OpenCLDevice::pointer device) const; + cl::Buffer getAsOpenCLBuffer(OpenCLDevice::pointer device, float opacity = 1.0f) const; + /** + * @brief Has this colormap opacity defined + * @return + */ bool hasOpacity() const; + /** + * @brief Is this colormap grayscale + * @return + */ bool isGrayscale() const; + /** + * @brief Is this colormap grayscale + * @return + */ bool isInterpolated() const; + /** + * @brief Is this colormap intensity invariant + * @return + */ bool isIntensityInvariant() const; int getSteps() const; /** @@ -59,7 +77,18 @@ class FAST_EXPORT Colormap { */ std::vector getData() const; + /** + * @brief Ultrasound S-curve colormap (grayscale and color (with a hint of blue)) + * @param grayscale + * @return ultrasound colormap + */ static Colormap Ultrasound(bool grayscale = false); + /** + * @brief Inferno heatmap + * @param withOpacity Create inferno heatmap with custom opacity. + * If you will use this heatmap as an overlay you should enable this. + * @return inferno heatmap + */ static Colormap Inferno(bool withOpacity = false); private: std::vector m_data; @@ -89,10 +118,17 @@ class FAST_EXPORT ApplyColormap : public ProcessObject { /** * @brief Create instance * @param colormap Colormap to apply + * @param opacity Apply colormap with an opacity. + * If the colormap already has opacity, this opacity will be multiplied with the existing opacity. + * @param minValue Set the minimum value of the input data to scale the colormap to. This is only used + * on intensity invariant colormaps. If not set, the true minimum value of the input data is used. + * @param maxValue Set the maximum value of the input data to scale the colormap to. This is only used + * on intensity invariant colormaps. If not set, the true maximum value of the input data is used. * @return instance */ FAST_CONSTRUCTOR(ApplyColormap, Colormap, colormap,, + float, opacity, = 1.0f, float, minValue, = std::nanf(""), float, maxValue, = std::nanf("") ); @@ -100,6 +136,7 @@ class FAST_EXPORT ApplyColormap : public ProcessObject { Colormap getColormap() const; void setMinValue(float minValue); void setMaxValue(float maxValue); + void setOpacity(float opacity); protected: ApplyColormap(); void execute() override; @@ -108,6 +145,7 @@ class FAST_EXPORT ApplyColormap : public ProcessObject { cl::Buffer m_colormapBuffer; float m_minValue; float m_maxValue; + float m_opacity = 1.0f; }; } // end namespace \ No newline at end of file