From 6cfc3dba59314aa9af7dba5cf821f34a4728a3c2 Mon Sep 17 00:00:00 2001 From: jkriege2 Date: Mon, 26 Nov 2018 22:14:41 +0100 Subject: [PATCH] added OpenCV-support --- README.md | 2 + lib/jkqtplotter/jkqtpdatastorage.cpp | 44 ++++++- lib/jkqtplotter/jkqtpdatastorage.h | 35 ++++- ...kqtplotter_simpletest_imageplot_opencv.png | Bin 0 -> 17015 bytes ...tter_simpletest_imageplot_opencv_small.png | Bin 0 -> 12907 bytes .../.gitignore | 1 + .../README.md | 122 ++++++++++++++++++ ...kqtplotter_simpletest_imageplot_opencv.cpp | 106 +++++++++++++++ ...kqtplotter_simpletest_imageplot_opencv.pro | 24 ++++ 9 files changed, 325 insertions(+), 9 deletions(-) create mode 100644 screenshots/jkqtplotter_simpletest_imageplot_opencv.png create mode 100644 screenshots/jkqtplotter_simpletest_imageplot_opencv_small.png create mode 100644 test/jkqtplotter_simpletest_imageplot_opencv/.gitignore create mode 100644 test/jkqtplotter_simpletest_imageplot_opencv/README.md create mode 100644 test/jkqtplotter_simpletest_imageplot_opencv/jkqtplotter_simpletest_imageplot_opencv.cpp create mode 100644 test/jkqtplotter_simpletest_imageplot_opencv/jkqtplotter_simpletest_imageplot_opencv.pro diff --git a/README.md b/README.md index 044b8a5cb2..af850647e2 100644 --- a/README.md +++ b/README.md @@ -475,6 +475,8 @@ The result looks like this: ![jkqtplotter_simpletest_imageplot](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_imageplot.png) +[![jkqtplotter_simpletest_imageplot_opencv_small](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_imageplot_opencv_small.png)](https://github.com/jkriege2/JKQtPlotter/test/jkqtplotter_simpletest_imageplot_opencv) + diff --git a/lib/jkqtplotter/jkqtpdatastorage.cpp b/lib/jkqtplotter/jkqtpdatastorage.cpp index c0d51586ec..a691d75f60 100644 --- a/lib/jkqtplotter/jkqtpdatastorage.cpp +++ b/lib/jkqtplotter/jkqtpdatastorage.cpp @@ -97,8 +97,8 @@ double JKQTPcolumn::getValue(size_t n) const //////////////////////////////////////////////////////////////////////////////////////////////// double *JKQTPcolumn::getPointer(size_t n) const { - if (!datastore) return 0; - if (!datastore->getItem(datastoreItem)) return 0; + if (!datastore) return nullptr; + if (!datastore->getItem(datastoreItem)) return nullptr; return datastore->getItem(datastoreItem)->getPointer(datastoreOffset, n); } @@ -106,10 +106,9 @@ double *JKQTPcolumn::getPointer(size_t n) const void JKQTPcolumn::setValue(size_t n, double val) { if (!datastore) return ; - if (!datastore->getItem(datastoreItem)) return; + if (!datastore->getItem(datastoreItem)) return ; datastore->getItem(datastoreItem)->set(datastoreOffset, n, val); -}; - +} @@ -490,6 +489,41 @@ 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 + void copyDataFromMat(double* data, const cv::Mat& mat, int channel) { + size_t r=0; + const int channels=mat.channels(); + for (int iy=0; iy(iy); + for (int ix=0; ix(&(row[ix*channels+channel]))); + r++; + } + } + } +} + +size_t JKQTPdatastore::copyCvMatToColumn(const cv::Mat& mat, const QString &name, int channel) +{ + const size_t N=static_cast(mat.cols*mat.rows); + double* d=static_cast(malloc(static_cast(N)*sizeof(double))); + + if (CV_MAT_DEPTH(mat.type())==CV_64F) JKQTPdatastore_Helper::copyDataFromMat(d, mat, channel); + else if (CV_MAT_DEPTH(mat.type())==CV_32F) JKQTPdatastore_Helper::copyDataFromMat(d, mat, channel); + else if (CV_MAT_DEPTH(mat.type())==CV_32S) JKQTPdatastore_Helper::copyDataFromMat(d, mat, channel); + else if (CV_MAT_DEPTH(mat.type())==CV_16S) JKQTPdatastore_Helper::copyDataFromMat(d, mat, channel); + else if (CV_MAT_DEPTH(mat.type())==CV_16U) JKQTPdatastore_Helper::copyDataFromMat(d, mat, channel); + else if (CV_MAT_DEPTH(mat.type())==CV_8S) JKQTPdatastore_Helper::copyDataFromMat(d, mat, channel); + else if (CV_MAT_DEPTH(mat.type())==CV_8U) JKQTPdatastore_Helper::copyDataFromMat(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 diff --git a/lib/jkqtplotter/jkqtpdatastorage.h b/lib/jkqtplotter/jkqtpdatastorage.h index 429c4b2b71..e880fa8285 100644 --- a/lib/jkqtplotter/jkqtpdatastorage.h +++ b/lib/jkqtplotter/jkqtpdatastorage.h @@ -49,7 +49,9 @@ #include #include #include - +#ifdef JKQTPLOTTER_OPENCV_INTERFACE +# include +#endif #ifndef JKQTPDATASTORAGE_H #define JKQTPDATASTORAGE_H @@ -164,7 +166,12 @@ class LIB_EXPORT JKQTPdatastore{ void clear(); /** \brief returns the JKQTPdatastoreItem object for the \a i -th item in the store */ - inline JKQTPdatastoreItem* getItem(size_t i) const { + inline JKQTPdatastoreItem* getItem(size_t i) { + return items.value(i, nullptr); + } + + /** \brief returns the JKQTPdatastoreItem object for the \a i -th item in the store */ + inline const JKQTPdatastoreItem* getItem(size_t i) const { return items.value(i, nullptr); } @@ -259,6 +266,17 @@ 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 + */ + 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. * @@ -362,7 +380,7 @@ class LIB_EXPORT JKQTPdatastore{ /** \brief add one external column to the datastore. It contains \a width * \a height rows. The external data is assumed to be organized as a row-major image and is copied as such. The external data is copied to an internal array, so * afterwards you can delete the external arrayThis returns its logical column ID.*/ template - inline size_t addCopiedImageAsColumn(const TContainer& data, size_t /*width*/, const QString& name=QString("")){ + inline size_t addCopiedImageAsColumn(const TContainer& data, const QString& name=QString("")){ return addCopiedColumn(data, name); } @@ -617,7 +635,16 @@ class LIB_EXPORT JKQTPcolumn { * This method accesses the datastore and returns the double value stored in the \a n'th row of the according * column. */ - void setValue(size_t n, double val) ; + void setValue(size_t n, double val); + + /** \brief sets the element at (x,y) in the column, where the data is interpreted as a row-major ordered Matrix of the given width + * + * This method accesses the datastore and returns the double value stored in the \a n'th row of the according + * column. + */ + inline void setPixelValue(size_t x, size_t y, size_t width, double val) { + setValue(y*width+x, val); + } /** \brief returns a pointer to the datastore item representing this column */ inline JKQTPdatastoreItem* getDatastoreItem() const { return datastore->getItem(datastoreItem); } diff --git a/screenshots/jkqtplotter_simpletest_imageplot_opencv.png b/screenshots/jkqtplotter_simpletest_imageplot_opencv.png new file mode 100644 index 0000000000000000000000000000000000000000..7b12a17685e7ab3efd3517738a9cae32ae3843f8 GIT binary patch literal 17015 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 literal 0 HcmV?d00001 diff --git a/screenshots/jkqtplotter_simpletest_imageplot_opencv_small.png b/screenshots/jkqtplotter_simpletest_imageplot_opencv_small.png new file mode 100644 index 0000000000000000000000000000000000000000..8da725f3485d2db13f78289549f3ff13ff1400d7 GIT binary patch literal 12907 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 VKI~nvE5!f+002ovPDHLkV1oK``~d&} literal 0 HcmV?d00001 diff --git a/test/jkqtplotter_simpletest_imageplot_opencv/.gitignore b/test/jkqtplotter_simpletest_imageplot_opencv/.gitignore new file mode 100644 index 0000000000..0082aa1a30 --- /dev/null +++ b/test/jkqtplotter_simpletest_imageplot_opencv/.gitignore @@ -0,0 +1 @@ +/OpenCV-3.4.1 diff --git a/test/jkqtplotter_simpletest_imageplot_opencv/README.md b/test/jkqtplotter_simpletest_imageplot_opencv/README.md new file mode 100644 index 0000000000..fec6352f66 --- /dev/null +++ b/test/jkqtplotter_simpletest_imageplot_opencv/README.md @@ -0,0 +1,122 @@ +[Back to JKQTPlotter main page](https://github.com/jkriege2/JKQtPlotter/) + +# JKQtPlotter + +## Simple math image plot, showin a 1-channel OpenCV cv::Mat +This project (see `./test/jkqtplotter_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 stored as a simple C-array in row-major ordering and then copied into a single column of the internal datasdtore (JKQTPMathImage could be directly used without the internal datastore). This very simple interface can also be used to interface with many common image processing libraries, like CImg or OpenCV. + +The soruce code of the main application is (see `./test/jkqtplotter_simpletest_imageplot_opencv/jkqtplotter_simpletest_imageplot_opencv.cpp`): +```c++ +#include +#include +#include "jkqtplotter/jkqtplotter.h" +#include "jkqtplotter/jkqtpimageelements.h" +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + + +int main(int argc, char* argv[]) +{ + QApplication app(argc, argv); + + JKQtPlotter plot; + + + // 1. create a plotter window and get a pointer to the internal datastore (for convenience) + plot.get_plotter()->set_useAntiAliasingForGraphs(true); // nicer (but slower) plotting + plot.get_plotter()->set_useAntiAliasingForSystem(true); // nicer (but slower) plotting + plot.get_plotter()->set_useAntiAliasingForText(true); // nicer (but slower) text rendering + JKQTPdatastore* ds=plot.getDatastore(); + + + // 2. now we create data for the charts (taken from https://commons.wikimedia.org/wiki/File:Energiemix_Deutschland.svg) + cv::Mat airydisk(150, 150, CV_64FC1); // OpenCV-Image for the data + const double dx=1e-2; // size of a pixel in x-direction [micrometers] + const double dy=1e-2; // size of a pixel in x-direction [micrometers] + const double w=static_cast(airydisk.cols)*dx; + const double h=static_cast(airydisk.rows)*dy; + + // 2.1 Parameters for airy disk plot (see https://en.wikipedia.org/wiki/Airy_disk) + double NA=1.1; // numerical aperture of lens + double wavelength=488e-3; // wavelength of the light [micrometers] + + // 2.2 calculate image of airy disk in a row-major array + double x, y=-h/2.0; + for (int iy=0; iy(iy,ix) = pow(2.0*j1(v)/v, 2); + x+=dx; + } + y+=dy; + } + + + // 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"); + + + // 4. create a graph (JKQTPColumnMathImage) with the column created above as data + // The data is color-coded with the color-palette JKQTPMathImageMATLAB + // the converted range of data is determined automatically because set_autoImageRange(true) + JKQTPColumnMathImage* graph=new JKQTPColumnMathImage(&plot); + graph->set_title(""); + // image column with the data + graph->set_imageColumn(cAiryDisk); + // set size of the data (the datastore does not contain this info, as it only manages 1D columns of data and this is used to assume a row-major ordering + graph->set_Nx(airydisk.cols); + graph->set_Ny(airydisk.rows); + // where does the image start in the plot, given in plot-axis-coordinates (bottom-left corner) + graph->set_x(-w/2.0); + graph->set_y(-h/2.0); + // width and height of the image in plot-axis-coordinates + graph->set_width(w); + graph->set_height(h); + // color-map is "MATLAB" + graph->set_palette(JKQTPMathImageMATLAB); + // get coordinate axis of color-bar and set its label + graph->get_colorBarRightAxis()->set_axisLabel("light intensity [A.U.]"); + // determine min/max of data automatically and use it to set the range of the color-scale + graph->set_autoImageRange(true); + // you can set the color-scale range manually by using: + // graph->set_autoImageRange(false); + // graph->set_imageMin(0); + // graph->set_imageMax(10); + + + // 5. add the graphs to the plot, so it is actually displayed + plot.addGraph(graph); + + // 6. set axis labels + plot.get_xAxis()->set_axisLabel("x [{\\mu}m]"); + plot.get_yAxis()->set_axisLabel("y [{\\mu}m]"); + + // 7. fix axis and plot aspect ratio to 1 + plot.get_plotter()->set_maintainAspectRatio(true); + plot.get_plotter()->set_maintainAxisAspectRatio(true); + + // 8 autoscale the plot so the graph is contained + plot.zoomToFit(); + + // show plotter and make it a decent size + plot.show(); + plot.resize(600,600); + plot.setWindowTitle("JKQTPColumnMathImage"); + + + return app.exec(); +} + +``` +The result looks like this: + +![jkqtplotter_simpletest_imageplot](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_imageplot_opencv.png) + +[Back to JKQTPlotter main page](https://github.com/jkriege2/JKQtPlotter/) \ No newline at end of file diff --git a/test/jkqtplotter_simpletest_imageplot_opencv/jkqtplotter_simpletest_imageplot_opencv.cpp b/test/jkqtplotter_simpletest_imageplot_opencv/jkqtplotter_simpletest_imageplot_opencv.cpp new file mode 100644 index 0000000000..49f33253f4 --- /dev/null +++ b/test/jkqtplotter_simpletest_imageplot_opencv/jkqtplotter_simpletest_imageplot_opencv.cpp @@ -0,0 +1,106 @@ +#include +#include +#include "jkqtplotter/jkqtplotter.h" +#include "jkqtplotter/jkqtpimageelements.h" +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + + +int main(int argc, char* argv[]) +{ + QApplication app(argc, argv); + + JKQtPlotter plot; + + + // 1. create a plotter window and get a pointer to the internal datastore (for convenience) + plot.get_plotter()->set_useAntiAliasingForGraphs(true); // nicer (but slower) plotting + plot.get_plotter()->set_useAntiAliasingForSystem(true); // nicer (but slower) plotting + plot.get_plotter()->set_useAntiAliasingForText(true); // nicer (but slower) text rendering + JKQTPdatastore* ds=plot.getDatastore(); + + + // 2. now we create data for the charts (taken from https://commons.wikimedia.org/wiki/File:Energiemix_Deutschland.svg) + cv::Mat airydisk(150, 150, CV_64FC1); // OpenCV-Image for the data + const double dx=1e-2; // size of a pixel in x-direction [micrometers] + const double dy=1e-2; // size of a pixel in x-direction [micrometers] + const double w=static_cast(airydisk.cols)*dx; + const double h=static_cast(airydisk.rows)*dy; + + // 2.1 Parameters for airy disk plot (see https://en.wikipedia.org/wiki/Airy_disk) + double NA=1.1; // numerical aperture of lens + double wavelength=488e-3; // wavelength of the light [micrometers] + + // 2.2 calculate image of airy disk in a row-major array + double x, y=-h/2.0; + for (int iy=0; iy(iy,ix) = pow(2.0*j1(v)/v, 2); + x+=dx; + } + y+=dy; + } + + + // 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"); + + + // 4. create a graph (JKQTPColumnMathImage) with the column created above as data + // The data is color-coded with the color-palette JKQTPMathImageMATLAB + // the converted range of data is determined automatically because set_autoImageRange(true) + JKQTPColumnMathImage* graph=new JKQTPColumnMathImage(&plot); + graph->set_title(""); + // image column with the data + graph->set_imageColumn(cAiryDisk); + // set size of the data (the datastore does not contain this info, as it only manages 1D columns of data and this is used to assume a row-major ordering + graph->set_Nx(airydisk.cols); + graph->set_Ny(airydisk.rows); + // where does the image start in the plot, given in plot-axis-coordinates (bottom-left corner) + graph->set_x(-w/2.0); + graph->set_y(-h/2.0); + // width and height of the image in plot-axis-coordinates + graph->set_width(w); + graph->set_height(h); + // color-map is "MATLAB" + graph->set_palette(JKQTPMathImageMATLAB); + // get coordinate axis of color-bar and set its label + graph->get_colorBarRightAxis()->set_axisLabel("light intensity [A.U.]"); + // determine min/max of data automatically and use it to set the range of the color-scale + graph->set_autoImageRange(true); + // you can set the color-scale range manually by using: + // graph->set_autoImageRange(false); + // graph->set_imageMin(0); + // graph->set_imageMax(10); + + + // 5. add the graphs to the plot, so it is actually displayed + plot.addGraph(graph); + + // 6. set axis labels + plot.get_xAxis()->set_axisLabel("x [{\\mu}m]"); + plot.get_yAxis()->set_axisLabel("y [{\\mu}m]"); + + // 7. fix axis and plot aspect ratio to 1 + plot.get_plotter()->set_maintainAspectRatio(true); + plot.get_plotter()->set_maintainAxisAspectRatio(true); + + // 8 autoscale the plot so the graph is contained + plot.zoomToFit(); + + // show plotter and make it a decent size + plot.show(); + plot.resize(600,600); + plot.setWindowTitle("JKQTPColumnMathImage"); + + + return app.exec(); +} diff --git a/test/jkqtplotter_simpletest_imageplot_opencv/jkqtplotter_simpletest_imageplot_opencv.pro b/test/jkqtplotter_simpletest_imageplot_opencv/jkqtplotter_simpletest_imageplot_opencv.pro new file mode 100644 index 0000000000..92d4b48002 --- /dev/null +++ b/test/jkqtplotter_simpletest_imageplot_opencv/jkqtplotter_simpletest_imageplot_opencv.pro @@ -0,0 +1,24 @@ +# source code for this simple demo +SOURCES = jkqtplotter_simpletest_imageplot_opencv.cpp + +# configure Qt +CONFIG += qt +QT += core gui svg +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport + +# output executable name +TARGET = jkqtplotter_simpletest_imageplot_opencv + +# include JKQtPlotter source code +include(../../lib/jkqtplotter.pri) +# here you can activate some debug options +#DEFINES += SHOW_JKQTPLOTTER_DEBUG +#DEFINES += JKQTBP_AUTOTIMER + + +# link agains OpenCV-3.4.1 +INCLUDEPATH += $$PWD/OpenCV-3.4.1/include/ +LIBS += -L$$PWD/OpenCV-3.4.1/bin/ -llibopencv_core341 + +# add OpenCV-interface to JKQTPdatastore +DEFINES += JKQTPLOTTER_OPENCV_INTERFACE