#include "MultiTracker.h"
#include "VideoReader.h"
#include "SharedPtr.h"
+#include "WorkerThread.h"
namespace suanzi{
class EngineObserver;
TK_DECLARE_PTR(Engine);
+TK_DECLARE_PTR(MultiTracker);
+
+struct Person;
class Engine
{
virtual ~Engine();
virtual void start();
+ //virtual void getCurrentCount();
+ // virtual void capture(bool bb = false);
void addObserver(EngineObserver* o);
void setVideoSrc(VideoSrcType type, const std::string& url);
+protected:
+ friend class MultiTracker;
+ void onStatusChanged();
+ void onPersonsIn(const std::vector<Person>& p);
+ void onPersonsOut(const std::vector<Person>& p);
+
private:
Engine();
void run();
+ WorkerThread eventThread {"EventThread"};
DetectorPtr detector;
MultiTrackerPtr multiTracker;
std::set<EngineObserver *> observer_list;
- //std::string videoSrc;
VideoReaderPtr reader;
};
Gender gender = Female;
Ages age = Kid;
- std::string ageToString (Ages age){
+ std::string ageToString (Ages age) const {
switch (age){
case Kid: return "Kid";
case Teenager: return "Teenager";
}
}
- std::string toString(){
+ std::string toString() const {
std::stringstream ss;
ss << "Person: id=" << id << ". Gender:" << (gender == Gender::Male ? "Male" : "Female" ) <<
". Age: " << ageToString(age);
class EngineObserver
{
public:
- //virtual void onPersonIn(std::set<Person> persons) = 0;
- virtual void onPersonIn(Person& p) = 0;
- virtual void onPersonOut(Person& p) = 0;
+ virtual void onPersonsIn(const std::vector<Person>& p) = 0;
+ virtual void onPersonsOut(const std::vector<Person>& p) = 0;
};
} // namespace suanzi
#include "PredictorWrapper.h"
#include <opencv2/opencv.hpp>
#include <utility>
+#include "Engine.h"
namespace suanzi {
TK_DECLARE_PTR(Patch);
TK_DECLARE_PTR(MultiTracker);
TK_DECLARE_PTR(Tracker);
+ TK_DECLARE_PTR(Engine);
class MultiTracker
{
public:
- MultiTracker();
+ MultiTracker(EngineWPtr e);
virtual ~MultiTracker();
void update(unsigned int total, const Detection* d, const cv::Mat& image);
double distance(TrackerPtr t, const cv::Mat& image, const Detection& d);
PredictorWrapperPtr predictor;
cv::HOGDescriptor descriptor;
+ EngineWPtr engine;
};
class Patch
TK_DECLARE_PTR(VideoReaderFactory);
TK_DECLARE_PTR(VideoReader);
TK_DECLARE_PTR(URLReader);
+ TK_DECLARE_PTR(Engine);
class VideoReaderFactory
{
private:
VideoSrcType type;
+ EngineWPtr engine;
protected:
std::string url;
--- /dev/null
+#ifndef _WORKER_THREAD_H
+#define _WORKER_THREAD_H
+
+#include <string>
+#include <thread>
+#include <queue>
+#include <mutex>
+#include <condition_variable>
+#include "SharedPtr.h"
+
+namespace suanzi {
+
+class WorkItem
+{
+public:
+ virtual ~WorkItem(){}
+ virtual void run(){}
+
+protected:
+ WorkItem(){}
+};
+
+TK_DECLARE_PTR(WorkItem);
+
+class WorkerThread
+{
+public:
+ WorkerThread(const std::string& name);
+ ~WorkerThread();
+ void enqueue(WorkItemPtr w);
+ void enqueue(WorkItem* w);
+
+private:
+ std::string m_name;
+ std::thread m_thread;
+ void run();
+ std::condition_variable m_cond;
+ std::mutex m_mutex;
+ std::queue<WorkItemPtr> m_queue;
+};
+
+}
+
+
+#endif // _WORKER_THREAD_H
class Callback : public EngineObserver
{
- void onPersonIn(Person& p){
- LOG_DEBUG(TAG, "OnPersonIn " << p.toString())
-
+ void onPersonsIn(const std::vector<Person>& p){
+ LOG_DEBUG(TAG, "onPersonsIn");
+ for (const auto& i : p){
+ LOG_DEBUG(TAG, "OnPersonIn " << i.toString());
+ }
};
- void onPersonOut(Person& p) {
- LOG_DEBUG(TAG, "OnPersonIn " << p.toString())
+ void onPersonsOut(const std::vector<Person>& p) {
+ LOG_DEBUG(TAG, "onPersonsOut");
+ for (const auto& i : p){
+ LOG_DEBUG(TAG, "OnPersonOut " << i.toString());
+ }
};
};
#include <mutex>
#include <thread>
+#include <condition_variable>
#include "Engine.h"
#include "Logger.h"
#include "PredictorWrapper.h"
using namespace suanzi;
+using namespace std;
static const std::string TAG = "Engine";
-
static std::mutex g_mutex;
static EngineWPtr g_instance;
+typedef std::shared_ptr<std::vector<Person>> PersonsInfoPtr;
+// class Engine
EnginePtr Engine::create()
{
LOG_DEBUG(TAG, "create");
Engine::Engine()
{
detector = std::make_shared<Detector>();
- multiTracker = std::make_shared<MultiTracker>();
}
Engine::~Engine()
void Engine::start()
{
LOG_DEBUG(TAG, "start");
+ multiTracker = std::make_shared<MultiTracker>(g_instance);
if (!reader){
LOG_ERROR(TAG, "reader is null. exit");
return;
{
observer_list.insert(observer);
}
+
+
+// WorkItem class for event thread
+class PersonInEventWorkItem : public WorkItem
+{
+public:
+ PersonInEventWorkItem(std::set<EngineObserver*> obs, PersonsInfoPtr info) : obs(obs), info(info){
+ }
+ ~PersonInEventWorkItem(){}
+ void run (){
+ for (auto o : obs){
+ o->onPersonsIn(*(info.get()));
+ }
+ }
+private:
+ std::set<EngineObserver*> obs;
+ PersonsInfoPtr info;
+};
+
+class PersonOutEventWorkItem : public WorkItem
+{
+public:
+ PersonOutEventWorkItem(std::set<EngineObserver*> obs, PersonsInfoPtr info) : obs(obs), info(info){
+ }
+ ~PersonOutEventWorkItem(){}
+ void run (){
+ for (auto o : obs){
+ o->onPersonsIn(*(info.get()));
+ }
+ }
+private:
+ std::set<EngineObserver*> obs;
+ PersonsInfoPtr info;
+};
+
+void Engine::onPersonsOut(const std::vector<Person>& p)
+{
+ PersonsInfoPtr pp = std::make_shared<std::vector<Person>>(p);
+ eventThread.enqueue(new PersonOutEventWorkItem(this->observer_list, pp));
+}
+
+void Engine::onPersonsIn(const std::vector<Person>& p)
+{
+ PersonsInfoPtr pp = std::make_shared<std::vector<Person>>(p);
+ eventThread.enqueue(new PersonInEventWorkItem(this->observer_list, pp));
+}
+
+void Engine::onStatusChanged()
+{
+ Person pm, p2;
+ std::vector<Person> ps;
+ ps.push_back(pm);
+ ps.push_back(p2);
+ onPersonsOut(ps);
+}
#define MaxCost 100000
-MultiTracker::MultiTracker()
+MultiTracker::MultiTracker(EngineWPtr e)
+: engine(e)
{
LOG_DEBUG(TAG, "init - loading model.pkl");
predictor = PredictorWrapper::create("./python/model.pkl");
trackers.clear();
}
+static double calc_iou_ratio(const Detection& d1, const Detection& d2)
+{
+ // TODO
+ return 0.1;
+}
static std::vector<double> similarity(const PatchPtr p1, const PatchPtr p2)
{
double center_distance = sqrt(pow((d1.center_x - d2.center_x), 2) + pow((d1.center_y - d2.center_y), 2));
feature.push_back(center_distance / (d1.width + d1.height + d2.width + d2.height) * 4);
- //TODO
- double iou_ratio = 0.03;
+ double iou_ratio = calc_iou_ratio(d1, d2);
feature.push_back(iou_ratio);
return feature;
return prob;
}
+static long cc = 0;
+
void MultiTracker::update(unsigned int total, const Detection* detections, const Mat& image)
{
+ //////
+ if ((cc % 50) == 0){
+ if (EnginePtr e = engine.lock()){
+ e->onStatusChanged();
+ }
+ }
+ cc++;
+
+ //////
int row = trackers.size();
int col = total;
Eigen::MatrixXi cost_matrix = Eigen::MatrixXi::Zero(row, col);
for (int i = 0; i < row; i++){
for (int j = 0; j < col; j++){
- // TODO
- cost_matrix(i, j) = distance(trackers[i], image, detections[j]);
+ //if (calc_iou_ratio(trackers[i], detections[j]) < -0.1)
+ // cost_matrix(i, j) = MaxCost;
+ //else
+ cost_matrix(i, j) = distance(trackers[i], image, detections[j]);
}
}
- // assignment
Eigen::VectorXi tracker_inds, bb_inds;
linear_sum_assignment(cost_matrix, tracker_inds, bb_inds);
// handle unmatched trackers
- vector<TrackerPtr> unmatched_trackers;
+ //vector<TrackerPtr> unmatched_trackers;
for (int i = 0; i < row; i++){
if (!(tracker_inds.array() == i).any()){
- unmatched_trackers.push_back(trackers[i]);
+ trackers[i]->updateState(image);
}
}
- for (auto t : unmatched_trackers){
- t->updateState(image);
- }
// handle unmatched detections
vector<int> unmatched_detection;
float sranges[] = {0, 256};
const float* ranges[] = {hranges, sranges};
calcHist(&hsv, 1, channels, Mat(), hist, 2, histSize, ranges, true, false);
- Size sm = hist.size();
patch->image_crop = im.clone();
patch->detection = detect;
--- /dev/null
+#include "WorkerThread.h"
+#include <iostream>
+#include "Logger.h"
+
+using namespace suanzi;
+using namespace std;
+
+static const std::string TAG = "WorkerThread";
+
+WorkerThread::WorkerThread(const std::string& name)
+: m_name(name)
+, m_thread (thread(&WorkerThread::run, this))
+{
+}
+
+WorkerThread::~WorkerThread()
+{
+}
+
+void WorkerThread::run()
+{
+ LOG_DEBUG(TAG, "start workerThread " + m_name);
+ WorkItemPtr workItem;
+ while(true){
+ unique_lock<mutex> l(m_mutex);
+ if (!m_queue.empty()){
+ workItem = m_queue.front();
+ m_queue.pop();
+ l.unlock();
+ workItem->run();
+ LOG_DEBUG(TAG, " ------ Queue Size: " << m_queue.size());
+ } else {
+ m_cond.wait(l);
+ }
+ }
+ LOG_DEBUG(TAG, "End workerThread " + m_name);
+}
+
+void WorkerThread::enqueue(WorkItemPtr item)
+{
+ unique_lock<mutex> l(m_mutex);
+ m_queue.push(item);
+ m_cond.notify_one();
+}
+
+void WorkerThread::enqueue(WorkItem* w)
+{
+ WorkItemPtr p (w);
+ enqueue(p);
+}