ruby-opencv/ext/opencv/window.cpp

284 lines
8.2 KiB
C++

#include "opencv2/highgui.hpp"
#include "window.hpp"
#include "trackbar.hpp"
#include "error.hpp"
#include "mat.hpp"
namespace rubyopencv {
namespace Window {
void mark_window(void *ptr);
void free_window(void *ptr);
VALUE rb_klass;
rb_data_type_t opencv_window_type = {
"Window",
{ mark_window, free_window, 0, },
0,
0,
0
};
void mark_window(void *ptr) {
window_t* window_ptr = (window_t*)ptr;
rb_gc_mark(window_ptr->name);
rb_gc_mark(window_ptr->trackbars);
}
void free_window(void *ptr) {
xfree(ptr);
}
VALUE rb_allocate(VALUE klass) {
window_t* ptr = NULL;
return TypedData_Make_Struct(klass, window_t, &opencv_window_type, ptr);
}
window_t* obj2window(VALUE obj) {
window_t* ptr = NULL;
TypedData_Get_Struct(obj, window_t, &opencv_window_type, ptr);
return ptr;
}
inline char* GET_WINDOW_NAME(VALUE obj) {
window_t* w = obj2window(obj);
return StringValueCStr(w->name);
}
/*
* Creates a window.
*
* @overload new(name, flags = CV_WINDOW_AUTOSIZE)
* @param name [String] Name of the window in the window caption that may be used as a window identifier.
* @param flags [Integer] Flags of the window. The supported flags are:
* * CV_WINDOW_AUTOSIZE - If this is set, the window size is automatically adjusted
* to fit the displayed image, and you cannot change the window size manually.
* * CV_WINDOW_NORMAL - If this is set, the user can resize the window (no constraint).
* * CV_WINDOW_OPENGL - If this is set, the window will be created with OpenGL support.
* @opencv_func cv::namedWindow
*/
VALUE rb_initialize(int argc, VALUE *argv, VALUE self) {
VALUE name, flags;
rb_scan_args(argc, argv, "11", &name, &flags);
Check_Type(name, T_STRING);
char* name_str = StringValueCStr(name);
if (cvGetWindowHandle(name_str) != NULL) {
rb_raise(rb_eStandardError, "window name should be unique.");
}
int mode = CV_WINDOW_AUTOSIZE;
if (argc == 2) {
Check_Type(flags, T_FIXNUM);
mode = FIX2INT(flags);
}
window_t* self_ptr = obj2window(self);
self_ptr->name = name;
self_ptr->trackbars = rb_ary_new();
try {
cv::namedWindow(name_str, mode);
}
catch (cv::Exception& e) {
Error::raise(e);
}
return self;
}
/*
* Displays an image in the specified window.
*
* @overload show(image)
* @param image [Mat] Image to be shown.
* @opencv_func cv::imshow
*/
VALUE rb_show(VALUE self, VALUE img) {
try {
cv::Mat* m = Mat::obj2mat(img);
cv::imshow(GET_WINDOW_NAME(self), *m);
}
catch (cv::Exception& e) {
Error::raise(e);
}
return self;
}
/*
* Waits for a pressed key.
*
* @overload wait_key(delay = 0)
* @param delay [Integer] Delay in milliseconds. 0 is the special value that means "forever".
* @opencv_func cv::waitKey
*/
VALUE rb_wait_key(int argc, VALUE* argv, VALUE self) {
VALUE delay;
rb_scan_args(argc, argv, "01", &delay);
int ret = 0;
int delay_value = NIL_P(delay) ? 0 : NUM2INT(delay);
try {
ret = cv::waitKey(delay_value);
}
catch (cv::Exception& e) {
Error::raise(e);
}
return INT2NUM(ret);
}
/*
* Destroys a window. alive status of window be false.
*/
VALUE
rb_destroy(VALUE self) {
try {
cv::destroyWindow(GET_WINDOW_NAME(self));
}
catch (cv::Exception& e) {
Error::raise(e);
}
return self;
}
/*
* Destorys all the windows.
*/
VALUE rb_destroy_all(VALUE klass) {
try {
cv::destroyAllWindows();
}
catch (cv::Exception& e) {
Error::raise(e);
}
return Qnil;
}
/*
* Resizes window to the specified size.
*
* @overload resize(width, height)
* @param width [Integer] The new window width.
* @param height [Integer] The new window height.
* @opencv_func cv::resizeWindow
*/
VALUE rb_resize(VALUE self, VALUE width, VALUE height) {
try {
cv::resizeWindow(GET_WINDOW_NAME(self), NUM2INT(width), NUM2INT(height));
}
catch (cv::Exception& e) {
Error::raise(e);
}
return self;
}
/*
* Moves window to the specified position.
*
* @overload move(x, y)
* @param x [Integer] The new x-coordinate of the window.
* @param y [Integer] The new y-coordinate of the window.
* @opencv_func cv::moveWindow
*/
VALUE rb_move(VALUE self, VALUE x, VALUE y) {
try {
cv::moveWindow(GET_WINDOW_NAME(self), NUM2INT(x), NUM2INT(y));
}
catch (cv::Exception& e) {
Error::raise(e);
}
return self;
}
void trackbar_callback(int value, void* block) {
rb_funcall((VALUE)block, rb_intern("call"), 1, INT2NUM(value));
}
/*
* Creates or sets a trackbar and attaches it to the specified window.
*
* @overload set_trackbar(trackbar)
* @param trackbar [TrackBar] The trackbar to set.
*
* @overload set_trackbar(name, count, value = nil) { |value| ... }
* @param name [String] Name of the created trackbar.
* @param count [Integer] Maximal position of the slider. The minimal position is always 0.
* @param value [Integer] Optional value to an integer variable whose value reflects the position of the slider.
* Upon creation, the slider position is defined by this variable.
* @yield [value] Function to be called every time the slider changes position.
* @yieldparam value [Integer] The trackbar position.
* @opencv_func cv::createTrackbar
*/
VALUE rb_set_trackbar(int argc, VALUE *argv, VALUE self) {
VALUE trackbar;
if (argc == 1) {
trackbar = argv[0];
}
else {
trackbar = Trackbar::newobj(argc, argv);
}
Trackbar::trackbar_t *trackbar_ptr = Trackbar::obj2trackbar(trackbar);
try {
cv::TrackbarCallback callback = NULL;
void* block_ptr = NULL;
if (!NIL_P(trackbar_ptr->block)) {
block_ptr = (void*)(trackbar_ptr->block);
callback = (cv::TrackbarCallback)trackbar_callback;
}
cv::createTrackbar(trackbar_ptr->name, GET_WINDOW_NAME(self), &(trackbar_ptr->value),
trackbar_ptr->maxval, callback, block_ptr);
}
catch (cv::Exception& e) {
Error::raise(e);
}
rb_ary_push(obj2window(self)->trackbars, trackbar);
return trackbar;
}
void onMouse(int event, int x, int y, int flags, void* param) {
rb_funcall((VALUE)param, rb_intern("call"), 4, INT2FIX(event), INT2NUM(x), INT2NUM(y), INT2FIX(flags));
}
/*
* Sets mouse handler for the specified window.
*
* @overload set_mouse_callback { |event, x, y, flags| ... }
* @opencv_func cv::setMouseCallback
*/
VALUE rb_set_mouse_callback(int argc, VALUE* argv, VALUE self) {
window_t* selfptr = obj2window(self);
VALUE block = Qnil;
rb_scan_args(argc, argv, "0&", &block);
try {
if (rb_respond_to(block, rb_intern("call"))) {
cv::setMouseCallback(StringValueCStr(selfptr->name), onMouse, (void*)block);
}
}
catch (cv::Exception& e) {
Error::raise(e);
}
return block;
}
void init() {
VALUE opencv = rb_define_module("Cv");
rb_klass = rb_define_class_under(opencv, "Window", rb_cData);
rb_define_alloc_func(rb_klass, rb_allocate);
rb_define_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1);
rb_define_method(rb_klass, "show", RUBY_METHOD_FUNC(rb_show), 1);
rb_define_method(rb_klass, "destroy", RUBY_METHOD_FUNC(rb_destroy), 0);
rb_define_singleton_method(rb_klass, "destroy_all", RUBY_METHOD_FUNC(rb_destroy_all), 0);
rb_define_method(rb_klass, "resize", RUBY_METHOD_FUNC(rb_resize), 2);
rb_define_method(rb_klass, "move", RUBY_METHOD_FUNC(rb_move), 2);
rb_define_method(rb_klass, "set_trackbar", RUBY_METHOD_FUNC(rb_set_trackbar), -1);
rb_define_method(rb_klass, "set_mouse_callback", RUBY_METHOD_FUNC(rb_set_mouse_callback), -1);
rb_define_alias(rb_klass, "on_mouse", "set_mouse_callback");
}
}
}