C++で開発しなければならないときに、困っているのがいいグラフを書くライブラリです。
Windows,Linuxでも同じように動作して、MATLAB並みの操作性と、なるべくならMATLAB類似のライブラリの体系を持っているライブラリです。OpenCVとも親和性がよいのを望んでいます。
どなたか、そのようないいライブラリの情報をお持ちでしたら、お知らせください。
C++で使えるという条件を外すと、pythonのライブラリ,matplotlibがある。
しかたがないので、C++からスクリプトを生成して、pythonでmatplotlibを実行してみる雛形を書いてみた。
実行ディレクトリにlena.jpgがあることを仮定しています。
#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>
// 文字列を置換する
// どなたかが書いた関数
std::string Replace(std::string String1, std::string String2, std::string String3){
std::string::size_type Pos(String1.find(String2));
while (Pos != std::string::npos){
String1.replace(Pos, String2.length(), String3);
Pos = String1.find(String2, Pos + String3.length());
}
return String1;
}
void dataByPylab(double x0, double xn){
std::ofstream ofs("dataByPylab.py");
ofs << "import numpy as np" << std::endl;
ofs << "import pylab" << std::endl;
ofs << cv::format("x = np.linspace(%f, %f, 100)", x0, xn) << std::endl;
ofs << "y = np.sin(x)" << std::endl;
ofs << "pylab.figure(1)" << std::endl;
ofs << "pylab.plot(x, y)" << std::endl;
ofs << "pylab.savefig('dataByPylab.png')" << std::endl;
}
void dataByOpenCV(cv::Mat mat){
// cv::format(mat, "numpy")はOpenCV2.4系統にはあるが、今のところOpenCV3系統には見かけなかった。
// 出力中にある"type="は、"dtype="でないと、numpyが解釈に失敗する。
// しかたがないので、もう一度読み直して、文字列の置換をしている。
std::ofstream ofs("dataByOpenCV_bug.py");
ofs << "import cv2" << std::endl;
ofs << "from numpy import *" << std::endl;
ofs << "import pylab" << std::endl;
ofs << "gray = " << cv::format(mat, "numpy") << std::endl;
ofs << "pylab.figure(1)" << std::endl;
ofs << "pylab.subplot(2,2,1)" << std::endl;
ofs << "pylab.imshow(gray)" << std::endl;
ofs << "pylab.subplot(2,2,2)" << std::endl;
ofs << "pylab.hist(gray)" << std::endl;
ofs << "pylab.savefig('dataByOpenCV.png')" << std::endl;
std::ifstream ifs("dataByOpenCV_bug.py");
std::ofstream ofs2("dataByOpenCV.py");
std::string str;
while (getline(ifs, str)){
str = Replace(str, "type=", "dtype=");
ofs2 << str << std::endl;
}
}
int main(int argc, char* arcv[]){
dataByPylab(-10.0, 20.0);//add parametr to plot script
system("python dataByPylab.py");
cv::Mat img = cv::imread("lena.jpg",0);//read as grayscale
dataByOpenCV(img);
system("python dataByOpenCV.py");
exit(1);
}
結果は、レナの画像と、画像のヒストグラムの表示になります。
####追記
Pythonのスクリプトをsystem()関数で別プロセスにすることなしに実行する方法をネットから見つけましたので、それを元に書いた版を追記します。まだ、自分のやりたいようなインタフェースになっていない。
cpp:callPython.cpp
#include <Python.h>
#include <stdio.h>
int main()
{
double x0 = -10.0;
double xn = 20.0;
char line[256];
sprintf(line, "x = np.linspace(%f, %f, 100)", x0, xn);
Py_Initialize();
PyRun_SimpleString("import numpy as np");
PyRun_SimpleString("import pylab");
PyRun_SimpleString(line);
PyRun_SimpleString("y = np.sin(x)");
PyRun_SimpleString("pylab.figure(1)");
PyRun_SimpleString("pylab.plot(x, y)");
PyRun_SimpleString("pylab.savefig('dataByPylab.png')");
PyRun_SimpleString("pylab.show()");
Py_Exit(0);
return 0;
}
####さらに追記
こうすると、もう少し一般化できる。
#include <Python.h>
#include <stdio.h>
#include <vector>
#include <iostream>
#include <string>
/**
* @brief pythonのスクリプトを実行する。
* @pram[in] lines
*/
void runPythonLines(const std::vector<std::string> &lines){
Py_Initialize();
for (unsigned int i = 0; i < lines.size(); i++){
std::cout << lines[i] << std::endl;
PyRun_SimpleString(lines[i].c_str());
}
Py_Exit(0);
}
int main()
{
double x0 = -10.0;
double xn = 20.0;
char line[256];
sprintf(line, "x = np.linspace(%f, %f, 100)", x0, xn);
std::vector<std::string> lines{
"import numpy as np",
"import pylab",
line,
"y = np.sin(x)",
"pylab.figure(1)",
"pylab.plot(x, y)",
"pylab.savefig('dataByPylab.png')",
"pylab.show()"
};
runPythonLines(lines);
return 0;
}
C++からmatplotlibのグラフ描画機能を使うヘッダライブラリ: matplotlib-cpp
[C++のコードから簡単にmatplotlibを使ってグラフを作成する方法]
(http://myenigma.hatenablog.com/entry/2016/01/16/093912)