matplotlibcpp在linux上安装及简单使用(结合opencv显示图像)
前言这段时间一直在做slam,使用到opencv,因为要把多张图片同时显示在一个窗口上以供对比,在python上很简单用一个plt.imshow()就可以实现了,于是我就想到在c++上也使用matplotlibcpp来实现这个效果,效果如下:安装matplotlibcpp(ubuntu)我写这篇文章是2021年七月一号,git上的地址是:https://github.com/lava/matplo
前言
这段时间一直在做slam,使用到opencv,因为要把多张图片同时显示在一个窗口上以供对比,在python上很简单用一个plt.imshow()就可以实现了,于是我就想到在c++上也使用matplotlibcpp来实现这个效果,效果如下:
安装matplotlibcpp(ubuntu)
我写这篇文章是2021年七月一号,git上的地址是:https://github.com/lava/matplotlib-cpp ,上面对于这个库的介绍已经挺详尽并且example里面也有许多例程,这里不再赘述。把库下载之后(可以直接下载或者在终端git clone一下):
cd matplotlibcpp-master
mkdir build && cd build
cmake ..
make
sudo make install
前提是安装好了cmake。之后就会提示你安装到了usr/local/include下,你可以到该目录下面看到这个头文件,之后我们就能在代码里面直接引用这个头文件。
配置cmakelists文件
我习惯用cmake来编译工程,特地去找了配置matplotlibcpp的方法,参考了https://mangoroom.cn/cpp/call-matplotlib-on-cpp.html 当中的方法,我这里用的是python3安装的matplotlib以及numpy,并且我的opencv是4.0的版本,你可以按照你的实际情况对python和opencv的版本进行相应的设置。
cmake_minimum_required(VERSION 2.8)
#设置cmake最低版本
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS "-std=c++11 -O2 ${SSE_FLAGS} -msse4")
#指定c++编译版本
project(mat)
find_package(Python3 COMPONENTS Development NumPy)
find_package(OpenCV 4 REQUIRED)
#找到必要的库,你可以根据你的实际情况修改成python2或者opencv其他版本
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(main main.cpp)
#这个也是根据你的实际情况进行修改
target_link_libraries(main ${OpenCV_LIBS})
target_include_directories(main PRIVATE ${Python3_INCLUDE_DIRS} ${Python3_NumPy_INCLUDE_DIRS})
target_link_libraries(main Python3::Python Python3::NumPy)
#链接库
opencv与matplotlib结合
这个结合可以有多种方式,但是要注意的是opencv默认把图片读进来的通道顺序是BGR,需要在使用matplotlib显示之前把通道转换一下:
cvtColor(img1,img11,CV_BGR2RGB);
用这个方法需要包含头文件:
#include<opencv2/imgproc/imgproc.hpp>
在源代码中可以看到有两种实现方法,但是我在用其中一种方法的时候,发现源代码本身有问题,在这里留下这个问题,如果有熟悉c++的人能给我一些指导,下面是源代码里面对于plt::imshow()的说明:
inline void imshow(const unsigned char *ptr, const int rows, const int columns, const int colors, const std::map<std::string, std::string> &keywords = {}, PyObject** out = nullptr)
{
detail::imshow((void *) ptr, NPY_UINT8, rows, columns, colors, keywords, out);
}
inline void imshow(const float *ptr, const int rows, const int columns, const int colors, const std::map<std::string, std::string> &keywords = {}, PyObject** out = nullptr)
{
detail::imshow((void *) ptr, NPY_FLOAT, rows, columns, colors, keywords, out);
}
#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);
}
detail::imshow(image2.data, npy_type, image2.rows, image2.cols, image2.channels(), keywords);
}
#endif // WITH_OPENCV
#endif // WITHOUT_NUMPY
先不管它是怎么实现的,源码中大体上有三种引用方式:传入char类型数组、传入float类型数组、传入一张Mat图像,但是第三种方法需要在WITH_OPENCV下进行(因为源码中有这样一句话#ifdef WITH_OPENCV ... #endif)
前面两种方法:
前面两种方法其实大同小异,不同的只是传入的数组的类型,所以放在一起说一下,在opencv中,图像的data成员就是这个函数所需要的参数:
plt::subplot(2,2,1);
cvtColor(img1,img11,CV_BGR2RGB);
plt::imshow(img11.data,img11.rows,img11.cols,3);
plt::subplot(2,2,2);
cvtColor(img2,img21,CV_BGR2RGB);
plt::imshow(img21.data,img21.rows,img21.cols,3);
plt::subplot(2,2,3);
cvtColor(outimg,outimg1,CV_BGR2RGB);
plt::imshow(outimg1.data,outimg1.rows,outimg1.cols,3);
plt::show();
第三种方法:
在用第三种方法的时候,需要在头文件中包含#define WITH_OPENCV,这样你在传参数的时候可以直接传一个Mat图片,但是编译的时候报错居然在matplotlibcpp.h头文件中,这个就很离谱?
/usr/local/include/matplotlibcpp.h:987:96: error: too few arguments to function ‘void matplotlibcpp::detail::imshow(void*, NPY_TYPES, int, int, int, const std::map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >&, PyObject**)’
[build] 987 | detail::imshow(image2.data, npy_type, image2.rows, image2.cols, image2.channels(), keywords);
[build] | ^
[build] /usr/local/include/matplotlibcpp.h:918:13: note: declared here
[build] 918 | inline 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, PyObject** out)
[build] | ^~~~~~
大体意思就是说这个头文件里面第987行的引用错了,给的参数太少,我再回去看一下那个头文件:
可以看到编译器已经给我标红了,说明在这个函数里面调用imshow()的时候参数设置有问题。希望懂得同学能给我指导一下怎么样修改这个头文件。
代码:
//#define WITH_OPENCV
#include<iostream>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgcodecs/legacy/constants_c.h>
#include<opencv2/features2d/features2d.hpp>
#include<./matplotlibcpp.h>
#include<opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
namespace plt=matplotlibcpp;
int main(int argc, char **argv){
if (argc!=3){
cout<<"two images are needed, but "<<argc-1<<" is given";
return 1;
}
Mat img1=imread(argv[1],CV_LOAD_IMAGE_COLOR);
Mat img2=imread(argv[2],CV_LOAD_IMAGE_COLOR);
assert(img1.data!=nullptr && img2.data!=nullptr);
cout<<"two images has been read"<<endl;
vector<KeyPoint> keypointImg1,keypointImg2;
Mat descriptorImg1,descriptorImg2;
Ptr<FeatureDetector> dectector =ORB::create();
Ptr<DescriptorExtractor>descriptor=ORB::create();
Ptr<DescriptorMatcher> matcher=DescriptorMatcher::create("BruteForce-Hamming");
dectector->detect(img1,keypointImg1);
dectector->detect(img2,keypointImg2);
descriptor->compute(img1,keypointImg1,descriptorImg1);
descriptor->compute(img2,keypointImg2,descriptorImg2);
Mat outimg;
drawKeypoints(img1,keypointImg1,outimg,Scalar::all(-1),DrawMatchesFlags::DEFAULT);
Mat img11;
Mat img21;
Mat outimg1;
plt::subplot(2,2,1);
cvtColor(img1,img11,CV_BGR2RGB);
plt::imshow(img11.data,img11.rows,img11.cols,3);
plt::subplot(2,2,2);
cvtColor(img2,img21,CV_BGR2RGB);
plt::imshow(img21.data,img21.rows,img21.cols,3);
plt::subplot(2,2,3);
cvtColor(outimg,outimg1,CV_BGR2RGB);
plt::imshow(outimg1.data,outimg1.rows,outimg1.cols,3);
plt::show();
return 0;
}
更多推荐
所有评论(0)