mirror of
https://github.com/jkriege2/JKQtPlotter.git
synced 2024-12-26 18:41:40 +08:00
1080 lines
54 KiB
C++
1080 lines
54 KiB
C++
/*
|
|
Copyright (c) 2008-2022 Jan W. Krieger (<jan@jkrieger.de>)
|
|
|
|
|
|
|
|
This software is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License (LGPL) as published by
|
|
the Free Software Foundation, either version 2.1 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License (LGPL) for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License (LGPL)
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
#ifndef JKQTPBASICIMAGETOOLS_H
|
|
#define JKQTPBASICIMAGETOOLS_H
|
|
#include <QIcon>
|
|
#include <QDebug>
|
|
#include <QImage>
|
|
#include <QStringList>
|
|
#include <cmath>
|
|
#include <cfloat>
|
|
#include <stdint.h>
|
|
#include <QColor>
|
|
#include <vector>
|
|
#include "jkqtcommon/jkqtcommon_imexport.h"
|
|
#include "jkqtcommon/jkqtpmathtools.h"
|
|
|
|
/** \brief possible datatypes of the data array, plotted by this class.
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
*/
|
|
enum class JKQTPMathImageDataType {
|
|
FloatArray, /*!< Data is of type \c float */
|
|
DoubleArray, /*!< Data is of type \c double */
|
|
UInt8Array, /*!< Data is of type \c uint8_t */
|
|
UInt16Array, /*!< Data is of type \c uint16_t */
|
|
UInt32Array, /*!< Data is of type \c uint32_t */
|
|
UInt64Array, /*!< Data is of type \c uint8_t */
|
|
Int8Array, /*!< Data is of type \c int8_t */
|
|
Int16Array, /*!< Data is of type \c int16_t */
|
|
Int32Array, /*!< Data is of type \c int32_t */
|
|
Int64Array /*!< Data is of type \c int64_t */
|
|
};
|
|
|
|
/*! \brief retrieve an R/G/B/Alpha (\a ch == 0/1/2/3) value from the \c QRgb value \a rgb
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
*/
|
|
inline int JKQTPGetColorChannel(QRgb rgb, int ch)
|
|
{
|
|
switch(ch) {
|
|
case 0: return qRed(rgb);
|
|
case 1: return qGreen(rgb);
|
|
case 2: return qBlue(rgb);
|
|
case 3: return qAlpha(rgb);
|
|
}
|
|
return qGray(rgb);
|
|
}
|
|
|
|
/*! \brief set the R/G/B/Alpha (\a ch == 0/1/2/3) value in the \c QRgb value \a rgb to \a val (0..255!)
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
*/
|
|
inline void JKQTPSetColorChannel(QRgb& rgb, int ch, int val)
|
|
{
|
|
switch(ch) {
|
|
case 0: rgb= qRgba(val, qGreen(rgb), qBlue(rgb), qAlpha(rgb)); break;
|
|
case 1: rgb= qRgba(qRed(rgb), val, qBlue(rgb), qAlpha(rgb)); break;
|
|
case 2: rgb= qRgba(qRed(rgb), qGreen(rgb), val, qAlpha(rgb)); break;
|
|
case 3: rgb= qRgba(qRed(rgb), qGreen(rgb), qBlue(rgb), val); break;
|
|
}
|
|
}
|
|
|
|
/*! \brief available palettes for coloring an image
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
*/
|
|
enum JKQTPMathImageColorPalette {
|
|
JKQTPMathImageGRAY=0, /*!< \image html palettes/palette_gray.png */
|
|
JKQTPMathImageINVERTEDGRAY, /*!< \image html palettes/palette_invgray.png */
|
|
JKQTPMathImageRED, /*!< \image html palettes/palette_red.png */
|
|
JKQTPMathImageINVERTEDRED, /*!< \image html palettes/palette_invred.png */
|
|
JKQTPMathImageGREEN, /*!< \image html palettes/palette_green.png */
|
|
JKQTPMathImageINVERTEDGREEN, /*!< \image html palettes/palette_invgreen.png */
|
|
JKQTPMathImageBLUE, /*!< \image html palettes/palette_blue.png */
|
|
JKQTPMathImageINVERTEDBLUE, /*!< \image html palettes/palette_invblue.png */
|
|
JKQTPMathImageCYAN, /*!< \image html palettes/palette_cyan.png */
|
|
JKQTPMathImageINVERTED_CYAN, /*!< \image html palettes/palette_invcyan.png */
|
|
JKQTPMathImageYELLOW, /*!< \image html palettes/palette_yellow.png */
|
|
JKQTPMathImageINVERTED_YELLOW, /*!< \image html palettes/palette_invyellow.png */
|
|
JKQTPMathImageMAGENTA, /*!< \image html palettes/palette_magenta.png */
|
|
JKQTPMathImageINVERTED_MAGENTA, /*!< \image html palettes/palette_invmagenta.png */
|
|
|
|
|
|
JKQTPMathImageMATLAB, /*!< \image html palettes/palette_Matlab.png */
|
|
JKQTPMathImageINVERTED_MATLAB, /*!< \image html palettes/palette_invMatlab.png */
|
|
JKQTPMathImageRYGB, /*!< \image html palettes/palette_RYGB.png */
|
|
JKQTPMathImageINVERTED_RYGB, /*!< \image html palettes/palette_invRYGB.png */
|
|
JKQTPMathImageHSV, /*!< \image html palettes/palette_HSV.png */
|
|
JKQTPMathImageINVERTED_HSV, /*!< \image html palettes/palette_invHSV.png */
|
|
JKQTPMathImageRAINBOW, /*!< \image html palettes/palette_rainbow.png */
|
|
JKQTPMathImageINVERTED_RAINBOW, /*!< \image html palettes/palette_invrainbow.png */
|
|
JKQTPMathImageHOT, /*!< \image html palettes/palette_AFMhot.png */
|
|
JKQTPMathImageINVERTED_HOT, /*!< \image html palettes/palette_invAFMhot.png */
|
|
JKQTPMathImageOCEAN, /*!< \image html palettes/palette_ocean.png */
|
|
JKQTPMathImageINVERTED_OCEAN, /*!< \image html palettes/palette_invocean.png */
|
|
JKQTPMathImageTRAFFICLIGHT, /*!< \image html palettes/palette_trafficlight.png */
|
|
JKQTPMathImageINVERTED_TRAFFICLIGHT, /*!< \image html palettes/palette_invtrafficlight.png */
|
|
|
|
JKQTPMathImageBone, /*!< \image html palettes/palette_bone.png */
|
|
JKQTPMathImageCool, /*!< \image html palettes/palette_cool.png */
|
|
JKQTPMathImageCopper, /*!< \image html palettes/palette_copper.png */
|
|
JKQTPMathImageAutumn, /*!< \image html palettes/palette_autumn.png */
|
|
JKQTPMathImageSeismic, /*!< \image html palettes/palette_seismic.png */
|
|
JKQTPMathImageTerrain, /*!< \image html palettes/palette_terrain.png */
|
|
JKQTPMathImageViridis, /*!< \image html palettes/palette_viridis.png
|
|
\see from https://github.com/BIDS/colormap/blob/master/colormaps.py https://github.com/BIDS/colormap/blob/master/colormaps.py */
|
|
JKQTPMathImageMagma, /*!< \image html palettes/palette_magma.png
|
|
\see from https://github.com/BIDS/colormap/blob/master/colormaps.py https://github.com/BIDS/colormap/blob/master/colormaps.py */
|
|
JKQTPMathImageInferno, /*!< \image html palettes/palette_inferno.png
|
|
\see from https://github.com/BIDS/colormap/blob/master/colormaps.py https://github.com/BIDS/colormap/blob/master/colormaps.py */
|
|
JKQTPMathImagePlasma, /*!< \image html palettes/palette_plasma.png
|
|
\see from https://github.com/BIDS/colormap/blob/master/colormaps.py https://github.com/BIDS/colormap/blob/master/colormaps.py */
|
|
|
|
|
|
JKQTPMathImageBLUEMAGENTAYELLOW, /*!< \image html palettes/palette_BlMaYe.png */
|
|
JKQTPMathImageINVERTED_BLUEMAGENTAYELLOW, /*!< \image html palettes/palette_YeMaBl.png */
|
|
JKQTPMathImageYELLOWMAGENTABLUE=JKQTPMathImageINVERTED_BLUEMAGENTAYELLOW, /*!< \image html palettes/palette_YeMaBl.png */
|
|
JKQTPMathImageBLUEYELLOW, /*!< \image html palettes/palette_BlYe.png */
|
|
JKQTPMathImageINVERTED_BLUEYELLOW, /*!< \image html palettes/palette_YeBl.png */
|
|
JKQTPMathImageYELLOWBLUE=JKQTPMathImageINVERTED_BLUEYELLOW, /*!< \image html palettes/palette_YeBl.png */
|
|
|
|
JKQTPMathImageBLUEWHITERED, /*!< \image html palettes/palette_bluewhitered.png */
|
|
JKQTPMathImageREDWHITEBLUE, /*!< \image html palettes/palette_redwhiteblue.png */
|
|
|
|
JKQTPMathImageBLACKBLUEREDYELLOW, /*!< \image html palettes/palette_BBlRdYe.png */
|
|
JKQTPMathImageGREENREDVIOLET, /*!< \image html palettes/palette_GnRdVi.png */
|
|
JKQTPMathImageBLACKBLUEWHITEYELLOWWHITE, /*!< \image html palettes/palette_BWprint.png */
|
|
JKQTPMathImageWHITEYELLOWWHITEBLUEBLACK, /*!< \image html palettes/palette_invBWprint.png */
|
|
JKQTPMathImageBR_GR, /*!< \image html palettes/palette_BrBG.png */
|
|
JKQTPMathImageBrownGreen=JKQTPMathImageBR_GR, /*!< \image html palettes/palette_BrBG.png */
|
|
JKQTPMathImagePU_OR, /*!< \image html palettes/palette_PuOr.png */
|
|
JKQTPMathImageOrangeWhitePurple=JKQTPMathImagePU_OR, /*!< \image html palettes/palette_PuOr.png */
|
|
JKQTPMathImageGN_BU, /*!< \image html palettes/palette_greenblue.png */
|
|
JKQTPMathImageGreenBlue=JKQTPMathImageGN_BU, /*!< \image html palettes/palette_greenblue.png */
|
|
JKQTPMathImageBU_GN, /*!< \image html palettes/palette_bluegreen.png */
|
|
JKQTPMathImageBlueGreen=JKQTPMathImageBU_GN, /*!< \image html palettes/palette_bluegreen.png */
|
|
JKQTPMathImageYL_GN_BU, /*!< \image html palettes/palette_YeGnBu.png */
|
|
JKQTPMathImageYellowGreenBlue=JKQTPMathImageYL_GN_BU, /*!< \image html palettes/palette_YeGnBu.png */
|
|
|
|
JKQTPMathImageBR_GR_STEP, /*!< \image html palettes/palette_stepsBrBG.png */
|
|
JKQTPMathImagePU_OR_STEP, /*!< \image html palettes/palette_stepsPuOr.png */
|
|
JKQTPMathImageGN_BU_STEP, /*!< \image html palettes/palette_stepsGnBl.png */
|
|
JKQTPMathImageBU_GN_STEP, /*!< \image html palettes/palette_stepsBlGn.png */
|
|
JKQTPMathImageYL_GN_BU_STEP, /*!< \image html palettes/palette_stepsYeGnBu.png */
|
|
|
|
|
|
JKQTPMathImageCYANWHITE, /*!< \image html palettes/palette_cyanwhite.png */
|
|
JKQTPMathImageINVERTED_CYANWHITE, /*!< \image html palettes/palette_whitecyan.png */
|
|
JKQTPMathImageWHITECYAN=JKQTPMathImageINVERTED_CYANWHITE, /*!< \image html palettes/palette_whitecyan.png */
|
|
JKQTPMathImageYELLOWWHITE, /*!< \image html palettes/palette_yellowwhite.png */
|
|
JKQTPMathImageINVERTED_YELLOWWHITE, /*!< \image html palettes/palette_whiteyellow.png */
|
|
JKQTPMathImageWHITEYELLOW=JKQTPMathImageINVERTED_YELLOWWHITE, /*!< \image html palettes/palette_whiteyellow.png */
|
|
JKQTPMathImageMAGENTAWHITE, /*!< \image html palettes/palette_magentawhite.png */
|
|
JKQTPMathImageINVERTED_MAGENTAWHITE, /*!< \image html palettes/palette_whitemagenta.png */
|
|
JKQTPMathImageWHITEMAGENTA=JKQTPMathImageINVERTED_MAGENTAWHITE, /*!< \image html palettes/palette_whitemagenta.png */
|
|
JKQTPMathImageBlueGreenRed, /*!< \image html palettes/palette_bluegreenred.png */
|
|
JKQTPMathImageRedGreenBlue, /*!< \image html palettes/palette_redgreenblue.png */
|
|
JKQTPMathImageMagentaYellow, /*!< \image html palettes/palette_magentayellow.png */
|
|
JKQTPMathImageYellowMagenta, /*!< \image html palettes/palette_yellowmagenta.png */
|
|
JKQTPMathImageRedBlue, /*!< \image html palettes/palette_redblue.png */
|
|
JKQTPMathImageBlueRed, /*!< \image html palettes/palette_bluered.png */
|
|
|
|
JKQTPMathImagePREDEFINED_PALETTES_COUNT, /*!< \brief the number of predefined palettes */
|
|
|
|
JKQTPMathImageUSER_PALETTE=65000, /*!< \brief special value for JKQTPImageTools::array2image(), which signals the usage of a provided user-defined palette */
|
|
|
|
JKQTPMathImageALPHA=JKQTPMathImageUSER_PALETTE-2, /*!< \brief special palette with increasing alpha values */
|
|
JKQTPMathImageINVERTED_ALPHA=JKQTPMathImageUSER_PALETTE-1, /*!< \brief special palette with decreasing alpha values */
|
|
|
|
JKQTPMathImageFIRST_REGISTERED_USER_PALETTE=JKQTPMathImagePREDEFINED_PALETTES_COUNT, /*!< \brief the ID of the first user-defined paletted, registered with JKQTPImageTools::registerPalette() or JKQTPImageTools::registerPalettesFromFile() */
|
|
JKQTPMathImageLAST_POSSIBLE_REGISTERED_USER_PALETTE=JKQTPMathImageUSER_PALETTE-10, /*!< \brief the ID of the first user-defined paletted, registered with JKQTPImageTools::registerPalette() or JKQTPImageTools::registerPalettesFromFile() */
|
|
};
|
|
|
|
|
|
|
|
/*! \brief modes available for image pixels that are above/below the pixel value range
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
*/
|
|
enum JKQTPMathImageColorRangeFailAction {
|
|
JKQTPMathImageLastPaletteColor=0, /*!< set to last color in the palette */
|
|
JKQTPMathImageGivenColor=1, /*!< set to the provided min/max color */
|
|
JKQTPMathImageTransparent=2 /*!< set transparent */
|
|
};
|
|
|
|
/*! \brief tool structure that summarizes several static properties of JKQTPlotters palette system,
|
|
also provides functions to work with palettes and register user-defined palettes.
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
|
|
\see \ref JKQTPlotterImagePlot
|
|
*/
|
|
struct JKQTPImageTools {
|
|
|
|
/*! \brief Datatype to store lookup-tables used to map data values (scales to 0..size-1) onto RGB-colors */
|
|
typedef QVector<QRgb> LUTType;
|
|
|
|
/*! \brief Width of the Palette-Icons, generated e.g. by JKQTPImageTools::GetPaletteIcon() */
|
|
static JKQTCOMMON_LIB_EXPORT const int PALETTE_ICON_WIDTH;
|
|
/*! \brief Height of the Palette-Icons, generated e.g. by JKQTPImageTools::GetPaletteIcon() */
|
|
static JKQTCOMMON_LIB_EXPORT const int PALETTE_IMAGEICON_HEIGHT;
|
|
|
|
/*! \brief size of the lookup tables used by JKQTFPimagePlot_array2image() */
|
|
static JKQTCOMMON_LIB_EXPORT const int LUTSIZE;
|
|
|
|
/*! \brief loads all palettes defined in the given palette files \a filename into global_jkqtpimagetools_userluts
|
|
and assigns a new LUT-ID >=JKQTPMathImageFIRST_REGISTERED_USER_PALETTE to each palette
|
|
All new IDs are returned as a list
|
|
|
|
|
|
The file might either be a palette XML-file or a CSV-file:
|
|
|
|
\b CSV-files need to have one of the following two formats (RED/GREEN/BLUE: 0..255):
|
|
\verbatim
|
|
scalar, red, green, blue
|
|
scalar, red, green, blue
|
|
...
|
|
\endverbatim
|
|
or simply
|
|
\verbatim
|
|
red, green, blue
|
|
red, green, blue
|
|
...
|
|
\endverbatim
|
|
The parser will also allow tabs and whitespaces as column separators.
|
|
|
|
|
|
\b CML-files need to have one of the following two formats (RED/GREEN/BLUE/OPACITY: 0..1):
|
|
\verbatim
|
|
<ColorMap name="PALETTENAME" space="RGB">
|
|
<Point x="scalar" r="RED" g="GREEN" b="BLUE"/>
|
|
<Point x="scalar" r="RED" g="GREEN" b="BLUE"/>
|
|
...
|
|
</ColorMap>
|
|
\endverbatim
|
|
optionally several \code <ColorMap>...</ColorMap> \endcode definitions may be put below an arbitrarily named
|
|
document node, e.g.:
|
|
\verbatim
|
|
<ColorMaps>
|
|
<ColorMap name="PALETTENAME" space="RGB">
|
|
<Point x="scalar" r="RED" g="GREEN" b="BLUE"/>
|
|
<Point x="scalar" r="RED" g="GREEN" b="BLUE"/>
|
|
...
|
|
</ColorMap>
|
|
<ColorMap name="PALETTENAME" space="RGB">
|
|
<Point x="scalar" r="RED" g="GREEN" b="BLUE"/>
|
|
<Point x="scalar" r="RED" g="GREEN" b="BLUE"/>
|
|
...
|
|
</ColorMap>
|
|
...
|
|
</ColorMaps>
|
|
\endverbatim
|
|
|
|
\note In both cases, the palette will be formed without interpolation, i.e. using JKQTPBuildColorPaletteLUT() .
|
|
If in addition \a interpolatePalette is set to \c true, the function JKQTPBuildColorPaletteLUTLinInterpolate()
|
|
is used instead.
|
|
|
|
\see \ref JKQTPlotterImagePlot , JKQTPBuildColorPaletteLUT()
|
|
*/
|
|
static JKQTCOMMON_LIB_EXPORT QVector<int> registerPalettesFromFile(const QString& filename, bool interpolatePalette=false);
|
|
|
|
/*! \brief registers a new LUT defined by \a paletteLut and with the given \a name (computer-readable) for later use, optionally stores also the human-readable and localized name \a nameT
|
|
and assigns a new LUT-ID >=JKQTPMathImageFIRST_REGISTERED_USER_PALETTE to the palette and returns it
|
|
|
|
\see \ref JKQTPlotterImagePlot, JKQTPBuildColorPaletteLUTLinInterpolate(), JKQTPBuildColorPaletteLUT(), JKQTPBuildColorPaletteLUTLinInterpolateSorted(), JKQTPBuildColorPaletteLUTSorted(), JKQTPBuildColorPaletteLUTLinInterpolate(), JKQTPBuildColorPaletteLUT()
|
|
*/
|
|
static JKQTCOMMON_LIB_EXPORT int registerPalette(const QString& name, const LUTType &paletteLut, const QString &nameT=QString());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*! \brief convert a 2D image (as 1D array) into a QImage with given palette (see JKQTFPColorPalette)
|
|
|
|
\param dbl_in pointer to a 1D array of template type \c T representing the image to plot. This array has to be of size \a width * \a height
|
|
\param width width of the array in \a dbl
|
|
\param height height of the array in \a dbl
|
|
\param[out] img the QImage object to draw to (should be initialized as \c QImage::Format_ARGB32 )
|
|
\param palette the color palette to use for the display
|
|
\param minColor lower boundary of color range in \a dbl pixels, if \a minColor == \a maxColor then this function will extract the image min and image max.
|
|
\param maxColor upper boundary of color range in \a dbl pixels, if \a minColor == \a maxColor then this function will extract the image min and image max.
|
|
\param paletteMinFail specifies what shell happen, when a value in \a dbl is below \a minColor
|
|
\param paletteMaxFail specifies what shell happen, when a value in \a dbl is above \a maxColor
|
|
\param minFailColor color to use for pixels that are below \a minColor for some settings of \a paletteMinFail
|
|
\param maxFailColor color to use for pixels that are below \a maxColor for some settings of \a paletteMaxFail
|
|
\param nanColor color to use for pixels that are not-a-number
|
|
\param infColor color to use for pixels that are infinity
|
|
\param logScale create a log-scaled image
|
|
\param logBase base for the logarithm used when \c logScale==true
|
|
\param lutUser user define LUT, used if \a palette \c ==JKQTPMathImageUSER_PALETTE
|
|
\note There is a variant of this function that is called with a userLUT directly, instead of \a palette
|
|
*/
|
|
template <class T>
|
|
static inline void array2image(const T* dbl_in, int width, int height, QImage &img, JKQTPMathImageColorPalette palette, double minColor, double maxColor, JKQTPMathImageColorRangeFailAction paletteMinFail=JKQTPMathImageLastPaletteColor, JKQTPMathImageColorRangeFailAction paletteMaxFail=JKQTPMathImageLastPaletteColor, QColor minFailColor=QColor("black"), QColor maxFailColor=QColor("black"), QColor nanColor=QColor("black"), QColor infColor=QColor("black"), bool logScale=false, double logBase=10.0, const LUTType& lutUser=LUTType())
|
|
{
|
|
if (!dbl_in || width<=0 || height<=0)
|
|
return;
|
|
|
|
double min = *dbl_in;
|
|
double max = *dbl_in;
|
|
if (jkqtp_approximatelyEqual(minColor, maxColor, JKQTP_DOUBLE_EPSILON)) {
|
|
bool first=true;
|
|
for (int i=1; i<width*height; ++i)
|
|
{
|
|
T v=dbl_in[i];
|
|
if (!(std::isnan(static_cast<long double>(v)) || std::isinf(static_cast<long double>(v)))) {
|
|
if (first) {
|
|
min=max=v;
|
|
first=false;
|
|
} else {
|
|
if (v < min)
|
|
min = v;
|
|
else if (v > max)
|
|
max = v;
|
|
}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
min = minColor;
|
|
max = maxColor;
|
|
}
|
|
|
|
const T* dbl=dbl_in;
|
|
QVector<T> dbl1;
|
|
if (logScale) {
|
|
double logB=log10(logBase);
|
|
dbl1=QVector<T>(width*height, 0);
|
|
for (int i=0; i<width*height; i++) {
|
|
dbl1[i]=log10(dbl_in[i])/logB;
|
|
}
|
|
dbl=dbl1.data();
|
|
min=log10(min)/logB;
|
|
max=log10(max)/logB;
|
|
}
|
|
double delta=max-min;
|
|
|
|
|
|
// either use lutUser (if palette==JKQTPMathImageUSER_PALETTE) or else read the LUT from the internal storage
|
|
const LUTType& lut_used=(palette==JKQTPMathImageUSER_PALETTE)?lutUser:getLUTforPalette(JKQTPImageTools::global_jkqtpimagetools_lutstore, palette);
|
|
|
|
img = QImage(width, height, QImage::Format_ARGB32);
|
|
if (jkqtp_approximatelyEqual(min, max, JKQTP_DOUBLE_EPSILON)) {
|
|
img.fill(0);
|
|
} else {
|
|
const int lutSize=lut_used.size();
|
|
if (lutSize>0) {
|
|
// LUT found: collor the image accordingly
|
|
for (int j=0; j<height; ++j) {
|
|
QRgb* line=reinterpret_cast<QRgb*>(img.scanLine(height-1-j));
|
|
for (int i=0; i<width; ++i) {
|
|
double val=dbl[j*width+i];
|
|
if (std::isnan(val)) {
|
|
line[i]=nanColor.rgba();
|
|
} else if (std::isinf(val)) {
|
|
line[i]=infColor.rgba();
|
|
} else {
|
|
const int v = static_cast<int>((val-min)/delta*static_cast<double>(lutSize-1));
|
|
const int vv = (v < 0) ? 0 : ( (v >= lutSize) ? (lutSize-1) : v);
|
|
line[i]=lut_used[vv];
|
|
if ((v<0)&&(paletteMinFail==JKQTPMathImageGivenColor)) {
|
|
line[i]=minFailColor.rgba();
|
|
} else if ((v>lutSize)&&(paletteMaxFail==JKQTPMathImageGivenColor)) {
|
|
line[i]=maxFailColor.rgba();
|
|
} else if ((v<0)&&(paletteMinFail==JKQTPMathImageTransparent)) {
|
|
line[i]=QColor(Qt::transparent).rgba();
|
|
} else if ((v>lutSize)&&(paletteMaxFail==JKQTPMathImageTransparent)) {
|
|
line[i]=QColor(Qt::transparent).rgba();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// no LUT found: paint a black image!
|
|
img.fill(0);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*! \brief convert a 2D image (as 1D array) into a QImage with given palette (see JKQTFPColorPalette)
|
|
|
|
\param dbl_in pointer to a 1D array of template type \c T representing the image to plot. This array has to be of size \a width * \a height
|
|
\param width width of the array in \a dbl
|
|
\param height height of the array in \a dbl
|
|
\param[out] img the QImage object to draw to (should be initialized as \c QImage::Format_ARGB32 )
|
|
\param lutUser user-defined lookup-table
|
|
\param minColor lower boundary of color range in \a dbl pixels, if \a minColor == \a maxColor then this function will extract the image min and image max.
|
|
\param maxColor upper boundary of color range in \a dbl pixels, if \a minColor == \a maxColor then this function will extract the image min and image max.
|
|
\param paletteMinFail specifies what shell happen, when a value in \a dbl is below \a minColor
|
|
\param paletteMaxFail specifies what shell happen, when a value in \a dbl is above \a maxColor
|
|
\param minFailColor color to use for pixels that are below \a minColor for some settings of \a paletteMinFail
|
|
\param maxFailColor color to use for pixels that are below \a maxColor for some settings of \a paletteMaxFail
|
|
\param nanColor color to use for pixels that are not-a-number
|
|
\param infColor color to use for pixels that are infinity
|
|
\param logScale create a log-scaled image
|
|
\param logBase base for the logarithm used when \c logScale==true
|
|
*/
|
|
template <class T>
|
|
static inline void array2image(const T* dbl_in, int width, int height, QImage &img, const LUTType& lutUser, double minColor, double maxColor, JKQTPMathImageColorRangeFailAction paletteMinFail=JKQTPMathImageLastPaletteColor, JKQTPMathImageColorRangeFailAction paletteMaxFail=JKQTPMathImageLastPaletteColor, QColor minFailColor=QColor("black"), QColor maxFailColor=QColor("black"), QColor nanColor=QColor("black"), QColor infColor=QColor("black"), bool logScale=false, double logBase=10.0)
|
|
{
|
|
array2image(dbl_in, width, height, img, JKQTPMathImageUSER_PALETTE, minColor, maxColor, paletteMinFail, paletteMaxFail, minFailColor, maxFailColor, nanColor, infColor, logScale, logBase, lutUser);
|
|
}
|
|
|
|
|
|
|
|
/** \brief return a list of all globally available LUTs, human-readable/localized form */
|
|
static QStringList JKQTCOMMON_LIB_EXPORT getPredefinedPalettes();
|
|
|
|
/** \brief return a list of all globally available LUTs, machine-readable form */
|
|
static QStringList JKQTCOMMON_LIB_EXPORT getPredefinedPalettesMachineReadable();
|
|
|
|
/*! \brief convert the palette \a p to a string
|
|
\see JKQTPImageTools::String2JKQTPMathImageColorPalette()
|
|
*/
|
|
static JKQTCOMMON_LIB_EXPORT QString JKQTPMathImageColorPalette2String(JKQTPMathImageColorPalette p);
|
|
|
|
/*! \brief convert the palette name \a p to JKQTPMathImageColorPalette (compatible with JKQTPImageTools::String2JKQTPMathImageColorPalette() )
|
|
\see JKQTPImageTools::JKQTPMathImageColorPalette2String()
|
|
*/
|
|
static JKQTCOMMON_LIB_EXPORT JKQTPMathImageColorPalette String2JKQTPMathImageColorPalette(const QString& p);
|
|
|
|
|
|
/** \brief generates a QImage with width \a width and height 1 for the i-th color palette (\a i is based on the list returned by JKQTPImagePlot_getPredefinedPalettes() ) */
|
|
static QImage JKQTCOMMON_LIB_EXPORT GetPaletteImage(int i, int width);
|
|
/** \brief generates a QImage with width \a width and height \a height for the i-th color palette (\a i is based on the list returned by JKQTPImagePlot_getPredefinedPalettes() ) */
|
|
static QImage JKQTCOMMON_LIB_EXPORT GetPaletteImage(int i, int width, int height);
|
|
/** \brief generates a QImage with width \a width and height 1 for a specific JKQTPMathImageColorPalette */
|
|
static QImage JKQTCOMMON_LIB_EXPORT GetPaletteImage(JKQTPMathImageColorPalette palette, int width);
|
|
/** \brief generates a QImage with width \a width and height \a height for a specific JKQTPMathImageColorPalette */
|
|
static QImage JKQTCOMMON_LIB_EXPORT GetPaletteImage(JKQTPMathImageColorPalette palette, int width, int height);
|
|
/** \brief generates a QImage with width \a width and height 1 for a lookup-table \a lut */
|
|
static QImage JKQTCOMMON_LIB_EXPORT GetPaletteImage(const LUTType& lut, int width);
|
|
|
|
/** \brief generates a QIcon for the i-th color palette (\a i is based on the list returned by JKQTPImagePlot_getPredefinedPalettes() ) */
|
|
static QIcon JKQTCOMMON_LIB_EXPORT GetPaletteIcon(int i) ;
|
|
|
|
|
|
/** \brief generates a QIcon for a specific JKQTPMathImageColorPalette */
|
|
static QIcon JKQTCOMMON_LIB_EXPORT GetPaletteIcon(JKQTPMathImageColorPalette palette) ;
|
|
|
|
private:
|
|
|
|
/*! \brief internal datatype, representing a lookup-table and its metadata inside global_jkqtpimagetools_lutstore
|
|
\internal
|
|
*/
|
|
struct LUTData {
|
|
LUTData();
|
|
LUTData(const LUTType& _lut, const QString& _name, const QString& _nameT);
|
|
LUTData(const QString& _name, const QString& _nameT);
|
|
/** \brief the LUT itself */
|
|
LUTType lut;
|
|
/** \brief name for the LUT (machine-readable) */
|
|
QString name;
|
|
/** \brief name for the LUT (localized, human-readable) */
|
|
QString nameT;
|
|
};
|
|
|
|
/*! \brief internal global storage object for lookup-tables
|
|
\internal
|
|
*/
|
|
static JKQTCOMMON_LIB_EXPORT QMap<int, LUTData > global_jkqtpimagetools_lutstore;
|
|
|
|
/*! \brief storage for the next ID to assign to a user-defined palette, registered with registerPalette() or registerPalettesFromFile()
|
|
\internal
|
|
|
|
\see registerPalette() registerPalettesFromFile()
|
|
*/
|
|
static JKQTCOMMON_LIB_EXPORT int global_next_userpalette;
|
|
|
|
/*! \brief returns data of the default LUTs, used to initialize global_jkqtpimagetools_lutstore
|
|
\internal
|
|
*/
|
|
static JKQTCOMMON_LIB_EXPORT QMap<int, LUTData > getDefaultLUTs();
|
|
|
|
|
|
/*! \brief create a LUT for a given JKQTPMathImageColorPalette, store it in \a lutstore and return it
|
|
\internal
|
|
*/
|
|
static JKQTCOMMON_LIB_EXPORT const LUTType& getLUTforPalette(QMap<int, LUTData > &lutcache, JKQTPMathImageColorPalette palette);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*! \brief modes available for RGB images
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
|
|
|
|
\see Examples: \ref JKQTPlotterRGBImagePlot
|
|
|
|
*/
|
|
enum JKQTPRGBMathImageRGBMode {
|
|
JKQTPRGBMathImageModeRGBMode=0, /*!< image channels are mapped to the R, G and B channel (red-green-blue) */
|
|
JKQTPRGBMathImageModeHSVMode=1, /*!< image channels are mapped to the H, S and V channel (hue-saturation-value) */
|
|
JKQTPRGBMathImageModeHSLMode=2, /*!< image channels are mapped to the H, S and L channel (bue-saturation-luminance) */
|
|
JKQTPRGBMathImageModeCMYMode=3 /*!< image channels are mapped to the C, M and Y channel (subtractive color model!!!) */
|
|
};
|
|
|
|
|
|
/*! \brief returns a vector containing all elements of the given array as doubles
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
|
|
*/
|
|
template <class T>
|
|
inline QVector<double> JKQTPImagePlot_arrayToDVector(const T* input, int N) {
|
|
if (!input || N<=0) return QVector<double>();
|
|
QVector<double> out(N, 0.0);
|
|
for (int i=0; i<N; i++) {
|
|
out[i]=input[i];
|
|
}
|
|
return out;
|
|
}
|
|
|
|
/*! \brief returns a vector containing all elements of the given boolean array as doubles (true=1, false=0)
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
|
|
*/
|
|
inline QVector<double> JKQTPImagePlot_BarrayToDVector(const bool* input, int N) {
|
|
if (!input || N<=0) return QVector<double>();
|
|
QVector<double> out(N, 0.0);
|
|
for (int i=0; i<N; i++) {
|
|
if (input[i]) out[i]=1.0;
|
|
}
|
|
return out;
|
|
}
|
|
|
|
/*! \brief fin the minimum pixel value in the given image \a dbl with width \a width and height \a height
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
|
|
*/
|
|
template <class T>
|
|
inline double JKQTPImagePlot_getImageMin(const T* dbl, int width, int height)
|
|
{
|
|
if (!dbl || width<=0 || height<=0)
|
|
return 0;
|
|
|
|
double min = 0;
|
|
double max = 0;
|
|
bool first=true;
|
|
for (int i=1; i<width*height; ++i)
|
|
{
|
|
T v=dbl[i];
|
|
if (!(std::isnan(static_cast<long double>(v)) || std::isinf(static_cast<long double>(v)))) {
|
|
if (first) {
|
|
min=max=v;
|
|
first=false;
|
|
} else {
|
|
if (v < min)
|
|
min = v;
|
|
else if (v > max)
|
|
max = v;
|
|
}
|
|
}
|
|
}
|
|
return min;
|
|
};
|
|
|
|
/*! \brief fin the maximum pixel value in the given image \a dbl with width \a width and height \a height
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
|
|
*/
|
|
template <class T>
|
|
inline double JKQTPImagePlot_getImageMax(const T* dbl, int width, int height)
|
|
{
|
|
if (!dbl || width<=0 || height<=0)
|
|
return 0;
|
|
|
|
double min = 0;
|
|
double max = 0;
|
|
bool first=true;
|
|
for (int i=1; i<width*height; ++i)
|
|
{
|
|
T v=dbl[i];
|
|
if (!(std::isnan(static_cast<long double>(v)) || std::isinf(static_cast<long double>(v)))) {
|
|
if (first) {
|
|
min=max=v;
|
|
first=false;
|
|
} else {
|
|
if (v < min)
|
|
min = v;
|
|
else if (v > max)
|
|
max = v;
|
|
}
|
|
}
|
|
}
|
|
return max;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*! \brief convert a 2D image (as 1D array) into a QImage and puts the image values into one color channel (set by \a channel).The other color channels are not changed! So a repeated call to this function for the SAME QImage will
|
|
result in a step-by-step buildup of an image.
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
|
|
\note All calls (except channel>=3, i.e. alpha) set alpha to 255. Only the call
|
|
with channel==3 (alpha) sets alpha to the desired value. Calls with channel==4 (saturation), channel==5 (value)
|
|
leave alpha as it is.
|
|
*/
|
|
template <class T>
|
|
inline void JKQTPImagePlot_array2RGBimage(const T* dbl_in, int width, int height, QImage &img, int channel, double minColor, double maxColor, JKQTPRGBMathImageRGBMode rgbMode=JKQTPRGBMathImageModeRGBMode, bool logScale=false, double logBase=10.0)
|
|
{
|
|
if (!dbl_in || width<=0 || height<=0)
|
|
return;
|
|
|
|
double min = *dbl_in;
|
|
double max = *dbl_in;
|
|
bool first=true;
|
|
if (jkqtp_approximatelyEqual(minColor, maxColor, JKQTP_DOUBLE_EPSILON)) {
|
|
for (int i=1; i<width*height; ++i)
|
|
{
|
|
T v=dbl_in[i];
|
|
if (std::isfinite(static_cast<long double>(v))) {
|
|
if (first) {
|
|
min=max=v;
|
|
first=false;
|
|
} else {
|
|
if (v < min)
|
|
min = v;
|
|
else if (v > max)
|
|
max = v;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
min = minColor;
|
|
max = maxColor;
|
|
}
|
|
|
|
|
|
const T* dbl=dbl_in;
|
|
QVector<T> dbllog;
|
|
if (logScale) {
|
|
double logB=log10(logBase);
|
|
dbllog.resize(static_cast<size_t>(width)*static_cast<size_t>(height));
|
|
//memcpy(dbl, dbl_in, width*height*sizeof(T));
|
|
for (int i=0; i<width*height; i++) {
|
|
dbllog[i]=log10(dbl_in[i])/logB;
|
|
}
|
|
min=log10(min)/logB;
|
|
max=log10(max)/logB;
|
|
dbl=dbllog.data();
|
|
}
|
|
double delta=max-min;
|
|
|
|
if (jkqtp_approximatelyUnequal(minColor, maxColor, JKQTP_DOUBLE_EPSILON)) {
|
|
if (rgbMode==JKQTPRGBMathImageModeRGBMode) {
|
|
//qDebug()<<"RGBMode";
|
|
if (channel==0) {
|
|
for (int j=0; j<height; ++j) {
|
|
QRgb* line=reinterpret_cast<QRgb *>(img.scanLine(height-1-j));
|
|
for (int i=0; i<width; ++i) {
|
|
int v = trunc(double(dbl[j*width+i]-min)*255.0/delta);
|
|
v = (v < 0) ? 0 : ( (v > 255) ? 255 : v);
|
|
const QRgb l=line[i];
|
|
//if (j==5) qDebug()<<"r: "<<v<<qGreen(l)<<qBlue(l)<<qAlpha(255);
|
|
line[i]=qRgb(v,qGreen(l),qBlue(l));
|
|
}
|
|
}
|
|
} else if (channel==1) {
|
|
for (int j=0; j<height; ++j) {
|
|
QRgb* line=reinterpret_cast<QRgb *>(img.scanLine(height-1-j));
|
|
for (int i=0; i<width; ++i) {
|
|
int v = (dbl[j*width+i]-min)*255/delta;
|
|
v = (v < 0) ? 0 : ( (v > 255) ? 255 : v);
|
|
const QRgb l=line[i];
|
|
//if (j==5) qDebug()<<"g: "<<qRed(l)<<v<<qBlue(l)<<qAlpha(255);
|
|
line[i]=qRgb(qRed(l),v,qBlue(l));
|
|
}
|
|
}
|
|
} else if (channel==2) {
|
|
for (int j=0; j<height; ++j) {
|
|
QRgb* line=reinterpret_cast<QRgb *>(img.scanLine(height-1-j));
|
|
for (int i=0; i<width; ++i) {
|
|
int v = (dbl[j*width+i]-min)*255/delta;
|
|
v = (v < 0) ? 0 : ( (v > 255) ? 255 : v);
|
|
const QRgb l=line[i];
|
|
//if (j==5) qDebug()<<"b: "<<qRed(l)<<qGreen(l)<<v<<qAlpha(255);
|
|
line[i]=qRgb(qRed(l),qGreen(l),v);
|
|
}
|
|
}
|
|
} else if (channel==3) {
|
|
for (int j=0; j<height; ++j) {
|
|
QRgb* line=reinterpret_cast<QRgb *>(img.scanLine(height-1-j));
|
|
for (int i=0; i<width; ++i) {
|
|
int v = (dbl[j*width+i]-min)*255/delta;
|
|
v = (v < 0) ? 0 : ( (v > 255) ? 255 : v);
|
|
const QRgb l=line[i];
|
|
//if (j==5) qDebug()<<"b: "<<qRed(l)<<qGreen(l)<<v<<qAlpha(255);
|
|
line[i]=qRgba(qRed(l),qGreen(l),qBlue(l), v);
|
|
}
|
|
}
|
|
}
|
|
} else if (rgbMode==JKQTPRGBMathImageModeCMYMode) {
|
|
//qDebug()<<"RGBMode";
|
|
if (channel==0) {
|
|
for (int j=0; j<height; ++j) {
|
|
QRgb* line=reinterpret_cast<QRgb *>(img.scanLine(height-1-j));
|
|
for (int i=0; i<width; ++i) {
|
|
int v = trunc(double(dbl[j*width+i]-min)*255.0/delta);
|
|
v = (v < 0) ? 0 : ( (v > 255) ? 255 : v);
|
|
const QRgb l=line[i];
|
|
//if (j==5) qDebug()<<"r: "<<v<<qGreen(l)<<qBlue(l)<<qAlpha(255);
|
|
line[i]=QColor::fromCmyk(v,QColor(l).magenta(),QColor(l).yellow(),QColor(l).black()).rgba();
|
|
}
|
|
}
|
|
} else if (channel==1) {
|
|
for (int j=0; j<height; ++j) {
|
|
QRgb* line=reinterpret_cast<QRgb *>(img.scanLine(height-1-j));
|
|
for (int i=0; i<width; ++i) {
|
|
int v = (dbl[j*width+i]-min)*255/delta;
|
|
v = (v < 0) ? 0 : ( (v > 255) ? 255 : v);
|
|
const QRgb l=line[i];
|
|
//if (j==5) qDebug()<<"g: "<<qRed(l)<<v<<qBlue(l)<<qAlpha(255);
|
|
line[i]=QColor::fromCmyk(QColor(l).cyan(),v,QColor(l).yellow(),QColor(l).black()).rgba();
|
|
}
|
|
}
|
|
} else if (channel==2) {
|
|
for (int j=0; j<height; ++j) {
|
|
QRgb* line=reinterpret_cast<QRgb *>(img.scanLine(height-1-j));
|
|
for (int i=0; i<width; ++i) {
|
|
int v = (dbl[j*width+i]-min)*255/delta;
|
|
v = (v < 0) ? 0 : ( (v > 255) ? 255 : v);
|
|
const QRgb l=line[i];
|
|
//if (j==5) qDebug()<<"b: "<<qRed(l)<<qGreen(l)<<v<<qAlpha(255);
|
|
line[i]=QColor::fromCmyk(QColor(l).cyan(),QColor(l).magenta(),v,QColor(l).black()).rgba();
|
|
}
|
|
}
|
|
}
|
|
} else if (rgbMode==JKQTPRGBMathImageModeHSVMode) {
|
|
if (channel==0) {
|
|
for (int j=0; j<height; ++j) {
|
|
QRgb* line=reinterpret_cast<QRgb *>(img.scanLine(height-1-j));
|
|
for (int i=0; i<width; ++i) {
|
|
int v = trunc(double(dbl[j*width+i]-min)*220.0/delta);
|
|
v = (v < 0) ? 0 : ( (v > 360) ? 360 : v);
|
|
QColor l=QColor::fromRgb(line[i]);
|
|
//if (i<10 && j==5) qDebug()<<"hi: "<<l.name()<<dbl[j*width+i]<<min<<max;
|
|
l.setHsv(v, l.saturation(), l.value());
|
|
//if (i<10 && j==5) qDebug()<<"ho: "<<l.name();
|
|
line[i]=l.rgb();
|
|
}
|
|
}
|
|
} else if (channel==1) {
|
|
for (int j=0; j<height; ++j) {
|
|
QRgb* line=reinterpret_cast<QRgb *>(img.scanLine(height-1-j));
|
|
for (int i=0; i<width; ++i) {
|
|
int v = (dbl[j*width+i]-min)*255/delta;
|
|
v = (v < 0) ? 0 : ( (v > 255) ? 255 : v);
|
|
QColor l=QColor::fromRgb(line[i]);
|
|
//if (i<10 && j==5) qDebug()<<"si: "<<l.name()<<dbl[j*width+i]<<min<<max;
|
|
l.setHsv(l.hue(), v, l.value());
|
|
//if (i<10 && j==5) qDebug()<<"so: "<<l.name();
|
|
line[i]=l.rgb();
|
|
}
|
|
}
|
|
} else if (channel==2) {
|
|
for (int j=0; j<height; ++j) {
|
|
QRgb* line=reinterpret_cast<QRgb *>(img.scanLine(height-1-j));
|
|
for (int i=0; i<width; ++i) {
|
|
int v = (dbl[j*width+i]-min)*255/delta;
|
|
v = (v < 0) ? 0 : ( (v > 255) ? 255 : v);
|
|
QColor l=QColor::fromRgb(line[i]);
|
|
//if (i<10 && j==5) qDebug()<<"vi: "<<l.name()<<dbl[j*width+i]<<min<<max;
|
|
l.setHsv(l.hue(), l.saturation(), v);
|
|
//if (i<10 && j==5) qDebug()<<"vo: "<<l.name();
|
|
line[i]=l.rgb();
|
|
}
|
|
}
|
|
|
|
}
|
|
} else if (rgbMode==JKQTPRGBMathImageModeHSLMode) {
|
|
if (channel==0) {
|
|
for (int j=0; j<height; ++j) {
|
|
QRgb* line=reinterpret_cast<QRgb *>(img.scanLine(height-1-j));
|
|
for (int i=0; i<width; ++i) {
|
|
int v = trunc(double(dbl[j*width+i]-min)*255.0/delta);
|
|
v = (v < 0) ? 0 : ( (v > 360) ? 360 : v);
|
|
QColor l=line[i];
|
|
l.setHsl(v, l.saturation(), l.lightness());
|
|
line[i]=l.rgb();
|
|
}
|
|
}
|
|
} else if (channel==1) {
|
|
for (int j=0; j<height; ++j) {
|
|
QRgb* line=reinterpret_cast<QRgb *>(img.scanLine(height-1-j));
|
|
for (int i=0; i<width; ++i) {
|
|
int v = (dbl[j*width+i]-min)*255/delta;
|
|
v = (v < 0) ? 0 : ( (v > 255) ? 255 : v);
|
|
QColor l=line[i];
|
|
l.setHsl(l.hue(), v, l.lightness());
|
|
line[i]=l.rgb();
|
|
}
|
|
}
|
|
} else if (channel==2) {
|
|
for (int j=0; j<height; ++j) {
|
|
QRgb* line=reinterpret_cast<QRgb *>(img.scanLine(height-1-j));
|
|
for (int i=0; i<width; ++i) {
|
|
int v = (dbl[j*width+i]-min)*255/delta;
|
|
v = (v < 0) ? 0 : ( (v > 255) ? 255 : v);
|
|
QColor l=line[i];
|
|
l.setHsl(l.hue(), l.saturation(), v);
|
|
line[i]=l.rgb();
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
if (channel==3) {
|
|
for (int j=0; j<height; ++j) {
|
|
QRgb* line=reinterpret_cast<QRgb *>(img.scanLine(height-1-j));
|
|
for (int i=0; i<width; ++i) {
|
|
int v = (dbl[j*width+i]-min)*255/delta;
|
|
v = (v < 0) ? 0 : ( (v > 255) ? 255 : v);
|
|
const QRgb l=line[i];
|
|
line[i]=qRgba(qRed(l),qGreen(l),qBlue(l),v);
|
|
}
|
|
}
|
|
} else if (channel==4) {
|
|
for (int j=0; j<height; ++j) {
|
|
QRgb* line=reinterpret_cast<QRgb *>(img.scanLine(height-1-j));
|
|
for (int i=0; i<width; ++i) {
|
|
int v = (dbl[j*width+i]-min)*255/delta;
|
|
v = (v < 0) ? 0 : ( (v > 255) ? 255 : v);
|
|
QColor c=QColor::fromRgba(line[i]);
|
|
c.setHsv(c.hue(), v, c.value(), c.alpha());
|
|
line[i]=c.rgba();
|
|
}
|
|
}
|
|
} else if (channel==5) {
|
|
for (int j=0; j<height; ++j) {
|
|
QRgb* line=reinterpret_cast<QRgb *>(img.scanLine(height-1-j));
|
|
for (int i=0; i<width; ++i) {
|
|
int v = (dbl[j*width+i]-min)*255/delta;
|
|
v = (v < 0) ? 0 : ( (v > 255) ? 255 : v);
|
|
QColor c=QColor::fromRgba(line[i]);
|
|
c.setHsv(c.hue(), c.saturation(), v, c.alpha());
|
|
line[i]=c.rgba();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*! \brief for building palettes from linear segments of single colors using JKQTPBuildColorPaletteLUTLinSegmentsSorted() and JKQTPBuildColorPaletteLUTLinSegments()
|
|
\ingroup jkqtplotter_imagelots_tools_LUTS
|
|
|
|
\see JKQTPBuildColorPaletteLUTLinSegmentsSorted() and JKQTPBuildColorPaletteLUTLinSegments(), \ref JKQTPlotterImagePlotUserPalette
|
|
|
|
*/
|
|
struct JKQTPColorPaletteSingleColorLinSegment {
|
|
JKQTPColorPaletteSingleColorLinSegment(double p, uint8_t y1, uint8_t y2);
|
|
static JKQTPColorPaletteSingleColorLinSegment makeDbl_0_1(double p, double y1, double y2);
|
|
JKQTPColorPaletteSingleColorLinSegment();
|
|
/** \brief scalar position of the element on the value axis */
|
|
double position;
|
|
/** \brief color-channel-value that ends the prevoius segment (ignored for the first entry in a table) */
|
|
uint8_t colval_endprevious;
|
|
/** \brief color-channel-value that starts the next segment (ignored for the last entry in a table) */
|
|
uint8_t colval_startnext;
|
|
};
|
|
|
|
/*! \brief build an interpolated palette with \a lut_size entries from the linear segments defined for the color channels R, G and B in \a itemsR, \a itemG and \a itemB respectively
|
|
\b NOTE: The entries in \a itemsR, \a itemsG, \a itemsB are assumed to be sorted by the position entry.
|
|
\ingroup jkqtplotter_imagelots_tools_LUTS
|
|
|
|
|
|
|
|
|
|
This is used to build a table of linear segments as a \c QList<JKQTPColorPaletteSingleColorLinSegment> :
|
|
\verbatim
|
|
i position colval1 colval2
|
|
~~~ ~~~~~~~~~~ ~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
|
|
0 0.0 0 (IGNORED) 0
|
|
1 0.5 100 100
|
|
2 0.8 255 255
|
|
3 1.0 255 255 (IGNORED)
|
|
\endverbatim
|
|
|
|
This will build a graph:
|
|
\verbatim
|
|
colval
|
|
^
|
|
|
|
|
250 - #**********#
|
|
| ***
|
|
200 - ***
|
|
| ***
|
|
150 - **
|
|
| **
|
|
100 - *****#
|
|
| ****
|
|
50 - *****
|
|
| *****
|
|
0 - #*****
|
|
|
|
|
---|----|----|----|----|----|----|----|----|----|----|--> position
|
|
0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
|
|
\endverbatim
|
|
|
|
You can also build graphs with a jump at a certain position
|
|
\verbatim
|
|
i position colval1 colval2
|
|
~~~ ~~~~~~~~~~ ~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
|
|
0 0.0 0 (IGNORED) 0
|
|
1 0.5 100 0
|
|
2 1.0 255 255 (IGNORED)
|
|
\endverbatim
|
|
|
|
This results in:
|
|
|
|
\verbatim
|
|
colval
|
|
^
|
|
|
|
|
250 - **#
|
|
| **
|
|
200 - **
|
|
| **
|
|
150 - ***
|
|
| **
|
|
100 - # **
|
|
| ****** **
|
|
50 - ****** **
|
|
| ****** **
|
|
0 - #****** #**
|
|
|
|
|
---|----|----|----|----|----|----|----|----|----|----|--> position
|
|
0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
|
|
\endverbatim
|
|
|
|
\see JKQTPBuildColorPaletteLUTLinSegments(), \ref JKQTPlotterImagePlotUserPalette , https://matplotlib.org/api/_as_gen/matplotlib.colors.LinearSegmentedColormap.html#matplotlib.colors.LinearSegmentedColormap
|
|
*/
|
|
JKQTPImageTools::LUTType JKQTCOMMON_LIB_EXPORT JKQTPBuildColorPaletteLUTLinSegmentsSorted(const QList<JKQTPColorPaletteSingleColorLinSegment>& itemsR, const QList<JKQTPColorPaletteSingleColorLinSegment>& itemsG, const QList<JKQTPColorPaletteSingleColorLinSegment>& itemsB, int lut_size=JKQTPImageTools::LUTSIZE);
|
|
|
|
|
|
|
|
/*! \brief build a linearly interpolated palette (as a look-up table) with \a lut_size entries by linearly interpolating between the nodes in \a items .
|
|
\b NOTE: \a items is assumed to be sorted by the first component of the \c QPair<double,QRgb> entries!
|
|
\ingroup jkqtplotter_imagelots_tools_LUTS
|
|
|
|
The LUT is built following these rules:
|
|
- the final LUT has \a lut_size entries
|
|
- the first color in the lut is given by \c items.first().second
|
|
- the last color in the lut is given by \c items.last().second
|
|
- in between the colors are interpolated between the nodes in \a items and the color-nodes are
|
|
distributed according to the first component of the \c QPair<double,QRgb> entries:<br>
|
|
\image html JKQTPBuildColorPaletteLUTLinInterpolateSorted.png
|
|
.
|
|
|
|
\see JKQTPBuildColorPaletteLUTLinInterpolate(), \ref JKQTPlotterImagePlotUserPalette
|
|
|
|
*/
|
|
JKQTPImageTools::LUTType JKQTCOMMON_LIB_EXPORT JKQTPBuildColorPaletteLUTLinInterpolateSorted(const QList<QPair<double, QRgb> >& items, int lut_size=JKQTPImageTools::LUTSIZE);
|
|
|
|
|
|
/*! \brief build a palette (as a look-up table) with \a lut_size entries that step between the nodes provided in \a items.
|
|
\b NOTE: \a items is assumed to be sorted by the first component of the \c QPair<double,QRgb> entries!
|
|
\ingroup jkqtplotter_imagelots_tools_LUTS
|
|
|
|
The LUT is built following these rules:
|
|
- the final LUT has \a lut_size entries
|
|
- the first color in the lut is given by \c items.first().second
|
|
- the last color in the lut is given by \c items.last().second
|
|
- in between the colors are stepped between the nodes in \a items and the color-nodes are
|
|
distributed according to the first component of the \c QPair<double,QRgb> entries:<br>
|
|
\image html JKQTPBuildColorPaletteLUTSorted.png
|
|
.
|
|
|
|
\see JKQTPBuildColorPaletteLUT(), \ref JKQTPlotterImagePlotUserPalette
|
|
|
|
*/
|
|
JKQTPImageTools::LUTType JKQTCOMMON_LIB_EXPORT JKQTPBuildColorPaletteLUTSorted(const QList<QPair<double, QRgb> >& items, int lut_size=JKQTPImageTools::LUTSIZE);
|
|
|
|
/*! \brief like JKQTPBuildColorPaletteLUTLinInterpolateSorted(), but sorts \a items before processing it!
|
|
\ingroup jkqtplotter_imagelots_tools_LUTS
|
|
|
|
\copydetails JKQTPBuildColorPaletteLUTLinInterpolateSorted()
|
|
*/
|
|
JKQTPImageTools::LUTType JKQTCOMMON_LIB_EXPORT JKQTPBuildColorPaletteLUTLinInterpolate(QList<QPair<double, QRgb> > items, int lut_size=JKQTPImageTools::LUTSIZE);
|
|
|
|
|
|
/*! \brief like JKQTPBuildColorPaletteLUTSorted(), but sorts \a items before processing it!
|
|
\ingroup jkqtplotter_imagelots_tools_LUTS
|
|
|
|
\copydetails JKQTPBuildColorPaletteLUTSorted()
|
|
*/
|
|
JKQTPImageTools::LUTType JKQTCOMMON_LIB_EXPORT JKQTPBuildColorPaletteLUT(QList<QPair<double, QRgb> > items, int lut_size=JKQTPImageTools::LUTSIZE);
|
|
|
|
/*! \brief like JKQTPBuildColorPaletteLUTLinSegmentsSorted(), but sorts \a itemsR, \a itemB, \a itemsG before processing them!
|
|
\ingroup jkqtplotter_imagelots_tools_LUTS
|
|
|
|
\copydetails JKQTPBuildColorPaletteLUTLinSegmentsSorted()
|
|
|
|
*/
|
|
JKQTPImageTools::LUTType JKQTCOMMON_LIB_EXPORT JKQTPBuildColorPaletteLUTLinSegments(QList<JKQTPColorPaletteSingleColorLinSegment> itemsR, QList<JKQTPColorPaletteSingleColorLinSegment> itemsG, QList<JKQTPColorPaletteSingleColorLinSegment> itemsB, int lut_size=JKQTPImageTools::LUTSIZE);
|
|
|
|
|
|
/*! \brief like JKQTPBuildColorPaletteLUTLinInterpolateSorted(), but accepts a \c QMap<double,QRgb> as parameter instead of \c QList<QPair<double,QRgb>>
|
|
\ingroup jkqtplotter_imagelots_tools_LUTS
|
|
|
|
\copydetails JKQTPBuildColorPaletteLUTLinInterpolateSorted()
|
|
|
|
*/
|
|
JKQTPImageTools::LUTType JKQTCOMMON_LIB_EXPORT JKQTPBuildColorPaletteLUTLinInterpolate(const QMap<double, QRgb>& items, int lut_size=JKQTPImageTools::LUTSIZE);
|
|
|
|
|
|
/*! \brief like JKQTPBuildColorPaletteLUTSorted(), but accepts a \c QMap<double,QRgb> as parameter instead of \c QList<QPair<double,QRgb>>
|
|
\ingroup jkqtplotter_imagelots_tools_LUTS
|
|
|
|
\copydetails JKQTPBuildColorPaletteLUTSorted()
|
|
*/
|
|
JKQTPImageTools::LUTType JKQTCOMMON_LIB_EXPORT JKQTPBuildColorPaletteLUT(const QMap<double, QRgb>& items, int lut_size=JKQTPImageTools::LUTSIZE);
|
|
|
|
|
|
|
|
/** \brief describes how to modify a rendered image with a second data array \see ModifierModeToString(), StringToModifierMode(), JKQTPImageModifierModeComboBox
|
|
\ingroup jkqtplotter_imagelots_tools*/
|
|
enum class JKQTPMathImageModifierMode {
|
|
ModifyNone=0, /*!< no modification \image html JKQTPMathImageBaseModifyNone.png */
|
|
ModifyValue=1, /*!< modify the VALUE-channel from the HSV color space \image html JKQTPMathImageBaseModifyValue.png */
|
|
ModifySaturation=2,/*!< modify the SATURATION-channel from the HSV color space \image html JKQTPMathImageBaseModifySaturation.png */
|
|
ModifyAlpha=3,/*!< modify the ALPHA/TRANSPARENCY-channel from the RGBA color space \image html JKQTPMathImageBaseModifyAlpha.png */
|
|
ModifyTransparency=ModifyAlpha,/*!< \see ModifyAlpha */
|
|
ModifyLuminance=4,/*!< modify the LUMINANCE-channel from the HSL color space \image html JKQTPMathImageBaseModifyLuminance.png */
|
|
ModifyHue=5,/*!< modify the HUE-channel from the HSV color space \image html JKQTPMathImageBaseModifyHue.png */
|
|
};
|
|
|
|
/** \brief convert a ModifierMode to a string
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
\see ModifierModeToString(), ModifierMode */
|
|
JKQTPMathImageModifierMode JKQTCOMMON_LIB_EXPORT StringToModifierMode(const QString& mode);
|
|
|
|
/** \brief convert a string to a ModifierMode
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
\see StringToModifierMode(), ModifierMode */
|
|
QString JKQTCOMMON_LIB_EXPORT ModifierModeToString(const JKQTPMathImageModifierMode& mode);
|
|
|
|
/** \brief modify the given image \a img, using modifier image \a dataModifier (of type \a datatypeModifier and size \a Nx * \a Ny), using values in the range \a internalModifierMin ... \a internalModifierMax )
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
*/
|
|
void JKQTCOMMON_LIB_EXPORT JKQTPModifyImage(QImage& img, JKQTPMathImageModifierMode modifierMode, const void* dataModifier, JKQTPMathImageDataType datatypeModifier, int Nx, int Ny, double internalModifierMin, double internalModifierMax);
|
|
|
|
|
|
|
|
|
|
|
|
#endif // JKQTPBASICIMAGETOOLS_H
|