From 04e9d606dfa5616132c37c62ede24286b0ca8350 Mon Sep 17 00:00:00 2001 From: Ethan Rublee Date: Sat, 10 Sep 2011 20:07:56 -0700 Subject: [PATCH] This addresses and does close #11. --- modules/opencv/highgui/imshow.cpp | 181 +++++++++++++++++++++++------- samples/rescale.py | 20 ++++ 2 files changed, 161 insertions(+), 40 deletions(-) create mode 100755 samples/rescale.py diff --git a/modules/opencv/highgui/imshow.cpp b/modules/opencv/highgui/imshow.cpp index d76a392..817e56e 100644 --- a/modules/opencv/highgui/imshow.cpp +++ b/modules/opencv/highgui/imshow.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -23,12 +24,128 @@ namespace { *(x.second) = false; } - }; - } namespace ecto_opencv { + struct CloseWindow + { + CloseWindow(const std::string& name) + : + name(name) + { + } + void + operator()(const boost::signals2::connection& c) const + { + c.disconnect(); + cv::destroyWindow(name); + } + std::string name; + }; + + struct ImshowJob + { + ImshowJob(const cv::Mat& image, const std::string& name, bool full_screen, bool auto_size) + : + image(image), + name(name), + full_screen(full_screen), + auto_size(auto_size) + { + } + + void + operator()(const boost::signals2::connection& c) const + { + c.disconnect(); + if (full_screen) + { + cv::namedWindow(name, CV_WINDOW_KEEPRATIO); + cv::setWindowProperty(name, CV_WND_PROP_FULLSCREEN, true); + } + else if (auto_size) + { + cv::namedWindow(name, CV_WINDOW_KEEPRATIO); + } + cv::imshow(name, image); + } + const cv::Mat image; + std::string name; + bool full_screen, auto_size; + }; + + struct HighGuiRunner + { + typedef boost::signals2::signal sig_type; + typedef boost::function jop_type; + + HighGuiRunner() + : + lastKey(0xff) + { + t.reset(new boost::thread(boost::ref(*this))); + } + + ~HighGuiRunner() + { + t->interrupt(); + t->join(); + t.reset(); + } + + void + operator()() + { + while (!boost::this_thread::interruption_requested()) + { + jobs(); + lastKey = 0xff & cv::waitKey(10); + keys[lastKey] = true; + } + } + + void + post_job(const jop_type& s) + { + sig_type::extended_slot_type job(s); + jobs.connect_extended(job); + } + + bool + testKey(int time, unsigned char key, bool reset) + { + if (time > 0) + { + int count = 0; + while (lastKey == 0xff && count++ < time) + { + boost::this_thread::sleep(boost::posix_time::millisec(1)); + } + } + else if (time == 0) + { + while (lastKey == 0xff) + { + boost::this_thread::sleep(boost::posix_time::millisec(1)); + } + } + bool pressed = keys[key]; + if (reset) + keys[key] = false; + return pressed; + } + unsigned char lastKey; + boost::shared_ptr t; + sig_type jobs; + std::bitset<0xFF> keys; + } + ; + + namespace + { + boost::shared_ptr runner; + } struct imshow { static void @@ -45,17 +162,10 @@ namespace ecto_opencv declare_io(const tendrils& params, tendrils& inputs, tendrils& outputs) { inputs.declare("image", "The image to show").required(true); - outputs.declare("out", "Character pressed."); //optional output. - bp::object triggers; params["triggers"] >> triggers; if (!triggers || triggers == bp::object()) - return;//no user supplied triggers. - - if (params.get("waitKey") < 0) - throw std::runtime_error( - "You may not have a waitKey of less than zero when you are supplying triggers." - " waitKey is what captures keypress events."); + return; //no user supplied triggers. bp::list l = bp::dict(triggers).items(); for (int j = 0, end = bp::len(l); j < end; ++j) @@ -76,12 +186,11 @@ namespace ecto_opencv auto_size_ = params.get("autoSize"); full_screen_ = params["maximize"]; image_ = inputs["image"]; - key_ = outputs["out"]; bp::object triggers; params["triggers"] >> triggers; if (!triggers || triggers == bp::object()) - return; //no user supllied triggers. + return; //no user supplied triggers. bp::list l = bp::dict(triggers).items(); for (int j = 0, end = bp::len(l); j < end; ++j) @@ -98,21 +207,15 @@ namespace ecto_opencv int process(const tendrils& inputs, const tendrils& outputs) { + if (!runner) + { + runner.reset(new HighGuiRunner); + } cv::Mat image = *image_; std::for_each(trigger_keys_.begin(), trigger_keys_.end(), trigger_reset()); - *key_ = 0; if (image.empty()) { - return 0; - } - if (*full_screen_) - { - cv::namedWindow(window_name_, CV_WINDOW_KEEPRATIO); - cv::setWindowProperty(window_name_, CV_WND_PROP_FULLSCREEN, true); - } - else if (auto_size_) - { - cv::namedWindow(window_name_, CV_WINDOW_KEEPRATIO); + return ecto::OK; } if (image.depth() == CV_32F || image.depth() == CV_64F) @@ -131,33 +234,31 @@ namespace ecto_opencv image = show; } - cv::imshow(window_name_, image); - - int r = 0; - if (waitkey_ >= 0) - r = 0xff & cv::waitKey(waitkey_); + runner->post_job(ImshowJob(image, window_name_, *full_screen_, auto_size_)); - *key_ = r; - - if (r == 27 || r == 'q' || r == 'Q') + if (runner->testKey(waitkey_, 'q', true) || runner->testKey(waitkey_, 27, true)) { - std::cout << "QUIT!\n"; + runner->post_job(CloseWindow(window_name_)); return ecto::QUIT; } - else - { - std::map >::iterator it = trigger_keys_.find(r); - if (it != trigger_keys_.end()) - *(it->second) = true; - return ecto::OK; - } + typedef std::pair > KeySporeT; + BOOST_FOREACH(KeySporeT x, trigger_keys_) + { + *(x.second) = runner->testKey(waitkey_, x.first, true); + } + return ecto::OK; } + + ~imshow() + { + runner->post_job(CloseWindow(window_name_)); + } + std::string window_name_; int waitkey_; bool auto_size_; ecto::spore full_screen_; ecto::spore image_; - ecto::spore key_; std::map > trigger_keys_; }; } diff --git a/samples/rescale.py b/samples/rescale.py new file mode 100755 index 0000000..24f3eb5 --- /dev/null +++ b/samples/rescale.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +import ecto +from ecto_opencv.highgui import VideoCapture, imshow, FPSDrawer +from ecto_opencv.imgproc import Scale, Interpolation +video_cap = VideoCapture(video_device=0, width=640, height=480) +fps = FPSDrawer() +factor = 0.1 +scale_down = Scale(factor=factor, interpolation=Interpolation.AREA) +scale_up = Scale(factor=1 / factor, interpolation=Interpolation.LANCZOS4) + +plasm = ecto.Plasm() +plasm.connect(video_cap['image'] >> scale_down['image'], + scale_down['image'] >> scale_up['image'], + scale_up['image'] >> fps['image'], + fps['image'] >> imshow(name='Rescaled',waitKey=100)['image'], + ) + +if __name__ == '__main__': + from ecto.opts import doit + doit(plasm, description='Capture a video from the device and display it.',locals=vars())