Skip to content

Add support for imshow() #79

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from
9 changes: 6 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
examples: minimal basic modern animation nonblock xkcd quiver bar surface fill_inbetween fill update
examples: minimal basic modern animation nonblock xkcd quiver bar surface fill_inbetween fill update imshow

minimal: examples/minimal.cpp matplotlibcpp.h
cd examples && g++ -DWITHOUT_NUMPY minimal.cpp -I/usr/include/python2.7 -lpython2.7 -o minimal -std=c++11
Expand Down Expand Up @@ -32,9 +32,12 @@ fill_inbetween: examples/fill_inbetween.cpp matplotlibcpp.h

fill: examples/fill.cpp matplotlibcpp.h
cd examples && g++ fill.cpp -I/usr/include/python2.7 -lpython2.7 -o fill -std=c++11

update: examples/update.cpp matplotlibcpp.h
cd examples && g++ update.cpp -I/usr/include/python2.7 -lpython2.7 -o update -std=c++11

imshow: examples/imshow.cpp matplotlibcpp.h
cd examples && g++ imshow.cpp -I/usr/include/python2.7 -lpython2.7 -o imshow -std=c++11

clean:
rm -f examples/{minimal,basic,modern,animation,nonblock,xkcd,quiver,bar,surface,fill_inbetween,fill,update}
rm -f examples/{minimal,basic,modern,animation,nonblock,xkcd,quiver,bar,surface,fill_inbetween,fill,update,imshow}
27 changes: 27 additions & 0 deletions examples/imshow.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#define _USE_MATH_DEFINES
#include <cmath>
#include "../matplotlibcpp.h"

using namespace std;
namespace plt = matplotlibcpp;

int main()
{
// Prepare data
int ncols = 500, nrows = 300;
std::vector<float> z(ncols * nrows);
for (int j=0; j<nrows; ++j) {
for (int i=0; i<ncols; ++i) {
z.at(ncols * j + i) = std::sin(std::hypot(i - ncols/2, j - nrows/2));
}
}

const float* zptr = &(z[0]);
const int colors = 1;

plt::title("My matrix");
plt::imshow(zptr, nrows, ncols, colors);

// Show plots
plt::save("imshow.png");
}
86 changes: 86 additions & 0 deletions matplotlibcpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
#ifndef WITHOUT_NUMPY
# define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
# include <numpy/arrayobject.h>

# ifdef WITH_OPENCV
# include <opencv2/opencv.hpp>
# endif // WITH_OPENCV
#endif // WITHOUT_NUMPY

#if PY_MAJOR_VERSION >= 3
Expand Down Expand Up @@ -45,6 +49,7 @@ struct _interpreter {
PyObject *s_python_function_fill;
PyObject *s_python_function_fill_between;
PyObject *s_python_function_hist;
PyObject *s_python_function_imshow;
PyObject *s_python_function_scatter;
PyObject *s_python_function_subplot;
PyObject *s_python_function_legend;
Expand Down Expand Up @@ -165,6 +170,9 @@ struct _interpreter {
s_python_function_fill = PyObject_GetAttrString(pymod, "fill");
s_python_function_fill_between = PyObject_GetAttrString(pymod, "fill_between");
s_python_function_hist = PyObject_GetAttrString(pymod,"hist");
#ifndef WITHOUT_NUMPY
s_python_function_imshow = PyObject_GetAttrString(pymod, "imshow");
#endif
s_python_function_scatter = PyObject_GetAttrString(pymod,"scatter");
s_python_function_subplot = PyObject_GetAttrString(pymod, "subplot");
s_python_function_legend = PyObject_GetAttrString(pymod, "legend");
Expand Down Expand Up @@ -211,6 +219,9 @@ struct _interpreter {
|| !s_python_function_axis
|| !s_python_function_xlabel
|| !s_python_function_ylabel
#ifndef WITHOUT_NUMPY
|| !s_python_function_imshow
#endif
|| !s_python_function_grid
|| !s_python_function_xlim
|| !s_python_function_ion
Expand Down Expand Up @@ -246,6 +257,9 @@ struct _interpreter {
|| !PyFunction_Check(s_python_function_legend)
|| !PyFunction_Check(s_python_function_annotate)
|| !PyFunction_Check(s_python_function_ylim)
#ifndef WITHOUT_NUMPY
|| !PyFunction_Check(s_python_function_imshow)
#endif
|| !PyFunction_Check(s_python_function_title)
|| !PyFunction_Check(s_python_function_axis)
|| !PyFunction_Check(s_python_function_xlabel)
Expand Down Expand Up @@ -623,6 +637,78 @@ bool hist(const std::vector<Numeric>& y, long bins=10,std::string color="b",
return res;
}

#ifndef WITHOUT_NUMPY
namespace internal {
void imshow(void *ptr, const NPY_TYPES type, const int rows, const int columns, const int colors, const std::map<std::string, std::string> &keywords)
{
assert(type == NPY_UINT8 || type == NPY_FLOAT);
assert(colors == 1 || colors == 3 || colors == 4);

detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work

// construct args
npy_intp dims[3] = { rows, columns, colors };
PyObject *args = PyTuple_New(1);
PyTuple_SetItem(args, 0, PyArray_SimpleNewFromData(colors == 1 ? 2 : 3, dims, type, ptr));

// construct keyword args
PyObject* kwargs = PyDict_New();
for(std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it)
{
PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
}

PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_imshow, args, kwargs);
Py_DECREF(args);
Py_DECREF(kwargs);
if (!res)
throw std::runtime_error("Call to imshow() failed");
Py_DECREF(res);
}
}

void imshow(const unsigned char *ptr, const int rows, const int columns, const int colors, const std::map<std::string, std::string> &keywords = {})
{
internal::imshow((void *) ptr, NPY_UINT8, rows, columns, colors, keywords);
}

void imshow(const float *ptr, const int rows, const int columns, const int colors, const std::map<std::string, std::string> &keywords = {})
{
internal::imshow((void *) ptr, NPY_FLOAT, rows, columns, colors, keywords);
}

#ifdef WITH_OPENCV
void imshow(const cv::Mat &image, const std::map<std::string, std::string> &keywords = {})
{
// Convert underlying type of matrix, if needed
cv::Mat image2;
NPY_TYPES npy_type = NPY_UINT8;
switch (image.type() & CV_MAT_DEPTH_MASK) {
case CV_8U:
image2 = image;
break;
case CV_32F:
image2 = image;
npy_type = NPY_FLOAT;
break;
default:
image.convertTo(image2, CV_MAKETYPE(CV_8U, image.channels()));
}

// If color image, convert from BGR to RGB
switch (image2.channels()) {
case 3:
cv::cvtColor(image2, image2, CV_BGR2RGB);
break;
case 4:
cv::cvtColor(image2, image2, CV_BGRA2RGBA);
}

internal::imshow(image2.data, npy_type, image2.rows, image2.cols, image2.channels(), keywords);
}
#endif
#endif

template<typename NumericX, typename NumericY>
bool scatter(const std::vector<NumericX>& x,
const std::vector<NumericY>& y,
Expand Down