several improvements in build infrastructure + some tidying the code (made classes on data storeage non-virtual) + moved OpenCV interface to a separate header-only file

This commit is contained in:
Jan W. Krieger 2018-12-28 15:17:40 +01:00
parent e1ea8ee6bf
commit 9d43cd67cf
17 changed files with 832 additions and 690 deletions

View File

@ -1,7 +0,0 @@
TEMPLATE = subdirs
SUBDIRS += jkqtfastplotterlib \
jkqtfastplotter_test
jkqtfastplotterlib.file = $$PWD/lib/jkqtfastplotterlib.pro
jkqtfastplotter_test.file = $$PWD/test/jkqtfastplotter_test/jkqtfastplotter_test_and_lib.pro

View File

@ -4,7 +4,8 @@ SUBDIRS += jkqtplotterlib \
jkqtmathtext_simpletest \
jkqtplot_test \
jkqtplotter_simpletest \
test_multiplot
test_multiplot \
jkqtfastplotter_test
jkqtplotterlib.file = lib/jkqtplotterlib.pro
@ -24,6 +25,9 @@ jkqtplotter_simpletest.depends = jkqtplotterlib
test_multiplot.file = test/test_multiplot/test_multiplot.pro
test_multiplot.depends = jkqtplotterlib
jkqtfastplotter_test.file = $$PWD/test/jkqtfastplotter_test/jkqtfastplotter_test.pro
jkqtfastplotter_test.depends = jkqtplotterlib
defineTest(addSimpleTest) {
test_name = $$1
SUBDIRS += jkqtplotter_simpletest_$${test_name}

View File

@ -54,13 +54,6 @@ build_script:
- echo "Build..."
- call %MAKETOOL%
- cd ..
#### Fast Plotter ########
- mkdir build_fast_plotter
- cd build_fast_plotter
- echo "Call QMake (Fast Plotter)..."
- qmake.exe ..\JKQtFastPlotterBuildAllExamples.pro
- echo "Build (Fast Plotter)..."
- call %MAKETOOL%
artifacts:
- path: build\lib\release\*.a
@ -71,15 +64,7 @@ artifacts:
name: dll %QTVER%%QTABI%
- path: build\test\**\*.exe
name: Test %QTVER%%QTABI%
#### Fast Plotter ########
- path: build_fast_plotter\lib\release\*.a
name: (FP) lib %QTVER%%QTABI%
- path: build_fast_plotter\lib\release\*.lib
name: (FP) lib %QTVER%%QTABI%
- path: build_fast_plotter\lib\release\*.dll
name: (FP) dll %QTVER%%QTABI%
- path: build_fast_plotter\test\**\*.exe
name: (FP) Test %QTVER%%QTABI%
# # remote desktop connection on init
# init:

24
lib/README.md Normal file
View File

@ -0,0 +1,24 @@
# JKQtPlotter
## LIB subdirectory
This directory contains all files necessary to build a library with the JKQtPlotter and JKQtFastPlotter classes inside. There are several ways to add these to your program:
### QMake
#### simply include all necessary files
If you use QMake and simply want to include all necessary files into your project, include one of these `PRI`-files into your QMake Project:
- `jkqtplotter.pri` contains all files in this library, including `JKQtFastPlotter` and `JKQtMathText`
- `jkqtfastplotter.pri` contains only those files from this directory which are necessary to build `JKQtFastPlotter`
- `jkqtmathtext.pri` contains only those files from this directory which are necessary to build `JKQtMathText`
#### Build (static) libraries
There are also `.PRO`-files with the same names as the `.PRI`-files above, that can be used to build the full library, or a limited subset. They will produce a static link library that you can include into your projects, e.g. with the following QMake-snippet:
```qmake
# include JKQtPlotter library
DEPENDPATH += . <PATHTOJKQTPLOTTERDIR>/lib
INCLUDEPATH += <PATHTOJKQTPLOTTERDIR>/lib
CONFIG (debug, debug|release):LIBS += -L<PATHTOJKQTPLOTTERDIR>/lib/debug -ljkqtplotterlib
CONFIG (release):LIBS += -L<PATHTOJKQTPLOTTERDIR>/lib/release -ljkqtplotterlib
```
This snippet assumes that you built the libraries with the provided `.PRO`-files.

View File

@ -1,6 +1,6 @@
TARGET = jkqtfastplotterlib
TEMPLATE = lib
CONFIG+=staticlib dll
CONFIG+=staticlib
include(jkqtfastplotter.pri)

View File

@ -10,74 +10,78 @@
DEFINES += _CRT_NO_VA_START_VALIDATION
}
HEADERS += $$PWD/jkqtplotter/jkqtpbaseplotter.h \
$$PWD/jkqtplotter/jkqtpdatastorage.h \
$$PWD/jkqtplotter/jkqtpgraphsbase.h \
$$PWD/jkqtplotter/jkqtpgraphs.h \
HEADERS += \
$$PWD/jkqtfastplotter/jkqtfastplotter.h \
$$PWD/jkqtmathtext/jkqtmathtext.h \
$$PWD/jkqtplotter/jkqtpbaseelements.h \
$$PWD/jkqtplotter/jkqtplotter.h \
$$PWD/jkqtplottertools/jkqtptools.h \
$$PWD/jkqtplottertools/jkqttools.h \
$$PWD/jkqtplotter/jkqtpgraphsimage.h \
$$PWD/jkqtplottertools/jkqtpimagetools.h \
$$PWD/jkqtplotter/jkqtpbaseplotter.h \
$$PWD/jkqtplotter/jkqtpdatastorage.h \
$$PWD/jkqtplotter/jkqtpelementsoverlay.h \
$$PWD/jkqtplotter/jkqtpgraphs.h \
$$PWD/jkqtplotter/jkqtpgraphsbarchart.h \
$$PWD/jkqtplotter/jkqtpgraphsbase.h \
$$PWD/jkqtplotter/jkqtpgraphsboxplot.h \
$$PWD/jkqtplotter/jkqtpgraphsevaluatedfunction.h \
$$PWD/jkqtplotter/jkqtpgraphsfilledcurve.h \
$$PWD/jkqtplotter/jkqtpgraphsgeometric.h \
$$PWD/jkqtplotter/jkqtpgraphsimage.h \
$$PWD/jkqtplotter/jkqtpgraphsimpulses.h \
$$PWD/jkqtplotter/jkqtpgraphsparsedfunction.h \
$$PWD/jkqtplotter/jkqtpelementsoverlay.h \
$$PWD/jkqtplotter/jkqtpgraphsgeometric.h \
$$PWD/jkqtplotter/jkqtpgraphspeakstream.h \
$$PWD/jkqtplottertools/jkqtpmathparser.h \
$$PWD/jkqtplottertools/jkqtp_imexport.h \
$$PWD/jkqtplottergui/jkqtpgraphsmodel.h \
$$PWD/jkqtplotter/jkqtplotter.h \
$$PWD/jkqtplottergui/jkqtpcomboboxes.h \
$$PWD/jkqtplottergui/jkqtpenhancedtableview.h \
$$PWD/jkqtplottergui/jkqtpenhancedspinboxes.h \
$$PWD/jkqtplottergui/jkqtpenhancedtableview.h \
$$PWD/jkqtplottergui/jkqtpgraphsmodel.h \
$$PWD/jkqtplottergui/jkvanishqtoolbar.h \
$$PWD/jkqtmathtext/jkqtmathtext.h \
$$PWD/jkqtplottertools/jkqtp_imexport.h \
$$PWD/jkqtplottertools/jkqtpdrawingtools.h \
$$PWD/jkqtplottertools/jkqtpenhancedpainter.h \
$$PWD/jkqtplottertools/jkqtphighrestimer.h \
$$PWD/jkqtplottertools/jkqtpenhancedpainter.h
$$PWD/jkqtplottertools/jkqtpimagetools.h \
$$PWD/jkqtplottertools/jkqtpmathparser.h \
$$PWD/jkqtplottertools/jkqtptools.h \
$$PWD/jkqtplottertools/jkqttools.h
SOURCES += $$PWD/jkqtplotter/jkqtpbaseplotter.cpp \
$$PWD/jkqtplotter/jkqtpdatastorage.cpp \
$$PWD/jkqtplotter/jkqtpgraphsbase.cpp \
$$PWD/jkqtplotter/jkqtpgraphs.cpp \
SOURCES += \
$$PWD/jkqtfastplotter/jkqtfastplotter.cpp \
$$PWD/jkqtmathtext/jkqtmathtext.cpp \
$$PWD/jkqtplotter/jkqtpbaseelements.cpp \
$$PWD/jkqtplotter/jkqtplotter.cpp \
$$PWD/jkqtplottertools/jkqtptools.cpp \
$$PWD/jkqtplottertools/jkqttools.cpp \
$$PWD/jkqtplotter/jkqtpgraphsimage.cpp \
$$PWD/jkqtplottertools/jkqtpimagetools.cpp \
$$PWD/jkqtplotter/jkqtpbaseplotter.cpp \
$$PWD/jkqtplotter/jkqtpdatastorage.cpp \
$$PWD/jkqtplotter/jkqtpelementsoverlay.cpp \
$$PWD/jkqtplotter/jkqtpgraphs.cpp \
$$PWD/jkqtplotter/jkqtpgraphsbarchart.cpp \
$$PWD/jkqtplotter/jkqtpgraphsbase.cpp \
$$PWD/jkqtplotter/jkqtpgraphsboxplot.cpp \
$$PWD/jkqtplotter/jkqtpgraphsevaluatedfunction.cpp \
$$PWD/jkqtplotter/jkqtpgraphsfilledcurve.cpp \
$$PWD/jkqtplotter/jkqtpgraphsgeometric.cpp \
$$PWD/jkqtplotter/jkqtpgraphsimage.cpp \
$$PWD/jkqtplotter/jkqtpgraphsimpulses.cpp \
$$PWD/jkqtplotter/jkqtpgraphsparsedfunction.cpp \
$$PWD/jkqtplotter/jkqtpelementsoverlay.cpp \
$$PWD/jkqtplotter/jkqtpgraphsgeometric.cpp \
$$PWD/jkqtplotter/jkqtpgraphspeakstream.cpp \
$$PWD/jkqtplottertools/jkqtpmathparser.cpp \
$$PWD/jkqtplottergui/jkqtpgraphsmodel.cpp \
$$PWD/jkqtplotter/jkqtplotter.cpp \
$$PWD/jkqtplottergui/jkqtpcomboboxes.cpp \
$$PWD/jkqtplottergui/jkqtpenhancedtableview.cpp \
$$PWD/jkqtplottergui/jkqtpenhancedspinboxes.cpp \
$$PWD/jkqtplottergui/jkqtpenhancedtableview.cpp \
$$PWD/jkqtplottergui/jkqtpgraphsmodel.cpp \
$$PWD/jkqtplottergui/jkvanishqtoolbar.cpp \
$$PWD/jkqtmathtext/jkqtmathtext.cpp \
$$PWD/jkqtplottertools/jkqtpdrawingtools.cpp \
$$PWD/jkqtplottertools/jkqtpenhancedpainter.cpp \
$$PWD/jkqtplottertools/jkqtphighrestimer.cpp \
$$PWD/jkqtplottertools/jkqtpenhancedpainter.cpp
$$PWD/jkqtplottertools/jkqtpimagetools.cpp \
$$PWD/jkqtplottertools/jkqtpmathparser.cpp \
$$PWD/jkqtplottertools/jkqtptools.cpp \
$$PWD/jkqtplottertools/jkqttools.cpp
RESOURCES += $$PWD/jkqtplotterressources/jkqtpbaseplotter.qrc
INCLUDEPATH += $$PWD
QT += core gui xml svg
QT += core gui xml svg opengl
#win32:LIBS += -lgdi32
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport

View File

@ -42,6 +42,7 @@ JKQTPcolumn::JKQTPcolumn()
valid=false;
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPcolumn::JKQTPcolumn(JKQTPdatastore *datastore, const QString &name, size_t datastoreItem, size_t datastoreOffset)
{
this->datastore=datastore;
@ -52,11 +53,13 @@ JKQTPcolumn::JKQTPcolumn(JKQTPdatastore *datastore, const QString &name, size_t
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPcolumn::~JKQTPcolumn()
{
}
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPcolumn::getRows() const {
if (!valid || !datastore) return 0;
JKQTPdatastoreItem* i=datastore->getItem(datastoreItem);
@ -67,11 +70,11 @@ size_t JKQTPcolumn::getRows() const {
////////////////////////////////////////////////////////////////////////////////////////////////
void JKQTPcolumn::copyData(QVector<double> &copyTo) const
{
double* d=getPointer(0);
const double* d=getPointer(0);
copyTo.clear();
size_t i, cnt=getRows();
if (cnt>0) {
copyTo.resize(cnt);
copyTo.resize(static_cast<int>(cnt));
for (i=0; i<cnt; i++) {
copyTo[i]=d[i];
}
@ -88,7 +91,15 @@ QVector<double> JKQTPcolumn::copyData()
////////////////////////////////////////////////////////////////////////////////////////////////
double *JKQTPcolumn::getPointer(size_t n) const
const double *JKQTPcolumn::getPointer(size_t n) const
{
if (!datastore) return nullptr;
if (!datastore->getItem(datastoreItem)) return nullptr;
return datastore->getItem(datastoreItem)->getPointer(datastoreOffset, n);
}
////////////////////////////////////////////////////////////////////////////////////////////////
double *JKQTPcolumn::getPointer(size_t n)
{
if (!datastore) return nullptr;
if (!datastore->getItem(datastoreItem)) return nullptr;
@ -257,6 +268,7 @@ JKQTPdatastore::JKQTPdatastore()
clear();
}
////////////////////////////////////////////////////////////////////////////////////////////////
void JKQTPdatastore::clear(){
maxItemID=0;
maxColumnsID=0;
@ -274,6 +286,7 @@ void JKQTPdatastore::clear(){
columns.clear();
}
////////////////////////////////////////////////////////////////////////////////////////////////
void JKQTPdatastore::deleteAllColumns(const QString& name, bool removeItems) {
QList<size_t> ids;
QMapIterator<size_t, JKQTPcolumn> it(columns);
@ -288,6 +301,7 @@ void JKQTPdatastore::deleteAllColumns(const QString& name, bool removeItems) {
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
void JKQTPdatastore::deleteAllPrefixedColumns(QString prefix, bool removeItems) {
QList<size_t> ids;
QMapIterator<size_t, JKQTPcolumn> it(columns);
@ -303,6 +317,7 @@ void JKQTPdatastore::deleteAllPrefixedColumns(QString prefix, bool removeItems)
}
////////////////////////////////////////////////////////////////////////////////////////////////
void JKQTPdatastore::deleteColumn(size_t column, bool removeItems) {
if (removeItems) {
size_t dsitem=columns[column].get_datastoreItem();
@ -322,6 +337,7 @@ void JKQTPdatastore::deleteColumn(size_t column, bool removeItems) {
columns.remove(column);
}
////////////////////////////////////////////////////////////////////////////////////////////////
int JKQTPdatastore::getColumnNum(const QString& name) {
if (columns.size()<=0) return -1;
QMapIterator<size_t, JKQTPcolumn> it(columns);
@ -332,6 +348,7 @@ int JKQTPdatastore::getColumnNum(const QString& name) {
return -1;
}
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPdatastore::ensureColumnNum(const QString& name) {
if (columns.size()<=0) return -1;
QMapIterator<size_t, JKQTPcolumn> it(columns);
@ -342,16 +359,19 @@ size_t JKQTPdatastore::ensureColumnNum(const QString& name) {
return addColumn(0, name);
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPcolumn JKQTPdatastore::getColumn(size_t i) const
{
return columns.value(i);
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPcolumn JKQTPdatastore::getColumn(int i) const
{
return columns.value(i);
}
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPdatastore::addCopiedItem(JKQTPdatastoreItemFormat dataformat, double* data, size_t columnsnum, size_t rows) {
JKQTPdatastoreItem* it=nullptr;
if ((dataformat==JKQTPsingleColumn)||(columnsnum==1)) {
@ -378,14 +398,14 @@ size_t JKQTPdatastore::addCopiedItem(JKQTPdatastoreItemFormat dataformat, double
/** \brief add a new columns/item with \a rows rows to the datastore and return its ID. The item uses internal memory management. */
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPdatastore::addItem(size_t rows) {
/*items.push_back(new JKQTPdatastoreItem(1, rows));
return items.size()-1;*/
return addItem(new JKQTPdatastoreItem(1, rows));
};
/** \brief add a new item with \a rows rows and \a columns columns to the datastore and return its ID. The item uses internal memory management. */
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPdatastore::addItem(size_t columnsnum, size_t rows) {
/*items.push_back(new JKQTPdatastoreItem(columnsnum, rows));
return items.size()-1;*/
@ -399,20 +419,21 @@ size_t JKQTPdatastore::addItem(double* data, size_t rows) {
return addItem(new JKQTPdatastoreItem(JKQTPsingleColumn, data, 1, rows));
}
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPdatastore::addInternalItem(double *data, size_t rows)
{
JKQTPdatastoreItem* dsi=new JKQTPdatastoreItem(JKQTPsingleColumn, data, 1, rows, true);
return addItem(dsi);
};
/** \brief add an external memory block to the datastore. It contains \a rows rows and \a columns columns. \a dataformat determined the memory layout*/
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPdatastore::addItem(JKQTPdatastoreItemFormat dataformat, double* data, size_t columnsnum, size_t rows) {
/*items.push_back(new JKQTPdatastoreItem(dataformat, data, columnsnum, rows));
return items.size()-1;*/
return addItem(new JKQTPdatastoreItem(dataformat, data, columnsnum, rows));
};
/** \brief add one external array to the datastore. It contains \a rows rows. The data is copied and the copy managed internally */
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPdatastore::addCopiedItem(const double* data, size_t rows) {
JKQTPdatastoreItem* it=new JKQTPdatastoreItem(1, rows);
if (data) {
@ -426,7 +447,7 @@ size_t JKQTPdatastore::addCopiedItem(const double* data, size_t rows) {
return addItem(it);
};
/** \brief add a new columns which references a specified item and a specified column therein. */
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPdatastore::addColumnForItem(size_t itemID, size_t columnInItem, const QString& name) {
/*JKQTPcolumn c(this, name, itemID, columnInItem);
columns.push_back(c);
@ -434,7 +455,7 @@ size_t JKQTPdatastore::addColumnForItem(size_t itemID, size_t columnInItem, cons
return addColumn(JKQTPcolumn(this, name, itemID, columnInItem));
};
/** \brief add a new columns with \a rows rows to the datastore and return its column ID. The new item uses internal memory management. */
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPdatastore::addColumn(size_t rows, const QString& name) {
//items.push_back(new JKQTPdatastoreItem(1, rows));
//return addColumnForItem(items.size()-1, 0, name);
@ -442,7 +463,7 @@ size_t JKQTPdatastore::addColumn(size_t rows, const QString& name) {
return addColumnForItem(item, 0, name);
};
/** \brief add one external column to the datastore. It contains \a rows rows. This returns its logical column ID.*/
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPdatastore::addColumn(double* data, size_t rows, const QString& name) {
//items.push_back(new JKQTPdatastoreItem(JKQTPsingleColumn, data, 1, rows));
//std::cout<<"added item\n";
@ -451,7 +472,8 @@ size_t JKQTPdatastore::addColumn(double* data, size_t rows, const QString& name)
size_t it=addItem(new JKQTPdatastoreItem(JKQTPsingleColumn, data, 1, rows));
return addColumnForItem(it, 0, name);
};
/** \brief add one external column to the datastore. It contains \a rows rows. This returns its logical column ID.*/
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPdatastore::addInternalColumn(double* data, size_t rows, const QString& name) {
//items.push_back(new JKQTPdatastoreItem(JKQTPsingleColumn, data, 1, rows));
//std::cout<<"added item\n";
@ -469,6 +491,7 @@ size_t JKQTPdatastore::addInternalColumn(double* data, size_t rows, const QStrin
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPdatastore::copyColumn(size_t old_column, size_t start, size_t stride, const QString& name)
{
JKQTPcolumn old=columns[old_column];
@ -486,49 +509,14 @@ size_t JKQTPdatastore::copyColumn(size_t old_column, size_t start, size_t stride
return n;
}
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPdatastore::copyColumn(size_t old_column, const QString& name)
{
return copyColumn(old_column, 0, 1, name);
}
#ifdef JKQTPLOTTER_OPENCV_INTERFACE
namespace JKQTPdatastore_Helper {
template <typename TPixel>
void copyDataFromMat(double* data, const cv::Mat& mat, int channel) {
size_t r=0;
const int channels=mat.channels();
for (int iy=0; iy<mat.rows; iy++ ) {
const TPixel* row=mat.ptr<TPixel>(iy);
for (int ix=0; ix<mat.cols; ix++ ) {
data[r]=jkqtp_todouble(*static_cast<const TPixel*>(&(row[ix*channels+channel])));
r++;
}
}
}
}
size_t JKQTPdatastore::copyCvMatToColumn(const cv::Mat& mat, const QString &name, int channel)
{
const size_t N=static_cast<size_t>(mat.cols*mat.rows);
double* d=static_cast<double*>(malloc(static_cast<size_t>(N)*sizeof(double)));
if (CV_MAT_DEPTH(mat.type())==CV_64F) JKQTPdatastore_Helper::copyDataFromMat<double>(d, mat, channel);
else if (CV_MAT_DEPTH(mat.type())==CV_32F) JKQTPdatastore_Helper::copyDataFromMat<float>(d, mat, channel);
else if (CV_MAT_DEPTH(mat.type())==CV_32S) JKQTPdatastore_Helper::copyDataFromMat<uint32_t>(d, mat, channel);
else if (CV_MAT_DEPTH(mat.type())==CV_16S) JKQTPdatastore_Helper::copyDataFromMat<int16_t>(d, mat, channel);
else if (CV_MAT_DEPTH(mat.type())==CV_16U) JKQTPdatastore_Helper::copyDataFromMat<uint16_t>(d, mat, channel);
else if (CV_MAT_DEPTH(mat.type())==CV_8S) JKQTPdatastore_Helper::copyDataFromMat<int8_t>(d, mat, channel);
else if (CV_MAT_DEPTH(mat.type())==CV_8U) JKQTPdatastore_Helper::copyDataFromMat<uint8_t>(d, mat, channel);
else throw std::runtime_error("datatype of cv::Mat not supported by JKQTPdatastore::copyImageToColumn()");
size_t itemid=addInternalItem(d, N);
return addColumnForItem(itemid, 0, name);
}
#endif
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPdatastore::addLinearColumn(size_t rows, double start, double end, const QString& name) {
double delta=(end-start)/(double)(rows-1);
JKQTPdatastoreItem* it=new JKQTPdatastoreItem(1, rows);
@ -543,6 +531,7 @@ size_t JKQTPdatastore::addLinearColumn(size_t rows, double start, double end, co
}
////////////////////////////////////////////////////////////////////////////////////////////////
int JKQTPdatastore::getNextLowerIndex(size_t column, size_t row, int start, int end) const
{
const JKQTPcolumn& col=columns[column];
@ -570,11 +559,13 @@ int JKQTPdatastore::getNextLowerIndex(size_t column, size_t row, int start, int
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
int JKQTPdatastore::getNextLowerIndex(size_t column, size_t row) const
{
return getNextLowerIndex(column, row, 0, columns[column].getRows()-1);
}
////////////////////////////////////////////////////////////////////////////////////////////////
int JKQTPdatastore::getNextHigherIndex(size_t column, size_t row, int start, int end) const
{
const JKQTPcolumn& col=columns[column];
@ -599,19 +590,23 @@ int JKQTPdatastore::getNextHigherIndex(size_t column, size_t row, int start, int
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
int JKQTPdatastore::getNextHigherIndex(size_t column, size_t row) const
{
return getNextHigherIndex(column, row, 0, columns[column].getRows()-1);
}
////////////////////////////////////////////////////////////////////////////////////////////////
int JKQTPdatastore::getNextLowerIndex(int column, size_t row, int start, int end) const {
return getNextLowerIndex(static_cast<size_t>(column), row, start, end);
}
////////////////////////////////////////////////////////////////////////////////////////////////
int JKQTPdatastore::getNextLowerIndex(int column, size_t row) const {
return getNextLowerIndex(static_cast<size_t>(column), row);
}
////////////////////////////////////////////////////////////////////////////////////////////////
int JKQTPdatastore::getNextHigherIndex(int column, size_t row, int start, int end) const {
return getNextHigherIndex(static_cast<size_t>(column), row, start, end);
}
@ -619,6 +614,7 @@ int JKQTPdatastore::getNextHigherIndex(int column, size_t row, int start, int en
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPdatastore::getMaxRows() {
size_t res=0;
/*for (size_t i=0; i<columns.size(); i++) {
@ -635,6 +631,7 @@ size_t JKQTPdatastore::getMaxRows() {
return res;
}
////////////////////////////////////////////////////////////////////////////////////////////////
void JKQTPdatastore::saveCSV(QString filename, QSet<int> userColumns, QString separator, QString decimal_separator, QString comment, QString aroundStrings, char floatformat) {
//std::cout<<filename<<"\n";
@ -649,6 +646,7 @@ void JKQTPdatastore::saveCSV(QString filename, QSet<int> userColumns, QString se
f.close();
}
////////////////////////////////////////////////////////////////////////////////////////////////
void JKQTPdatastore::saveMatlab(QString filename, QSet<int> userColumns) {
//std::cout<<filename<<"\n";
@ -663,6 +661,7 @@ void JKQTPdatastore::saveMatlab(QString filename, QSet<int> userColumns) {
f.close();
}
////////////////////////////////////////////////////////////////////////////////////////////////
QStringList JKQTPdatastore::getColumnNames() const {
QStringList names;
QMapIterator<size_t, JKQTPcolumn> it(columns);
@ -675,6 +674,7 @@ QStringList JKQTPdatastore::getColumnNames() const {
return names;
}
////////////////////////////////////////////////////////////////////////////////////////////////
void JKQTPdatastore::saveMatlab(QTextStream &txt, QSet<int> userColumns) {
//std::cout<<filename<<"\n";
@ -731,6 +731,7 @@ void JKQTPdatastore::saveMatlab(QTextStream &txt, QSet<int> userColumns) {
}
////////////////////////////////////////////////////////////////////////////////////////////////
void JKQTPdatastore::saveCSV(QTextStream& txt, QSet<int> userColumns, QString separator, QString decimal_separator, QString comment, QString aroundStrings, char floatformat) {
//std::cout<<filename<<"\n";
@ -782,6 +783,7 @@ void JKQTPdatastore::saveCSV(QTextStream& txt, QSet<int> userColumns, QString se
}
////////////////////////////////////////////////////////////////////////////////////////////////
void JKQTPdatastore::saveSYLK(QString filename, QSet<int> userColumns, QString floatformat) {
Q_UNUSED(floatformat)
// find out the decimal and the thousand separator
@ -833,6 +835,7 @@ void JKQTPdatastore::saveSYLK(QString filename, QSet<int> userColumns, QString f
}
////////////////////////////////////////////////////////////////////////////////////////////////
QList<QVector<double> > JKQTPdatastore::getData(QStringList *columnNames, QSet<int> userColumns)
{
QStringList cl;
@ -863,6 +866,7 @@ QList<QVector<double> > JKQTPdatastore::getData(QStringList *columnNames, QSet<i
}
////////////////////////////////////////////////////////////////////////////////////////////////
void JKQTPdatastore::saveDIF(QString filename, QSet<int> userColumns, QString floatformat) {
Q_UNUSED(floatformat)
// find out the decimal and the thousand separator
@ -921,6 +925,7 @@ void JKQTPdatastore::saveDIF(QString filename, QSet<int> userColumns, QString fl
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPdatastoreModel::JKQTPdatastoreModel(JKQTPdatastore *datastore, QObject *parent):
QAbstractTableModel(parent)
{
@ -928,28 +933,32 @@ JKQTPdatastoreModel::JKQTPdatastoreModel(JKQTPdatastore *datastore, QObject *par
reloadModel();
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPdatastoreModel::~JKQTPdatastoreModel()
{
}
////////////////////////////////////////////////////////////////////////////////////////////////
QVariant JKQTPdatastoreModel::data(const QModelIndex &index, int role) const {
int row=index.row();
int column=index.column();
if (datastore) {
if (role==Qt::DisplayRole || role==Qt::EditRole) {
int col=datastore->getColumnIDs().value(column, -1);
if (col>-1 && row>=0 && row<(int64_t)datastore->getColumn(col).getRows()) {
return datastore->get(col, row);
int col=static_cast<int>(datastore->getColumnIDs().value(column, -1));
if (col>-1 && row>=0 && row<static_cast<int>(datastore->getColumn(col).getRows())) {
return datastore->get(col, static_cast<size_t>(row));
}
}
}
return QVariant();
}
////////////////////////////////////////////////////////////////////////////////////////////////
Qt::ItemFlags JKQTPdatastoreModel::flags(const QModelIndex &/*index*/) const {
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
////////////////////////////////////////////////////////////////////////////////////////////////
QVariant JKQTPdatastoreModel::headerData(int section, Qt::Orientation orientation, int role) const {
if (datastore) {
if (role==Qt::DisplayRole) {
@ -966,20 +975,23 @@ QVariant JKQTPdatastoreModel::headerData(int section, Qt::Orientation orientatio
return QVariant();
}
////////////////////////////////////////////////////////////////////////////////////////////////
int JKQTPdatastoreModel::rowCount(const QModelIndex &/*parent*/) const {
if (datastore) {
return datastore->getMaxRows();
return static_cast<int>(datastore->getMaxRows());
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////
int JKQTPdatastoreModel::columnCount(const QModelIndex &/*parent*/) const {
if (datastore) {
return datastore->getColumnCount();
return static_cast<int>(datastore->getColumnCount());
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////
void JKQTPdatastoreModel::reloadModel()
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
@ -990,6 +1002,7 @@ void JKQTPdatastoreModel::reloadModel()
#endif
}
////////////////////////////////////////////////////////////////////////////////////////////////
int JKQTPdatastore::getNextHigherIndex(int column, size_t row) const {
return getNextHigherIndex(static_cast<size_t>(column), row);
}

View File

@ -279,19 +279,7 @@ class LIB_EXPORT JKQTPdatastore{
size_t itemid=addInternalItem(d, N);
return addColumnForItem(itemid, 0, name);
}
#ifdef JKQTPLOTTER_OPENCV_INTERFACE
/** \brief add one external column to the datastore. It will be filled with the contents of vector \a data.
*
* \tparam TContainer datatype of the container, which need to support standard C++ iterators and the function \c size(). The contents needs to be convertible to double.
* \param mat OpenCV-marix to store here
* \param name name for the column
* \param channel to copy from \a mat
* \return the ID of the newly created column
*
* \note You need to define the Macro JKQTPLOTTER_OPENCV_INTERFACE when compiling this lib to enabled this function.
*/
size_t copyCvMatToColumn(const cv::Mat& mat, const QString& name=QString(""), int channel=0);
#endif
/** \brief add one external column to the datastore. It will be filled with the contents of vector \a data.
*
@ -633,7 +621,8 @@ class LIB_EXPORT JKQTPcolumn {
bool valid;
protected:
JKQTPGET_MACRO(JKQTPdatastore*, datastore)
inline JKQTPdatastore* get_datastore() { return datastore; }
inline const JKQTPdatastore* get_datastore() const { return datastore; }
public:
JKQTPcolumn();
/** \brief class constructor that binds the column to a specific datastore object.
@ -648,7 +637,16 @@ class LIB_EXPORT JKQTPcolumn {
/** \brief class destructor */
~JKQTPcolumn() ;
JKQTPGET_SET_MACRO(QString, name)
/** \brief sets the property name to the specified \a __value. \details Description of the parameter name is: <CENTER>\copybrief name.</CENTER> \see name for more information */
inline void set_name (const QString& __value)
{
this->name = __value;
}
/** \brief returns the property name. \see name for more information */
inline QString get_name () const
{
return this->name;
}
/** \brief returns the number of rows in this column (accesses the datastore) */
size_t getRows() const;
@ -670,9 +668,10 @@ class LIB_EXPORT JKQTPcolumn {
* column.
*/
inline double getValue(int n) const;
/** \brief gets a pointer to the n-th value in the column
*/
double* getPointer(size_t n=0) const ;
/** \brief gets a pointer to the n-th value in the column */
double* getPointer(size_t n=0) ;
/** \brief gets a pointer to the n-th value in the column */
const double* getPointer(size_t n=0) const;
/** \brief sets the \a n'th value from the column
*
@ -724,8 +723,13 @@ class LIB_EXPORT JKQTPcolumn {
/** \brief set all values in the column to a specific \a value */
void setAll(double value);
JKQTPGET_MACRO(size_t, datastoreItem)
JKQTPGET_MACRO(size_t, datastoreOffset)
/** \brief returns the property datastoreItem. \details Description of the parameter datastoreItem is: <CENTER>\copybrief datastoreItem.</CENTER>. \see datastoreItem for more information */ \
inline size_t get_datastoreItem() const \
{ return this->datastoreItem; }
/** \brief returns the property datastoreOffset. \details Description of the parameter datastoreOffset is: <CENTER>\copybrief datastoreOffset.</CENTER>. \see datastoreOffset for more information */ \
inline size_t get_datastoreOffset() const \
{ return this->datastoreOffset; }
};
@ -780,8 +784,12 @@ class LIB_EXPORT JKQTPdatastoreItem {
/** \brief change the size of all columns to the givne number of rows. The data will be lost */
void resizeColumns(size_t rows);
JKQTPGET_MACRO(size_t, rows)
JKQTPGET_MACRO(size_t, columns)
/** \brief returns the property rows. \details Description of the parameter rows is: <CENTER>\copybrief rows.</CENTER>. \see rows for more information */ \
inline size_t get_rows() const
{ return rows; }
/** \brief returns the property columns. \details Description of the parameter columns is: <CENTER>\copybrief columns.</CENTER>. \see columns for more information */ \
inline size_t get_columns() const
{ return columns; }
/** \brief returns the data at the position (\a column, \a row ). The column index specifies the column inside THIS item, not the global column number. */
@ -810,6 +818,19 @@ class LIB_EXPORT JKQTPdatastoreItem {
}
return nullptr;
}
/** \brief returns the data at the position (\a column, \a row ). The column index specifies the column inside THIS item, not the global column number. */
inline const double* getPointer(size_t column, size_t row) const {
if (data!=nullptr) switch(dataformat) {
case JKQTPsingleColumn:
return &(data[row]);
case JKQTPmatrixColumn:
return &(data[column*rows+row]);
case JKQTPmatrixRow:
return &(data[row*columns+column]);
}
return nullptr;
}
/** \brief set the data at the position (\a column, \a row ) to \a value. The column index specifies the column inside THIS item, not the global column number. */
inline void set(size_t column, size_t row, double value) {
if (data!=nullptr) switch(dataformat) {

View File

@ -0,0 +1,93 @@
/*
Copyright (c) 2018 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 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/>.
*/
/**
* \defgroup jkqtpopencvinterface OPenCV Interfaceing Tools
* \ingroup jkqtplotter
*
* Classes and functions in this group allow JKQtPlotter to directly work with OpenCV data structures.
*/
/** \file jkqtpopencvinterface.h
* \ingroup jkqtpopencvinterface
*/
#include "jkqtplottertools/jkqtp_imexport.h"
#include "jkqtplotter/jkqtpdatastore.h"
#include <opencv/cv.h>
#ifndef JKQTPOPENCVINTERFACE_H
#define JKQTPOPENCVINTERFACE_H
/** \brief add one external column to the datastore. It will be filled with the contents of vector \a data.
*
* \param datastore the datastore to which the OpenCV matrix shuld be added (as column)
* \param mat OpenCV-marix to store here
* \param name name for the column
* \param channel to copy from \a mat
* \return the ID of the newly created column
*
* \note You need to define the Macro JKQTPLOTTER_OPENCV_INTERFACE when compiling this lib to enabled this function.
*/
inline size_t JKQTPcopyCvMatToColumn(JKQTPdatastore* datastore, const cv::Mat& mat, const QString& name=QString(""), int channel=0);
////////////////////////////////////////////////////////////////////////////////////////
namespace JKQTPdatastore_Helper {
template <typename TPixel>
inline void copyDataFromMat(double* data, const cv::Mat& mat, int channel) {
size_t r=0;
const int channels=mat.channels();
for (int iy=0; iy<mat.rows; iy++ ) {
const TPixel* row=mat.ptr<TPixel>(iy);
for (int ix=0; ix<mat.cols; ix++ ) {
data[r]=jkqtp_todouble(*static_cast<const TPixel*>(&(row[ix*channels+channel])));
r++;
}
}
}
}
inline size_t JKQTPcopyCvMatToColumn(JKQTPdatastore* datastore, const cv::Mat& mat, const QString &name, int channel)
{
const size_t N=static_cast<size_t>(mat.cols*mat.rows);
double* d=static_cast<double*>(malloc(static_cast<size_t>(N)*sizeof(double)));
if (CV_MAT_DEPTH(mat.type())==CV_64F) JKQTPdatastore_Helper::copyDataFromMat<double>(d, mat, channel);
else if (CV_MAT_DEPTH(mat.type())==CV_32F) JKQTPdatastore_Helper::copyDataFromMat<float>(d, mat, channel);
else if (CV_MAT_DEPTH(mat.type())==CV_32S) JKQTPdatastore_Helper::copyDataFromMat<uint32_t>(d, mat, channel);
else if (CV_MAT_DEPTH(mat.type())==CV_16S) JKQTPdatastore_Helper::copyDataFromMat<int16_t>(d, mat, channel);
else if (CV_MAT_DEPTH(mat.type())==CV_16U) JKQTPdatastore_Helper::copyDataFromMat<uint16_t>(d, mat, channel);
else if (CV_MAT_DEPTH(mat.type())==CV_8S) JKQTPdatastore_Helper::copyDataFromMat<int8_t>(d, mat, channel);
else if (CV_MAT_DEPTH(mat.type())==CV_8U) JKQTPdatastore_Helper::copyDataFromMat<uint8_t>(d, mat, channel);
else throw std::runtime_error("datatype of cv::Mat not supported by JKQTPdatastore::copyImageToColumn()");
size_t itemid=datastore->addInternalItem(d, N);
return datastore->addColumnForItem(itemid, 0, name);
}
#endif // JKQTPOPENCVINTERFACE_H

View File

@ -41,6 +41,7 @@
*/
class LIB_EXPORT JKQTPEnhancedPainter : public QPainter {
Q_GADGET
public:
JKQTPEnhancedPainter(QPaintDevice* device);
JKQTPEnhancedPainter();

File diff suppressed because it is too large Load Diff

View File

@ -28,8 +28,8 @@ DEFINES += DEBUG_TIMING
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport
# include JKQtFastPlotter source code
# include JKQtPlotter library
DEPENDPATH += . ../../lib
INCLUDEPATH += ../../lib
CONFIG (debug, debug|release):LIBS += -L../../lib/debug -ljkqtfastplotterlib
CONFIG (release):LIBS += -L../../lib/release -ljkqtfastplotterlib
CONFIG (debug, debug|release):LIBS += -L../../lib/debug -ljkqtplotterlib
CONFIG (release):LIBS += -L../../lib/release -ljkqtplotterlib

View File

@ -1,8 +1,8 @@
TEMPLATE = subdirs
SUBDIRS += jkqtfastplotterlib jkqtfastplotter_test
SUBDIRS += jkqtplotterlib jkqtfastplotter_test
jkqtfastplotterlib.file = ../../lib/jkqtfastplotterlib.pro
jkqtplotterlib.file = ../../lib/jkqtplotterlib.pro
jkqtfastplotter_test.file=$$PWD/jkqtfastplotter_test.pro
jkqtfastplotter_test.depends = jkqtfastplotterlib
jkqtfastplotter_test.depends = jkqtplotterlib

View File

@ -4,9 +4,9 @@
## Simple math image plot, showin a 1-channel OpenCV cv::Mat
This project (see `./test/simpletest_imageplot_opencv/`) simply creates a JKQtPlotter widget (as a new window) and adds a color-coded image plot of a mathematical function (here the Airy disk). The image is generated as an OpenCV cv::Mat image and then copied into a single column of the internal datasdtore (JKQTPMathImage could be directly used without the internal datastore).
To copy the data a special OpenCV Interface function `JKQTPdatastore::copyCvMatToColumn()` is used, that copies the data from a cv::Mat directly into a column.
To copy the data a special OpenCV Interface function `JKQTPcopyCvMatToColumn()` is used, that copies the data from a cv::Mat directly into a column.
The function `JKQTPdatastore::copyCvMatToColumn()` is only available, when the preprocessore macro `JKQTPLOTTER_OPENCV_INTERFACE` is defined when compiling the JKQtPlotter library.
The function `JKQTPcopyCvMatToColumn()` is available from the (non-default) header-only extension from `jkqtplotter/jkqtpopencvinterface.h`. This header provides facilities to interface JKQtPlotter with OPenCV.
The source code of the main application is (see [`jkqtplotter_simpletest_imageplot_opencv.cpp`](https://github.com/jkriege2/JKQtPlotter/blob/master/test/simpletest_imageplot_opencv/jkqtplotter_simpletest_imageplot_opencv.cpp):
```c++
@ -14,6 +14,7 @@ The source code of the main application is (see [`jkqtplotter_simpletest_imagepl
#include <cmath>
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/jkqtpgraphsimage.h"
#include "jkqtplotter/jkqtpopencvinterface.h"
#include <opencv/cv.h>
#ifndef M_PI
@ -63,7 +64,7 @@ int main(int argc, char* argv[])
// 3. make data available to JKQtPlotter by adding it to the internal datastore.
// In this step the contents of one channel of the openCV cv::Mat is copied into a column
// of the datastore in row-major order
size_t cAiryDisk=ds->copyCvMatToColumn(airydisk, "imagedata");
size_t cAiryDisk=JKQTPcopyCvMatToColumn(ds, airydisk, "imagedata");
// 4. create a graph (JKQTPColumnMathImage) with the column created above as data

View File

@ -3,6 +3,7 @@
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/jkqtpgraphs.h"
#include "jkqtplotter/jkqtpgraphsimage.h"
#include "jkqtplotter/jkqtpopencvinterface.h"
#include <opencv/cv.h>
#ifndef M_PI
@ -52,7 +53,7 @@ int main(int argc, char* argv[])
// 3. make data available to JKQtPlotter by adding it to the internal datastore.
// In this step the contents of one channel of the openCV cv::Mat is copied into a column
// of the datastore in row-major order
size_t cAiryDisk=ds->copyCvMatToColumn(airydisk, "imagedata");
size_t cAiryDisk=JKQTPcopyCvMatToColumn(ds, airydisk, "imagedata");
// 4. create a graph (JKQTPColumnMathImage) with the column created above as data

View File

@ -4,9 +4,9 @@
## Simple RGB image plot, showing a 3-channel OpenCV cv::Mat
This project (see `./test/simpletest_imageplot_opencv/`) simply creates a JKQtPlotter widget (as a new window) and adds a color-coded image plot of a mathematical function (here the Airy disk). The image is generated as an OpenCV cv::Mat image and then copied into a single column of the internal datasdtore (JKQTPMathImage could be directly used without the internal datastore).
To copy the data a special OpenCV Interface function `JKQTPdatastore::copyCvMatToColumn()` is used, that copies the data from a cv::Mat directly into a column.
To copy the data a special OpenCV Interface function `JKQTPcopyCvMatToColumn()` is used, that copies the data from a cv::Mat directly into a column.
The function `JKQTPdatastore::copyCvMatToColumn()` is only available, when the preprocessore macro `JKQTPLOTTER_OPENCV_INTERFACE` is defined when compiling the JKQtPlotter library.
The function `JKQTPcopyCvMatToColumn()` is available from the (non-default) header-only extension from `jkqtplotter/jkqtpopencvinterface.h`. This header provides facilities to interface JKQtPlotter with OPenCV.
The source code of the main application is (see [`jkqtplotter_simpletest_imageplot_opencv.cpp`](https://github.com/jkriege2/JKQtPlotter/blob/master/test/simpletest_imageplot_opencv/jkqtplotter_simpletest_imageplot_opencv.cpp):
```c++
@ -14,6 +14,7 @@ The source code of the main application is (see [`jkqtplotter_simpletest_imagepl
#include <cmath>
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/jkqtpgraphsimage.h"
#include "jkqtplotter/jkqtpopencvinterface.h"
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
@ -41,9 +42,9 @@ int main(int argc, char* argv[])
// 3. make data available to JKQtPlotter by adding it to the internal datastore.
// In this step the contents of each channel of the openCV cv::Mat is copied into a column
// of the datastore in row-major order
size_t cPictureR=ds->copyCvMatToColumn(picture, "R-channel", 2);
size_t cPictureG=ds->copyCvMatToColumn(picture, "G-channel", 1);
size_t cPictureB=ds->copyCvMatToColumn(picture, "B-channel", 0);
size_t cPictureR=JKQTPcopyCvMatToColumn(ds, picture, "R-channel", 2);
size_t cPictureG=JKQTPcopyCvMatToColumn(ds, picture, "G-channel", 1);
size_t cPictureB=JKQTPcopyCvMatToColumn(ds, picture, "B-channel", 0);
// 4. create a graph (JKQTPColumnRGBMathImage) with the columns created above as data

View File

@ -3,6 +3,7 @@
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/jkqtpgraphs.h"
#include "jkqtplotter/jkqtpgraphsimage.h"
#include "jkqtplotter/jkqtpopencvinterface.h"
#include <opencv2/imgcodecs.hpp>
@ -29,9 +30,9 @@ int main(int argc, char* argv[])
// 3. make data available to JKQtPlotter by adding it to the internal datastore.
// In this step the contents of each channel of the openCV cv::Mat is copied into a column
// of the datastore in row-major order
size_t cPictureR=ds->copyCvMatToColumn(picture, "R-channel", 2);
size_t cPictureG=ds->copyCvMatToColumn(picture, "G-channel", 1);
size_t cPictureB=ds->copyCvMatToColumn(picture, "B-channel", 0);
size_t cPictureR=JKQTPcopyCvMatToColumn(ds, picture, "R-channel", 2);
size_t cPictureG=JKQTPcopyCvMatToColumn(ds, picture, "G-channel", 1);
size_t cPictureB=JKQTPcopyCvMatToColumn(ds, picture, "B-channel", 0);
// 4. create a graph (JKQTPColumnRGBMathImage) with the columns created above as data