mirror of
https://github.com/jkriege2/JKQtPlotter.git
synced 2024-12-24 09:31:40 +08:00
added OpenCV-support
This commit is contained in:
parent
9ff25f4b0d
commit
6cfc3dba59
@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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 <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
|
||||
|
||||
|
||||
|
||||
|
@ -49,7 +49,9 @@
|
||||
#include <QStringList>
|
||||
#include <QAbstractTableModel>
|
||||
#include <QObject>
|
||||
|
||||
#ifdef JKQTPLOTTER_OPENCV_INTERFACE
|
||||
# include <opencv/cv.h>
|
||||
#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 <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);
|
||||
}
|
||||
|
||||
@ -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); }
|
||||
|
BIN
screenshots/jkqtplotter_simpletest_imageplot_opencv.png
Normal file
BIN
screenshots/jkqtplotter_simpletest_imageplot_opencv.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
BIN
screenshots/jkqtplotter_simpletest_imageplot_opencv_small.png
Normal file
BIN
screenshots/jkqtplotter_simpletest_imageplot_opencv_small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
1
test/jkqtplotter_simpletest_imageplot_opencv/.gitignore
vendored
Normal file
1
test/jkqtplotter_simpletest_imageplot_opencv/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/OpenCV-3.4.1
|
122
test/jkqtplotter_simpletest_imageplot_opencv/README.md
Normal file
122
test/jkqtplotter_simpletest_imageplot_opencv/README.md
Normal 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/)
|
@ -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();
|
||||
}
|
@ -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
|
Loading…
Reference in New Issue
Block a user