How to use plt.imshow() for display cv::Mat images?
I was looking for an easy way to plot subplots of images in C++. But this was the best that I could find. I know that plt.imshow() is not used for subplts. I'd use plt.subplots. But first I'd like to figure out how to use plt.imshow() for displaying images in C++. How would I do this given that images in C++ are of type cv::Mat?
Thank you so much!
Hi,
the easiest way to display C++ matrix using imshow is to convert it into nested python list using pybind11 API.
#include <pybind11/embed.h>
#include <pybind11/pybind11.h>
#include <pyscience11/matplotlib.h>
#include <pyscience11/matplotlib/pyplot.h>
namespace py = pybind11;
namespace m11 = matplotlib11;
int main(void)
{
py::scoped_interpreter interpreter;
py::list img;
for (size_t j = 0; j < 100; ++j)
{
py::list line;
for (size_t i = 0; i < 100; ++i)
{
line.append(i * j);
}
img.append(line);
}
// These lines are needed on macOS
auto matplotlib = m11::import_matplotlib();
matplotlib.use("TkAgg");
auto pl = m11::matplotlib::import_pyplot();
pl.imshow(img);
pl.show();
return 0;
}
This yields the following image.

Also subplotting is available, though we need to use pybind11 API directly because pyscience11 does not currently support class methods.
#include <pybind11/embed.h>
#include <pybind11/pybind11.h>
#include <pyscience11/matplotlib.h>
#include <pyscience11/matplotlib/pyplot.h>
namespace py = pybind11;
namespace m11 = matplotlib11;
int main(void)
{
py::scoped_interpreter interpreter;
py::list img;
for (size_t j = 0; j < 100; ++j)
{
py::list line;
for (size_t i = 0; i < 100; ++i)
{
line.append(i * j);
}
img.append(line);
}
// These lines are needed on macOS
auto matplotlib = m11::import_matplotlib();
matplotlib.use("TkAgg");
auto pl = m11::matplotlib::import_pyplot();
auto sub = pl.subplot(221);
sub.attr("imshow")(img);
pl.show();
return 0;
}
Hope this helps.
Hello, thank you so much. I just have a few questions.
-
Why does it use a python list instead of a numpy array? I suppose the two are easily interchangeable, but I'm still confused. I originally tried using your numpy wrapper to create a numpy array through calling numpy.zeros(), passing it to pl.imshow() and it didn't work.
-
For converting cv::Mat to py::list do I have to use nested loops? That seems pretty slow. Is there no faster way to do it?
Thank you.
Hi,
the above example is written as the easiest example to show images in C++ using matplotlib. If you are concerned with performance, you need to use ndarray instead of python list. Sorry that I haven't used OpenCV, I don't know there is an easy way to do the conversion.
Possibly pybind11:array_t<T> can be used.
I can create a two-dimensional ndarray using the following example, that can be passed to imshow.
auto numpy = n11::import_numpy();
py::list shape;
shape.append(10);
shape.append(10);
auto arr = numpy.zeros(shape);
Please check variables using py::repr to confirm you are creating a matrix with correct shape.
py::print(py::repr(arr));