diff options
-rw-r--r-- | annotator.conf | 1 | ||||
-rw-r--r-- | src/labeller.cc | 6 | ||||
-rw-r--r-- | src/labeller.h | 6 | ||||
-rw-r--r-- | src/settings.cc | 19 | ||||
-rw-r--r-- | src/settings.h | 1 | ||||
-rw-r--r-- | src/ui.cc | 28 |
6 files changed, 56 insertions, 5 deletions
diff --git a/annotator.conf b/annotator.conf index d89676d..6ec3ff2 100644 --- a/annotator.conf +++ b/annotator.conf @@ -1 +1,2 @@ labels = {"saccade", "blink", "head move start", "head move end", "look down start", "look down end"} +rectangles = {"face"} diff --git a/src/labeller.cc b/src/labeller.cc index 32f69c9..f7fa69e 100644 --- a/src/labeller.cc +++ b/src/labeller.cc @@ -6,6 +6,7 @@ namespace backend { struct labeller_impl { std::vector<std::string> labels; + std::vector<std::string> rectangleLabels; std::vector<label> annotations; // Bool in undo/redo buffers is whether was applied or deleted std::vector<std::pair<bool, label>> undoBuffer; @@ -30,6 +31,7 @@ namespace backend { labeller::labeller(const std::filesystem::path& savepath) { data = std::shared_ptr<labeller_impl>(new labeller_impl); data->labels = settings::getLabels(); + data->rectangleLabels = settings::getRectangleLabels(); data->savepath = savepath; if(std::filesystem::directory_entry(savepath).exists()) { load(savepath, *data); @@ -56,6 +58,10 @@ namespace backend { return data->labels; } + std::vector<std::string> labeller::getRectangleLabels() const { + return data->rectangleLabels; + } + void appLab(std::vector<label>& annotations, label lab) { annotations.push_back(lab); } diff --git a/src/labeller.h b/src/labeller.h index 4248e2a..e0dc090 100644 --- a/src/labeller.h +++ b/src/labeller.h @@ -8,11 +8,16 @@ namespace backend { struct labeller_impl; + struct rect { + int x1=0, x2=0, y1=0, y2=0; + }; + struct label { label() {} label(const std::string& name, double time) : name(name), time(time) {} std::string name; double time; + rect location; }; class labeller { @@ -20,6 +25,7 @@ namespace backend { labeller(const std::filesystem::path& savepath); std::pair<label, label> getSurrounding(double time) const; std::vector<std::string> getLabels() const; + std::vector<std::string> getRectangleLabels() const; void applyLabel(std::string name, double time); void deleteLabel(double time); // Deletes closest to time, last added if ties void undo(); diff --git a/src/settings.cc b/src/settings.cc index d19acde..7004e1d 100644 --- a/src/settings.cc +++ b/src/settings.cc @@ -5,9 +5,9 @@ #include <stdexcept> namespace settings { - std::vector<std::string> getLabels() { + std::vector<std::string> readVector(std::string heading) { cfg_opt_t opts[] = { - CFG_STR_LIST("labels", NULL, CFGF_NONE), + CFG_STR_LIST(heading.c_str(), NULL, CFGF_NONE), CFG_END() }; cfg_t *cfg = cfg_init(opts, CFGF_IGNORE_UNKNOWN); @@ -17,12 +17,21 @@ namespace settings { try { std::vector<std::string> ret; std::size_t i; - for(i = 0; i < cfg_size(cfg, "labels"); i++) { - ret.push_back(cfg_getnstr(cfg, "labels", i)); + for(i = 0; i < cfg_size(cfg, heading.c_str()); i++) { + ret.push_back(cfg_getnstr(cfg, heading.c_str(), i)); } return ret; } catch(std::exception& e) { - throw std::runtime_error("Cannot find 'labels' in configuration file"); + throw std::runtime_error("Cannot find '" + heading + "' in configuration file"); } } + + std::vector<std::string> getLabels() { + return readVector("labels"); + } + + std::vector<std::string> getRectangleLabels() { + return readVector("rectangles"); + } } + diff --git a/src/settings.h b/src/settings.h index 3b3ad71..2aa93ae 100644 --- a/src/settings.h +++ b/src/settings.h @@ -4,4 +4,5 @@ namespace settings { std::vector<std::string> getLabels(void); + std::vector<std::string> getRectangleLabels(void); } @@ -73,6 +73,32 @@ namespace frontend { return false; } + void mouseCallback(int event, int x, int y, int flags, void* userdata) { + // userdata is actually a &shared_ptr<ui_impl> + shared_ptr<ui_impl> data = (shared_ptr<ui_impl>) *userdata; + static bool mouseDown = false; + // We're interested in left button down/up and movement when down + if(event == cv::EVENT_LBUTTONDOWN) { + // If the current frame doesn't have a rectangle label, then make one + mouseDown = true; + double time = data->pb->getTime() + auto labs = data->llr->getSurrounding(time); + backend::label current; + if(labs.first.time == time) { + current = labs.first; + } else if(labs.second.time == time) { + current = labs.second; + } else { + + } + } else if(event == cv::EVENT_LBUTTONUP) { + // Mouse is no longer down + mouseDown = false; + } else if(event == cv::EVENT_MOUSEMOVE) { + // If the mouse is down, update x2 and y2 of current window + } + } + void ui::begin() { std::cout << "Playing a video that's " << data->pb->getMaxFrame() << " frames (" << data->pb->getMaxTime() << " seconds) long." << std::endl; std::cout << "Annotations:" << std::endl; @@ -84,6 +110,8 @@ namespace frontend { struct winsize size; ioctl(STDOUT_FILENO, TIOCGWINSZ, &size); int cols = size.ws_col; + // Register mouse callback + cv::setMouseCallback("Video", mouseCallback, &data); while(true) { data->pb->display("Video"); data->pb->interFrameSleep(); |