added OpenCV-support

This commit is contained in:
jkriege2 2018-11-26 22:14:41 +01:00
parent 9ff25f4b0d
commit 6cfc3dba59
9 changed files with 325 additions and 9 deletions

View File

@ -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](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)

View File

@ -97,8 +97,8 @@ double JKQTPcolumn::getValue(size_t n) const
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
double *JKQTPcolumn::getPointer(size_t n) const double *JKQTPcolumn::getPointer(size_t n) const
{ {
if (!datastore) return 0; if (!datastore) return nullptr;
if (!datastore->getItem(datastoreItem)) return 0; if (!datastore->getItem(datastoreItem)) return nullptr;
return datastore->getItem(datastoreItem)->getPointer(datastoreOffset, n); 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) void JKQTPcolumn::setValue(size_t n, double val)
{ {
if (!datastore) return ; if (!datastore) return ;
if (!datastore->getItem(datastoreItem)) return; if (!datastore->getItem(datastoreItem)) return ;
datastore->getItem(datastoreItem)->set(datastoreOffset, n, val); 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); 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

View File

@ -49,7 +49,9 @@
#include <QStringList> #include <QStringList>
#include <QAbstractTableModel> #include <QAbstractTableModel>
#include <QObject> #include <QObject>
#ifdef JKQTPLOTTER_OPENCV_INTERFACE
# include <opencv/cv.h>
#endif
#ifndef JKQTPDATASTORAGE_H #ifndef JKQTPDATASTORAGE_H
#define JKQTPDATASTORAGE_H #define JKQTPDATASTORAGE_H
@ -164,7 +166,12 @@ class LIB_EXPORT JKQTPdatastore{
void clear(); void clear();
/** \brief returns the JKQTPdatastoreItem object for the \a i -th item in the store */ /** \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); return items.value(i, nullptr);
} }
@ -259,6 +266,17 @@ class LIB_EXPORT JKQTPdatastore{
size_t itemid=addInternalItem(d, N); size_t itemid=addInternalItem(d, N);
return addColumnForItem(itemid, 0, name); 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. /** \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 /** \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.*/ * afterwards you can delete the external arrayThis returns its logical column ID.*/
template <typename TContainer> template <typename TContainer>
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<TContainer>(data, name); return addCopiedColumn<TContainer>(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 * This method accesses the datastore and returns the double value stored in the \a n'th row of the according
* column. * 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 */ /** \brief returns a pointer to the datastore item representing this column */
inline JKQTPdatastoreItem* getDatastoreItem() const { return datastore->getItem(datastoreItem); } inline JKQTPdatastoreItem* getDatastoreItem() const { return datastore->getItem(datastoreItem); }

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1 @@
/OpenCV-3.4.1

View File

@ -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 <QApplication>
#include <cmath>
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/jkqtpimageelements.h"
#include <opencv/cv.h>
#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<double>(airydisk.cols)*dx;
const double h=static_cast<double>(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<airydisk.rows; iy++ ) {
x=-w/2.0;
for (int ix=0; ix<airydisk.cols; ix++ ) {
const double r=sqrt(x*x+y*y);
const double v=2.0*M_PI*NA*r/wavelength;
airydisk.at<double>(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/)

View File

@ -0,0 +1,106 @@
#include <QApplication>
#include <cmath>
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/jkqtpimageelements.h"
#include <opencv/cv.h>
#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<double>(airydisk.cols)*dx;
const double h=static_cast<double>(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<airydisk.rows; iy++ ) {
x=-w/2.0;
for (int ix=0; ix<airydisk.cols; ix++ ) {
const double r=sqrt(x*x+y*y);
const double v=2.0*M_PI*NA*r/wavelength;
airydisk.at<double>(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();
}

View File

@ -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