mirror of
https://github.com/jkriege2/JKQtPlotter.git
synced 2024-11-15 18:15:52 +08:00
802 lines
36 KiB
C++
802 lines
36 KiB
C++
/*
|
|
Copyright (c) 2008-2019 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 "jkqtcommon/jkqtp_imexport.h"
|
|
#include <cmath>
|
|
#include <cfloat>
|
|
#include <stdint.h>
|
|
#include <QColor>
|
|
|
|
/*! \brief tool structure that summarizes several static properties
|
|
\ingroup jkqtptools_qt
|
|
\internal
|
|
*/
|
|
struct JKQTP_LIB_EXPORT JKQTPImageTools {
|
|
|
|
/*! \brief Width of the Palette-Icons, generated e.g. by JKQTPMathImageGetPaletteIcon()
|
|
\ingroup jkqtptools_qt */
|
|
static const int PALETTE_ICON_WIDTH;
|
|
/*! \brief Height of the Palette-Icons, generated e.g. by JKQTPMathImageGetPaletteIcon()
|
|
\ingroup jkqtptools_qt */
|
|
static const int PALETTE_IMAGEICON_HEIGHT;
|
|
|
|
/*! \brief size of the lookup tables used by JKQTFPimagePlot_array2image()
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
*/
|
|
static const int LUTSIZE;
|
|
};
|
|
|
|
|
|
/*! \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 */
|
|
JKQTPMathImageBLUEMAGENTAYELLOW, /*!< \image html palettes/palette_BlMaYe.png */
|
|
JKQTPMathImageINVERTED_BLUEMAGENTAYELLOW, /*!< \image html palettes/palette_YeMaBl.png */
|
|
JKQTPMathImageBLUEYELLOW, /*!< \image html palettes/palette_BlYe.png */
|
|
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 */
|
|
JKQTPMathImagePU_OR, /*!< \image html palettes/palette_PuOr.png */
|
|
JKQTPMathImageGN_BU, /*!< \image html palettes/palette_greenblue.png */
|
|
JKQTPMathImageBU_GN, /*!< \image html palettes/palette_bluegreen.png */
|
|
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 */
|
|
JKQTPMathImageYELLOWWHITE, /*!< \image html palettes/palette_yellowwhite.png */
|
|
JKQTPMathImageINVERTED_YELLOWWHITE, /*!< \image html palettes/palette_whiteyellow.png */
|
|
JKQTPMathImageMAGENTAWHITE, /*!< \image html palettes/palette_magentawhite.png */
|
|
JKQTPMathImageINVERTED_MAGENTAWHITE, /*!< \image html palettes/palette_whitemagenta.png */
|
|
JKQTPMathImageBlueGreenRed, /*!< \image html palettes/palette_bluegreenred.png */
|
|
JKQTPMathImageRedGreenBlue, /*!< \image html palettes/palette_redgreenblue.png */
|
|
|
|
JKQTPMathImagePREDEFINED_PALETTES_COUNT,
|
|
|
|
JKQTPMathImageUSER_PALETTE=65000,
|
|
|
|
JKQTPMathImageALPHA=JKQTPMathImageUSER_PALETTE-2,
|
|
JKQTPMathImageINVERTED_ALPHA=JKQTPMathImageUSER_PALETTE-1
|
|
};
|
|
|
|
|
|
|
|
|
|
/*! \brief convert the palette \a p to a string
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
\see String2JKQTPMathImageColorPalette()
|
|
*/
|
|
JKQTP_LIB_EXPORT QString JKQTPMathImageColorPalette2String(JKQTPMathImageColorPalette p);
|
|
|
|
/*! \brief convert the palette name \a p to JKQTPMathImageColorPalette (compatible with String2JKQTPMathImageColorPalette() )
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
\see JKQTPMathImageColorPalette2String()
|
|
*/
|
|
JKQTP_LIB_EXPORT JKQTPMathImageColorPalette String2JKQTPMathImageColorPalette(const QString& p);
|
|
|
|
|
|
|
|
/*! \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 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
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
|
|
*/
|
|
template <class T>
|
|
inline QVector<T> JKQTPImagePlot_arrayToVector(const T* input, int N) {
|
|
if (!input || N<=0) return QVector<double>();
|
|
T dummy;
|
|
QVector<T> out(N, dummy);
|
|
memcpy(out.data(), input, N*sizeof(T));
|
|
return out;
|
|
}
|
|
|
|
/*! \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(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(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(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 (minColor == maxColor) {
|
|
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;
|
|
}
|
|
|
|
|
|
T* dbl=dbl_in;
|
|
if (logScale) {
|
|
double logB=log10(logBase);
|
|
dbl=(T*)malloc(width*height*sizeof(T));
|
|
//memcpy(dbl, dbl_in, width*height*sizeof(T));
|
|
for (int i=0; i<width*height; i++) {
|
|
dbl[i]=log10(dbl_in[i])/logB;
|
|
}
|
|
min=log10(min)/logB;
|
|
max=log10(max)/logB;
|
|
}
|
|
double delta=max-min;
|
|
|
|
if (min != max) {
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (logScale) free(dbl);
|
|
}
|
|
|
|
|
|
/*! \brief Generate a QList with \a N entries of the value \a defaultValue
|
|
\ingroup jkqtptools_qt */
|
|
template <typename T>
|
|
inline QList<T> JKQTPImagePlot_makeQList(const T& defaultVal, int N=1) {
|
|
QList<T> l;
|
|
for (int i=0; i<N; i++) l<<defaultVal;
|
|
return l;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*! \brief build a linearly interpolated palette in \a lut with \a N entries that are provided in \a items
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
|
|
The entries in \a items are sorted by the first (double) argument and the full range is distributed
|
|
over 0 ... lut_size. Values in the LUT in between are generated by linear interpolations
|
|
|
|
\a lut needs to have \c lut_size) entries
|
|
*/
|
|
void JKQTP_LIB_EXPORT JKQTPImagePlot_buildDefinedPaletteLinInterpolate(int* lut, QList<QPair<double, QRgb> > items, int lut_size=JKQTPImageTools::LUTSIZE);
|
|
|
|
/*! \brief build a linearly interpolated palette in \a lut with \a N entries that are provided as (double, QRgb) value pairss in the variable arguments
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
|
|
The entries in \a items are sorted by the first (double) argument and the full range is distributed
|
|
over 0 ... lut_size. Values in the LUT in between are generated by linear interpolations
|
|
|
|
\a lut needs to have \c lut_size) entries
|
|
*/
|
|
void JKQTP_LIB_EXPORT JKQTPImagePlot_buildDefinedPaletteLinInterpolate(int* lut, int N, ...);
|
|
|
|
/*! \brief build a palette in \a lut with \a N entries that are provided in \a items
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
|
|
The entries in \a items are sorted by the first (double) argument and the full range is distributed
|
|
over 0 ... JKQTPImageTools::LUTSIZE.
|
|
|
|
\a lut needs to have \c JKQTPImageTools::LUTSIZE) entries
|
|
*/
|
|
void JKQTP_LIB_EXPORT JKQTPImagePlot_buildDefinedPalette(int* lut, QList<QPair<double, QRgb> > items);
|
|
|
|
/*! \brief build a palette in \a lut with \a N entries that are provided as as (double, QRgb) value pairss in the variable arguments
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
*/
|
|
void JKQTP_LIB_EXPORT JKQTPImagePlot_buildDefinedPalette(int* lut, int N, ...);
|
|
|
|
/*! \brief return a list of all globally available LUTs
|
|
\ingroup jkqtplotter_imagelots_tools */
|
|
QStringList JKQTP_LIB_EXPORT JKQTPImagePlot_getPredefinedPalettes();
|
|
|
|
|
|
|
|
/*! \brief create a LUT for a given JKQTPMathImageColorPalette, store it in \a lutstore and return it
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
\internal
|
|
*/
|
|
JKQTP_LIB_EXPORT int* JKQTPImagePlot_getCreateLUT(QList<int *> &lutstore, JKQTPMathImageColorPalette palette);
|
|
/*! \brief frees a list of LUTs
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
\internal
|
|
*/
|
|
void JKQTP_LIB_EXPORT JKQTPImagePlot_freeLUTs(QList<int *> &lutstore);
|
|
|
|
|
|
/*! \brief internal global storage object for lookup-tables
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
\internal
|
|
*/
|
|
extern JKQTP_LIB_EXPORT QList<int*> global_jkqtpimagetools_lutstore;
|
|
|
|
/*! \brief convert a 2D image (as 1D array) into a QImage with given palette (see JKQTFPColorPalette)
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
|
|
This method uses lookup tables which are saved as static variables to convert the 2D array into
|
|
an image. The luts are only created once, and stored then, so mor CPU time is saved. The precompiler define
|
|
JKQTPImageTools::LUTSIZE sets the size of the LUTs. Note that if you don't use a specific color palette,
|
|
the according LUT won't be calculated and stored!
|
|
|
|
\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
|
|
\param lutUserSize size of the LUT in lutUser
|
|
*/
|
|
template <class T>
|
|
inline void JKQTPImagePlot_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 int* lutUser=0, int lutUserSize=0)
|
|
{
|
|
if (!dbl_in || width<=0 || height<=0)
|
|
return;
|
|
|
|
double min = *dbl_in;
|
|
double max = *dbl_in;
|
|
if (minColor == maxColor) {
|
|
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;
|
|
T* dbl1=nullptr;
|
|
if (logScale) {
|
|
double logB=log10(logBase);
|
|
dbl1=(T*)malloc(width*height*sizeof(T));
|
|
//memcpy(dbl, dbl_in, width*height*sizeof(T));
|
|
for (int i=0; i<width*height; i++) {
|
|
dbl1[i]=log10(dbl_in[i])/logB;
|
|
}
|
|
dbl=dbl1;
|
|
min=log10(min)/logB;
|
|
max=log10(max)/logB;
|
|
}
|
|
double delta=max-min;
|
|
|
|
|
|
const int* lut_used=nullptr;
|
|
int lutSize=JKQTPImageTools::LUTSIZE;
|
|
if (global_jkqtpimagetools_lutstore.size()<=0) global_jkqtpimagetools_lutstore=JKQTPImagePlot_makeQList<int*>(nullptr, JKQTPImagePlot_getPredefinedPalettes().size()+2);
|
|
|
|
|
|
img = QImage(width, height, QImage::Format_ARGB32);
|
|
if (min == max)
|
|
img.fill(0);
|
|
else
|
|
{
|
|
|
|
if (palette==JKQTPMathImageUSER_PALETTE) {
|
|
lut_used=lutUser;
|
|
lutSize=lutUserSize;
|
|
//qDebug()<<"user palette "<<lutUser<<lutUserSize;
|
|
} else {
|
|
lut_used=JKQTPImagePlot_getCreateLUT(global_jkqtpimagetools_lutstore, palette);
|
|
}
|
|
|
|
|
|
if (lut_used!=nullptr && lutSize>0) {
|
|
const unsigned int* lut_usedui=reinterpret_cast<const unsigned int*>(lut_used);
|
|
// 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));
|
|
const int vv = (v < 0) ? 0 : ( (v > lutSize) ? (lutSize) : v);
|
|
line[i]=lut_usedui[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);
|
|
}
|
|
}
|
|
|
|
if (dbl1) free(dbl1);
|
|
|
|
};
|
|
|
|
/*! \brief convert a 2D image (as 1D array) into a QImage with given palette (see JKQTFPColorPalette)
|
|
\ingroup jkqtplotter_imagelots_tools
|
|
|
|
This method uses lookup tables which are saved as static variables to convert the 2D array into
|
|
an image. The luts are only created once, and stored then, so mor CPU time is saved. The precompiler define
|
|
JKQTPImageTools::LUTSIZE sets the size of the LUTs. Note that if you don't use a specific color palette,
|
|
the according LUT won't be calculated and stored!
|
|
|
|
\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 lutUserSize number of entries in \a lutUser
|
|
\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>
|
|
inline void JKQTPImagePlot_array2image(const T* dbl_in, int width, int height, QImage &img, const int* lutUser, int lutUserSize, 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)
|
|
{
|
|
JKQTPImagePlot_array2image(dbl_in, width, height, img, JKQTPMathImageUSER_PALETTE, minColor, maxColor, paletteMinFail, paletteMaxFail, minFailColor, maxFailColor, nanColor, infColor, logScale, logBase, lutUser, lutUserSize);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*! \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() )
|
|
\ingroup jkqtplotter_imagelots_tools */
|
|
QImage JKQTP_LIB_EXPORT JKQTPMathImageGetPaletteImage(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() )
|
|
\ingroup jkqtplotter_imagelots_tools */
|
|
QImage JKQTP_LIB_EXPORT JKQTPMathImageGetPaletteImage(int i, int width, int height);
|
|
/*! \brief generates a QImage with width \a width and height 1 for a specific JKQTPMathImageColorPalette
|
|
\ingroup jkqtplotter_imagelots_tools */
|
|
QImage JKQTP_LIB_EXPORT JKQTPMathImageGetPaletteImage(JKQTPMathImageColorPalette palette, int width);
|
|
/*! \brief generates a QImage with width \a width and height \a height for a specific JKQTPMathImageColorPalette
|
|
\ingroup jkqtplotter_imagelots_tools */
|
|
QImage JKQTP_LIB_EXPORT JKQTPMathImageGetPaletteImage(JKQTPMathImageColorPalette palette, int width, int height);
|
|
/*! \brief generates a QImage with width \a width and height 1 for a lookup-table \a lut with \a lut_size entries
|
|
\ingroup jkqtplotter_imagelots_tools */
|
|
QImage JKQTP_LIB_EXPORT JKQTPMathImageGetPaletteImage(int* lut, int lut_size, int width);
|
|
/*! \brief generates a QImage with width \a width and height \a height for a lookup-table \a lut with \a lut_size entries
|
|
\ingroup jkqtplotter_imagelots_tools */
|
|
QImage JKQTP_LIB_EXPORT JKQTPMathImageGetAlphaPaletteImage(int* lut, int lut_size, int width, int height);
|
|
|
|
/*! \brief generates a QIcon for the i-th color palette (\a i is based on the list returned by JKQTPImagePlot_getPredefinedPalettes() )
|
|
\ingroup jkqtplotter_imagelots_tools */
|
|
QIcon JKQTP_LIB_EXPORT JKQTPMathImageGetPaletteIcon(int i) ;
|
|
|
|
|
|
/*! \brief generates a QIcon for a specific JKQTPMathImageColorPalette
|
|
\ingroup jkqtplotter_imagelots_tools */
|
|
QIcon JKQTP_LIB_EXPORT JKQTPMathImageGetPaletteIcon(JKQTPMathImageColorPalette palette) ;
|
|
|
|
|
|
|
|
#endif // JKQTPBASICIMAGETOOLS_H
|