- log4cpp : logger utils
- opencv
- eigen : matrix library of C++
+- boost-python
+ - `apt-get install libpython-dev python-dev`
+ - build boost with python
+ - `pip install scipy numpy sklearn`
+<https://www.boost.org/doc/libs/1_67_0/libs/python/doc/html/building/installing_boost_python_on_your_.html>
+
+As boost has already
+
+`sudo ./b2 install link=static cxxflags=-fPIC --with-filesystem --with-test --with-log --with-program_options --with-python`
`apt-get install liblog4cpp5-dev libopencv-dev libeigen3-dev`
env = Environment(CXX="g++",
CPPPATH=['#include'],
- CCFLAGS=['-Wall', '-std=c++11', '-O2'])
+ CCFLAGS=['-Wall', '-std=c++11', '-O3'])
+
+env['ENV']['TERM'] = os.environ['TERM']
env.Append(LIBS = ['tracker'])
env.ParseConfig("pkg-config --libs opencv log4cpp")
-env.Append(LIBS = ['pthread'])
+env.ParseConfig("python-config --cflags --libs")
+env.Append(LIBS = ['pthread', 'boost_python'])
env.Append(LIBPATH=['#.'])
-obj = env.Object('main.cpp')
-
env.StaticLibrary('tracker', Glob('src/*.cpp'))
+#tracker = env.StaticLibrary('tracker', Glob('src/*.cpp'))
+#Depends(tracker, Glob('src/*.cpp'))
-env.Program("main", list(obj))
+env.Program("main", 'main.cpp')
+#main = env.Program("main", 'main.cpp')
+#Depends(main, ["main.cpp", 'libtracker.a'])
if GetOption('all'):
SConscript('test/SConscript', exports='env')
public:
Detector();
virtual ~Detector();
- unsigned int detect(cv::Mat& frame, Detection* detections){return 1;}
+ // TODO
+ unsigned int detect(const cv::Mat& frame, Detection* detections){return 1;}
};
struct Detection
namespace suanzi {
TK_DECLARE_PTR(Metrics);
- TK_DECLARE_PTR(Patch);
+ //TK_DECLARE_PTR(Patch);
+ struct Patch;
class Metrics
{
public:
~Metrics(){}
const static long int MaxCost = 100000;
const static int MaxPatch = 5;
+ void similarity(const Patch& p1, const Patch& p2);
+
private:
cv::HOGDescriptor descriptor = {cv::Size(64, 128), cv::Size(16, 16), cv::Size(8, 8), cv::Size(8, 8), 9};
};
- class Patch
+ struct Patch
{
- public:
- Patch(){};
- ~Patch(){};
+ // bb_ltrb
+
+ //
+ // image_crop
+ cv::Mat image_crop;
+ //
+ // features
+
};
}
private:
MetricsPtr metrics;
- std::set<TrackerPtr> trackers;
+ std::vector<TrackerPtr> trackers;
int max_id = 0;
void addTracker(TrackerPtr t);
TrackerPtr createTracker(int id = 0);
--- /dev/null
+#ifndef _PREDICTOR_H_
+#define _PREDICTOR_H_
+
+#include "SharedPtr.h"
+#include <boost/python.hpp>
+
+namespace suanzi {
+
+ TK_DECLARE_PTR(PredictorWrapper);
+
+ typedef boost::python::object PY_FUN;
+
+ class PredictorWrapper
+ {
+ public:
+ static PredictorWrapperPtr create(const std::string& fname);
+ ~PredictorWrapper(){}
+ void dump() { this->dump_func(); }
+ void predict() { this->predict_func();}
+
+ private:
+ PredictorWrapper(const std::string& fname);
+ static PredictorWrapperWPtr instance;
+
+ PY_FUN dump_func;
+ PY_FUN predict_func;
+
+ };
+
+}
+
+#endif // _PREDICTOR_H_
// @return the cost of the assignment
int linear_sum_assignment(const Eigen::MatrixXi& cost_matrix, Eigen::VectorXi& row_ind, Eigen::VectorXi& col_ind);
+
+// Computes the consine distance between u and v
+// https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.cosine.html#scipy.spatial.distance.cosine
+double distance_cosine(const Eigen::VectorXd& u, const Eigen::VectorXd& v);
+
+// Computes the Euclidean distance between u and v
+// https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.euclidean.html#scipy.spatial.distance.euclidean
+double distance_euclidean(const Eigen::VectorXd& u, const Eigen::VectorXd& v);
+
#endif // _HUNGARIAN_H_
};
};
-
-
int main(int argc, char* argv[])
{
initLogger("./config/log4cpp.properties");
LOG_DEBUG(TAG, "==================================");
-
EnginePtr e = Engine::create();
e->addObserver(new Callback());
e->setVideoSrc(VideoSrcType::URL, "rtsp://192.168.1.75:554/stream1");
e->start();
-
e->destroy();
+
log4cpp::Category::shutdown();
}
--- /dev/null
+(lp1
+ccopy_reg
+_reconstructor
+p2
+(csklearn.linear_model.logistic
+LogisticRegression
+p3
+c__builtin__
+object
+p4
+NtRp5
+(dp6
+S'warm_start'
+p7
+I00
+sS'C'
+F1
+sS'n_jobs'
+p8
+I1
+sS'verbose'
+p9
+I0
+sS'fit_intercept'
+p10
+I01
+sS'solver'
+p11
+S'liblinear'
+p12
+sS'classes_'
+p13
+cnumpy.core.multiarray
+_reconstruct
+p14
+(cnumpy
+ndarray
+p15
+(I0
+tS'b'
+tRp16
+(I1
+(L2L
+tcnumpy
+dtype
+p17
+(S'i4'
+I0
+I1
+tRp18
+(I3
+S'<'
+NNNI-1
+I-1
+I0
+tbI00
+S'\x00\x00\x00\x00\x01\x00\x00\x00'
+tbsS'n_iter_'
+p19
+g14
+(g15
+(I0
+tS'b'
+tRp20
+(I1
+(L1L
+tg17
+(S'i4'
+I0
+I1
+tRp21
+(I3
+S'<'
+NNNI-1
+I-1
+I0
+tbI00
+S'\x0b\x00\x00\x00'
+tbsS'intercept_scaling'
+p22
+I1
+sS'penalty'
+p23
+S'l2'
+p24
+sS'multi_class'
+p25
+S'ovr'
+p26
+sS'random_state'
+p27
+NsS'_sklearn_version'
+p28
+S'0.19.0'
+p29
+sS'dual'
+p30
+I00
+sS'tol'
+p31
+F0.0001
+sS'coef_'
+p32
+g14
+(g15
+(I0
+tS'b'
+tRp33
+(I1
+(L1L
+L8L
+tg17
+(S'f8'
+I0
+I1
+tRp34
+(I3
+S'<'
+NNNI-1
+I-1
+I0
+tbI00
+S'\xe2\x06dQ\xb5\xd1\x11@\xb4\x06\x1c.{`\xfb?\xea}\x1c\xea \xb7\xbb?TQz6\x17\r\xdc\xbfc}J\xd5\xfb\x81\x0c@\x92\xe9\xf7\r/\xa3\xf4\xbf\xf5\xc9mcQ\xfe\x01\xc0:\xa9`\xd4\xd3\xfb\xf7\xbf'
+tbsS'intercept_'
+p35
+g14
+(g15
+(I0
+tS'b'
+tRp36
+(I1
+(L1L
+tg34
+I00
+S'\xee\xa1\x95\x9f\xd3\xeb}?'
+tbsS'max_iter'
+p37
+I100
+sS'class_weight'
+p38
+Nsbag2
+(g3
+g4
+NtRp39
+(dp40
+g7
+I00
+sS'C'
+F1
+sg8
+I1
+sg9
+I0
+sg10
+I01
+sg11
+g12
+sg13
+g14
+(g15
+(I0
+tS'b'
+tRp41
+(I1
+(L2L
+tg18
+I00
+S'\x00\x00\x00\x00\x01\x00\x00\x00'
+tbsg19
+g14
+(g15
+(I0
+tS'b'
+tRp42
+(I1
+(L1L
+tg21
+I00
+S'\x0c\x00\x00\x00'
+tbsg22
+I1
+sg23
+g24
+sg25
+g26
+sg27
+Nsg28
+g29
+sg30
+I00
+sg31
+F0.0001
+sg32
+g14
+(g15
+(I0
+tS'b'
+tRp43
+(I1
+(L1L
+L16L
+tg34
+I00
+S'4\xf7\\\xbf\xe6$\x0c@biKO\x01\x00\xf6?\xff\x82\x07*\xe9\xf7\xd2?\xb8\xe3\xd7|\x14O\xdf\xbfK<B\xd8\x97\x8b\x01@\xd0G8]\x0b\xb5\xef\xbf8\x1e\xd3\xafZ\xf5\x0b\xc0.\x8b\xd0\x9cm\xf2\xe7\xbf$\x89\xdfM-5\xfa?\x14`\x04C4\xc6\xe0?L\xc8I\xc1\xc5\xb1\xd5?\x96%\xb0\xca\xe6\xf3\xa9\xbf\xb7\x93B\x0eD\xe1\xf6?\xb2@k\xd5sK\xa6?r\x8bVe\xbb\xe1\xf7?\xcb\xaa\x86\n/\x9e\xda\xbf'
+tbsg35
+g14
+(g15
+(I0
+tS'b'
+tRp44
+(I1
+(L1L
+tg34
+I00
+S'\\\x8c\xb8\x7f`\xbe\xe1\xbf'
+tbsg37
+I100
+sg38
+Nsbag2
+(g3
+g4
+NtRp45
+(dp46
+g7
+I00
+sS'C'
+F1
+sg8
+I1
+sg9
+I0
+sg10
+I01
+sg11
+g12
+sg13
+g14
+(g15
+(I0
+tS'b'
+tRp47
+(I1
+(L2L
+tg18
+I00
+S'\x00\x00\x00\x00\x01\x00\x00\x00'
+tbsg19
+g14
+(g15
+(I0
+tS'b'
+tRp48
+(I1
+(L1L
+tg21
+I00
+S'\r\x00\x00\x00'
+tbsg22
+I1
+sg23
+g24
+sg25
+g26
+sg27
+Nsg28
+g29
+sg30
+I00
+sg31
+F0.0001
+sg32
+g14
+(g15
+(I0
+tS'b'
+tRp49
+(I1
+(L1L
+L24L
+tg34
+I00
+S'\xe2\xd9\xb1\xd9!\xc5\x08@\xb9\xbf\xc0T!\xde\xf5?\x0fvN\xa2%\xe2\xd1?\x80\xda\xe1n\xff\x8f\xe0\xbf\x8bu\xd5wq\xf4\xfe?o\x81k\x01\xff\x93\xec\xbf\xcdQ\xac\x13\x14\xc0\r\xc0\x84\xc2\x8f58\x98\xda\xbf\xab\x87.\xe6-G\xf0?\x90\xb6wI\x10\xb8\xe2?\x19v\xe3\x0e>S\xd5?\x10\x00\xaf\xd6!\xa7\x81?\xb7\xbe\xa9,\xb0k\xec?\xf7\x18\x82?\xf8\xa6\xc2\xbfU\xe8Ni\xf2\xa2\xfa?\xff\x84E\xf7!\x98\xdf\xbf\xbb\x91N=\x86\xfd\xf1?\xd7/\xef\xb4\xb3\xc2\xe0?\x0c\x96\x13\x04Al\xd4?\xa4\xd3a\x12\x1d\xce\xc1\xbf\xd2(9\xcd\x9dh\xef?H /\xedC\xcf\xda?J\n\xa1\x1fD\x98\xc1?m%\xc3&\xaa;\xdb?'
+tbsg35
+g14
+(g15
+(I0
+tS'b'
+tRp50
+(I1
+(L1L
+tg34
+I00
+S'\x80\x1d\xf1\xf3(\x89\xe3\xbf'
+tbsg37
+I100
+sg38
+Nsbag2
+(g3
+g4
+NtRp51
+(dp52
+g7
+I00
+sS'C'
+F1
+sg8
+I1
+sg9
+I0
+sg10
+I01
+sg11
+g12
+sg13
+g14
+(g15
+(I0
+tS'b'
+tRp53
+(I1
+(L2L
+tg18
+I00
+S'\x00\x00\x00\x00\x01\x00\x00\x00'
+tbsg19
+g14
+(g15
+(I0
+tS'b'
+tRp54
+(I1
+(L1L
+tg21
+I00
+S'\r\x00\x00\x00'
+tbsg22
+I1
+sg23
+g24
+sg25
+g26
+sg27
+Nsg28
+g29
+sg30
+I00
+sg31
+F0.0001
+sg32
+g14
+(g15
+(I0
+tS'b'
+tRp55
+(I1
+(L1L
+L32L
+tg34
+I00
+S'N+\xd0R\xed\x8f\x06@\xe0\x9f\xab\xc1\x16\x8f\xf4?\xbe+\xed&\xea\r\xd0?\xb6\xfc,\x074\x8b\xe2\xbf\x8f>f\x8e\xa3\x07\x01@\xe7lu\xbbn\x9b\xf1\xbf>[@s\xc7:\x0e\xc0\x86"\xb8\xaa,\xdb\x85?\xec\xddMJ)\x1a\xea?\xec*\xe1\xfc.\xc5\xd4?\t\xef,\xd8\xf41\xd4?J[\'\x8fP\x14\xab\xbf\x8fA\xea\xd8\xf0b\xe6?3\x8a|\t1\x1c\xc1\xbfn6\xdf\x96\xc6\xe2\xfa?&\x04\x82\x14\x1f5\xdb\xbf\xcc+\x18\xfa\x9f\x0b\xea?\xc6\x1c\xcf\xec\xcf\xa0\xd8?\n\xa5\xbe\xb2\xd7\x1c\xd4?\x82c M\x85\xf6\xbb\xbf\x1b\xb6\x17\x972"\xe1?U\x90/\x04\x8f\xdb\xd2?\x93\xceVv\xe2\x9f\x9c?$p\x16#o\x93\xd7?\x0e\x1a\xfe=\xe7\xc3\xea?h\xfa\xee\xd04y\xdf?\xf8\xad\xff\x86\xf0\xc4\xd1?\xa4N\xb3<87\xb4?\xb8\xc9\xce@\xdc(\xc4?HSA\x9b\xd1I\xcb?g\n\xd9tn\x10\xd0?t\x9db\x95u\xd0\xdc?'
+tbsg35
+g14
+(g15
+(I0
+tS'b'
+tRp56
+(I1
+(L1L
+tg34
+I00
+S'\xbc;\xceA\xf6\xc7\xe2\xbf'
+tbsg37
+I100
+sg38
+Nsbag2
+(g3
+g4
+NtRp57
+(dp58
+g7
+I00
+sS'C'
+F1
+sg8
+I1
+sg9
+I0
+sg10
+I01
+sg11
+g12
+sg13
+g14
+(g15
+(I0
+tS'b'
+tRp59
+(I1
+(L2L
+tg18
+I00
+S'\x00\x00\x00\x00\x01\x00\x00\x00'
+tbsg19
+g14
+(g15
+(I0
+tS'b'
+tRp60
+(I1
+(L1L
+tg21
+I00
+S'\x0e\x00\x00\x00'
+tbsg22
+I1
+sg23
+g24
+sg25
+g26
+sg27
+Nsg28
+g29
+sg30
+I00
+sg31
+F0.0001
+sg32
+g14
+(g15
+(I0
+tS'b'
+tRp61
+(I1
+(L1L
+L40L
+tg34
+I00
+S'\xd9\xfe\'\xeeW\xc4\x05@\x9f:b\xf1F\xa4\xf4?\xf28\xaf\xdc`\xd4\xc8?\xf5\xcb.\x85#\xa9\xe7\xbf6"e&G\xbb\x00@1\x833\xe4O\xa9\xf1\xbfEm\x1d\x8b\xb9\xdb\x0c\xc0\x83\xd6J\xe3Q|\xcd?\xa5\xd5?\x034"\xe5?\xd7d\x92\xaf\x8ev\xdc?\xe2U:|\xe0\xf9\xd1?\xcf>~0\xadm\xcb\xbf\x92D.n\xf6\'\xde?\x83\x90\x81\x07\xab\xa2\xd2\xbfn\x96L\x15W*\xfa?\xecC\xfaMtr\xdd\xbf4\r\xcew\x90\xad\xe7?\x10Wu\x18\x84"\xe2?\xe7m\xba\xb1pk\xd2?T\x84V\xe1V\x86\xbd\xbf\x82\x1b-\x0c\xb6H\xcf?\xe9F\x06{\x8dW\xc8?\xa5\xb5d\x0e\x1b\x11\xbe\xbf\x9f\xe4y4\xe5n\xd3?\xe0\xf8M\xb1\xff\xb5\xd9?)\xb1e\xc4\xb4\x02\xe0?\x04\xdb\x94\xe2\xfd\xa6\xd1?9\xa7\x04\x89\xff\x90\xbf?\xee\x8f\xab\x1d1\x1c\xc8\xbf&w\xf6X\xd0\x8f\xc1?\xf3\xdeI\xaa\xfc\x02\xb2?\xae\xbf\xa3Sj\xa0\xc1?\x83\xdb\xcf\rr\x0e\xec?\r\xe8\xb1k\xc9\x14\xe0?\x1b"j?o\xc8\xd2?\xdf9_W\xa7{\xcd?.\xbf&\xea\xa2\x1f\xda?\xbeno\xb3\xe8\xda\xb5?\x85&\xcbt\xd3r\xd0?\x04\xbb\xffur\xc1\xde?'
+tbsg35
+g14
+(g15
+(I0
+tS'b'
+tRp62
+(I1
+(L1L
+tg34
+I00
+S'\x90\xe2;h\x9e\xbf\xe2\xbf'
+tbsg37
+I100
+sg38
+Nsba.
\ No newline at end of file
--- /dev/null
+from sklearn.linear_model import LogisticRegression
+try:
+ import cPickle as pickle
+except:
+ import pickle
+
+
+predictors = None
+
+def init(fname = './model.pkl'):
+ global predictors
+ f = open(fname, 'rb')
+ predictors = pickle.load(f)
+ f.close()
+
+def dump():
+ global predictors
+ for i in predictors:
+ print i
+ print i.coef_
+
+
+def predict(index, features):
+ pp = predictors[index]
+ true_class = int(pp.classes_[1] == 1)
+ prob = pp.predict_proba([features])[0, true_class]
+ return prob
+
+
+if __name__ == '__main__':
+ init('./model.pkl')
+ dump()
+ feature=[1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2]
+ print predict(len(predictors) - 1, feature)
+
#include <thread>
#include "Engine.h"
#include "Logger.h"
+#include "PredictorWrapper.h"
using namespace suanzi;
void Engine::setVideoSrc(VideoSrcType type, const std::string& url)
{
+ PredictorWrapperPtr pp = PredictorWrapper::create("./python/model.pkl");
+
+ pp->dump();
+
// videoSrc = url;
- reader = VideoReaderFactory::createVideoReader(type, url);
+ //reader = VideoReaderFactory::createVideoReader(type, url);
+
}
void Engine::run()
+#include "Logger.h"
#include "Metrics.h"
using namespace suanzi;
}
}
+
+void Metrics::similarity(const Patch& p1, const Patch& p2)
+{
+}
#include "MultiTracker.h"
#include "Metrics.h"
#include <algorithm>
+#include "hungarian.h"
using namespace suanzi;
using namespace cv;
+using namespace Eigen;
MultiTracker::MultiTracker(MetricsPtr m) : metrics(m)
{
void MultiTracker::addTracker(TrackerPtr t)
{
- trackers.insert(t);
+ trackers.push_back(t);
}
void MultiTracker::removeTracker(TrackerPtr t)
{
- trackers.erase(t);
+// trackers.erase(t);
}
void MultiTracker::initNewTrackers(cv::Mat& iamge)
{
}
-
-void MultiTracker::update(unsigned int total, const Detection* d, const Mat& image)
+void calculate_edistance()
{
+}
- // correct_trackers
-
-
- //
-
-
-
-
-
-
+#define MaxCost 100000
+void MultiTracker::update(unsigned int total, const Detection* detections, const Mat& image)
+{
+ // correct_trackers
+ // Generate cost matrix
+ int row = trackers.size();
+ int col = total;
+ MatrixXi cost_matrix = MatrixXi::Zero(row, col);
+ for (int i = 0; i < row; i++){
+ for (int j = 0; j < col; j++){
+ TrackerPtr tracker = trackers[i];
+ Detection det = detections[j];
+
+ int cost = MaxCost;
+
+ // TODO
+ cost_matrix(i, j) = cost;
+ }
+ }
+
+ // assignment
+ VectorXi tracker_inds, bb_inds;
+ linear_sum_assignment(cost_matrix, tracker_inds, bb_inds);
+
+ // handle the result
+ vector<TrackerPtr> unmatched_trackers;
+ vector<Detection> unmatched_detection;
+ for (int i = 0; i < row; i++){
+ if (!(tracker_inds.array() == i).any()){
+ unmatched_trackers.push_back(trackers[i]);
+ }
+ }
+ for(int j = 0; j < col; j++){
+ if (!(bb_inds.array() == j).any()){
+ unmatched_detection.push_back(detections[j]);
+ }
+ }
- // Delete long lost trackers;
-// for (auto& t : trackers){
-// if (t->status == TrackerStatus::Delete)
-// trackers.erase(t);
-// }
-//
- // Update trackers using kalman filter
-// for(auto& t: trackers){
-// //t.bb_ltrb =
-// }
-//
- // associate trackers with detections
-// correctTrackers(this->metric, image);
// create new trackers for new detections
}
--- /dev/null
+#include "PredictorWrapper.h"
+#include <string>
+#include <iostream>
+
+namespace py = boost::python;
+
+using namespace std;
+using namespace suanzi;
+
+
+PredictorWrapperWPtr PredictorWrapper::instance;
+
+const static std::string PREDICTOR_PY_DIR = "./python";
+
+static std::string parse_python_exception();
+
+
+PredictorWrapperPtr PredictorWrapper::create(const std::string& fname)
+{
+ //if (instance == nullptr){
+ if (instance.lock()){
+ //instance = new PredictorWrapper(fname);
+ return PredictorWrapperPtr();
+ }
+ PredictorWrapperPtr ins (new PredictorWrapper(fname));
+ instance = ins;
+ return ins;
+}
+
+PredictorWrapper::PredictorWrapper(const std::string& fname)
+{
+ Py_Initialize();
+ try{
+ py::object main_module = py::import("__main__");
+ py::object main_namespace = main_module.attr("__dict__");
+ py::exec("import sys", main_namespace);
+ std::string cmd = "sys.path.insert(0, '" + PREDICTOR_PY_DIR + "')";
+ py::exec(cmd.c_str(), main_namespace);
+ //py::exec("sys.path.insert(0, '/home/debian/project/tracker/python')", main_namespace);
+ //py::exec("sys.path.insert(0, './python')", main_namespace);
+ py::object predictor_mod = py::import("predictor");
+ py::object predictor_init = predictor_mod.attr("init");
+ dump_func = predictor_mod.attr("dump");
+ predict_func = predictor_mod.attr("predict");
+
+ predictor_init(fname.c_str());
+ //predictor_dump();
+ //py::exec("import predictor", main_namespace);
+ } catch (boost::python::error_already_set const &){
+ std::string perror_str = parse_python_exception();
+ std::cout << "Error in Python: " << perror_str << std::endl;
+ }
+}
+
+static std::string parse_python_exception(){
+ PyObject *type_ptr = NULL, *value_ptr = NULL, *traceback_ptr = NULL;
+ // Fetch the exception info from the Python C API
+ PyErr_Fetch(&type_ptr, &value_ptr, &traceback_ptr);
+
+ // Fallback error
+ std::string ret("Unfetchable Python error");
+ // If the fetch got a type pointer, parse the type into the exception string
+ if(type_ptr != NULL){
+ py::handle<> h_type(type_ptr);
+ py::str type_pstr(h_type);
+ // Extract the string from the boost::python object
+ py::extract<std::string> e_type_pstr(type_pstr);
+ // If a valid string extraction is available, use it
+ // otherwise use fallback
+ if(e_type_pstr.check())
+ ret = e_type_pstr();
+ else
+ ret = "Unknown exception type";
+ }
+ // Do the same for the exception value (the stringification of the exception)
+ if(value_ptr != NULL){
+ py::handle<> h_val(value_ptr);
+ py::str a(h_val);
+ py::extract<std::string> returned(a);
+ if(returned.check())
+ ret += ": " + returned();
+ else
+ ret += std::string(": Unparseable Python error: ");
+ }
+ // Parse lines from the traceback using the Python traceback module
+ if(traceback_ptr != NULL){
+ py::handle<> h_tb(traceback_ptr);
+ // Load the traceback module and the format_tb function
+ py::object tb(py::import("traceback"));
+ py::object fmt_tb(tb.attr("format_tb"));
+ // Call format_tb to get a list of traceback strings
+ py::object tb_list(fmt_tb(h_tb));
+ // Join the traceback strings into a single string
+ py::object tb_str(py::str("\n").join(tb_list));
+ // Extract the string, check the extraction, and fallback in necessary
+ py::extract<std::string> returned(tb_str);
+ if(returned.check())
+ ret += ": " + returned();
+ else
+ ret += std::string(": Unparseable Python traceback");
+ }
+ return ret;
+}
+
}
return 4;
}
+
+////////////////////////////////////////////////////////////////////////////////
+double distance_cosine(const VectorXd& u, const VectorXd& v)
+{
+ return (1 - u.dot(v) / std::sqrt(u.dot(u) * v.dot(v)));
+}
+
+double distance_euclidean(const VectorXd& u, const VectorXd& v)
+{
+ VectorXd d = u - v;
+ return std::sqrt(d.dot(d));
+}
#include "hungarian.h"
#include "gtest/gtest.h"
+#include <cmath>
using namespace std;
using namespace Eigen;
EXPECT_TRUE(expect_row_ind == row_ind);
EXPECT_TRUE(expect_col_ind == col_ind);
}
+
+TEST(Distance, consine)
+{
+ Vector3d u, v;
+ u << 1, 0, 0;
+ v << 0, 1, 0;
+ double d = distance_cosine(u, v);
+ EXPECT_DOUBLE_EQ(d, 1.0);
+
+ u << 100, 0, 0;
+ v << 0, 1, 0;
+ d = distance_cosine(u, v);
+ EXPECT_DOUBLE_EQ(d, 1.0);
+
+ u << 1, 1, 0;
+ v << 0, 1, 0;
+ d = distance_cosine(u, v);
+ EXPECT_TRUE(std::abs(d - 0.2928932) < 0.0001);
+}
+
+TEST(Distance, euclidean)
+{
+ Vector3d u, v;
+ u << 1, 0, 0;
+ v << 0, 1, 0;
+ double d = distance_euclidean(u, v);
+ EXPECT_TRUE(std::abs(d - 1.41421356) < 0.0001);
+
+ u << 1, 1, 0;
+ v << 0, 1, 0;
+ d = distance_euclidean(u, v);
+ EXPECT_DOUBLE_EQ(d, 1.0);
+}