spyglass 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +6 -0
  4. data/.travis.yml +11 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +20 -0
  7. data/README.md +28 -0
  8. data/Rakefile +5 -0
  9. data/examples/background_subtractor.rb +35 -0
  10. data/examples/cascade_classifier.rb +21 -0
  11. data/examples/contours.rb +24 -0
  12. data/examples/images/apple.jpg +0 -0
  13. data/examples/images/beach.jpg +0 -0
  14. data/examples/video_capture.rb +15 -0
  15. data/ext/spyglass/background_subtractor.cc +78 -0
  16. data/ext/spyglass/background_subtractor.h +18 -0
  17. data/ext/spyglass/cascade_classifier.cc +70 -0
  18. data/ext/spyglass/cascade_classifier.h +18 -0
  19. data/ext/spyglass/color.cc +83 -0
  20. data/ext/spyglass/color.h +22 -0
  21. data/ext/spyglass/color_space.cc +39 -0
  22. data/ext/spyglass/color_space.h +13 -0
  23. data/ext/spyglass/contour.cc +92 -0
  24. data/ext/spyglass/contour.h +22 -0
  25. data/ext/spyglass/extconf.rb +6 -0
  26. data/ext/spyglass/gui.cc +27 -0
  27. data/ext/spyglass/gui.h +15 -0
  28. data/ext/spyglass/image.cc +482 -0
  29. data/ext/spyglass/image.h +46 -0
  30. data/ext/spyglass/point.cc +78 -0
  31. data/ext/spyglass/point.h +23 -0
  32. data/ext/spyglass/prelude.h +42 -0
  33. data/ext/spyglass/rect.cc +131 -0
  34. data/ext/spyglass/rect.h +30 -0
  35. data/ext/spyglass/size.cc +89 -0
  36. data/ext/spyglass/size.h +25 -0
  37. data/ext/spyglass/spyglass.cc +35 -0
  38. data/ext/spyglass/spyglass.h +29 -0
  39. data/ext/spyglass/video_capture.cc +96 -0
  40. data/ext/spyglass/video_capture.h +20 -0
  41. data/ext/spyglass/window.cc +93 -0
  42. data/ext/spyglass/window.h +23 -0
  43. data/lib/spyglass.rb +6 -0
  44. data/lib/spyglass/color_space.rb +12 -0
  45. data/lib/spyglass/version.rb +3 -0
  46. data/spec/fixtures/haarcascade_frontalface_default.xml +35712 -0
  47. data/spec/fixtures/lena.jpg +0 -0
  48. data/spec/matchers/close_to.rb +6 -0
  49. data/spec/spec_helper.rb +8 -0
  50. data/spec/spyglass/background_subtractor_spec.rb +23 -0
  51. data/spec/spyglass/cascade_classifier_spec.rb +28 -0
  52. data/spec/spyglass/color_space_spec.rb +13 -0
  53. data/spec/spyglass/color_spec.rb +54 -0
  54. data/spec/spyglass/contour_spec.rb +26 -0
  55. data/spec/spyglass/gui/window_spec.rb +21 -0
  56. data/spec/spyglass/image_spec.rb +116 -0
  57. data/spec/spyglass/point_spec.rb +41 -0
  58. data/spec/spyglass/rect_spec.rb +103 -0
  59. data/spec/spyglass/size_spec.rb +52 -0
  60. data/spyglass.gemspec +26 -0
  61. data/tasks/compile.rake +6 -0
  62. data/tasks/gem.rake +2 -0
  63. data/tasks/rspec.rake +21 -0
  64. metadata +177 -0
@@ -0,0 +1,22 @@
1
+ #ifndef SPYGLASS_COLOR_H_
2
+ #define SPYGLASS_COLOR_H_
3
+
4
+ #include "spyglass.h"
5
+
6
+ namespace Spyglass {
7
+ namespace Color {
8
+ void define_ruby_class();
9
+ VALUE get_ruby_class();
10
+
11
+ static VALUE rb_alloc(VALUE self);
12
+ static void rb_free(cv::Scalar *color);
13
+ static VALUE rb_initialize(int argc, VALUE *argv, VALUE self);
14
+ static VALUE rb_get_color(VALUE self, VALUE index);
15
+ static VALUE rb_is_zeros(VALUE self);
16
+ static VALUE rb_to_a(VALUE self);
17
+
18
+ VALUE from_cvscalar(cv::Scalar *color);
19
+ }
20
+ }
21
+
22
+ #endif
@@ -0,0 +1,39 @@
1
+ #include "color_space.h"
2
+
3
+ VALUE ColorSpaceModule;
4
+
5
+ namespace Spyglass {
6
+ namespace ColorSpace {
7
+ void define_ruby_module() {
8
+ ColorSpaceModule = rb_define_module_under(Spyglass::get_ruby_module(), "ColorSpace");
9
+
10
+ // BGR
11
+ rb_define_const(ColorSpaceModule, "BGR_TO_GRAY", INT2FIX(CV_BGR2GRAY));
12
+ rb_define_const(ColorSpaceModule, "BGR_TO_HLS", INT2FIX(CV_BGR2HLS));
13
+ rb_define_const(ColorSpaceModule, "BGR_TO_HSV", INT2FIX(CV_BGR2HSV));
14
+ rb_define_const(ColorSpaceModule, "BGR_TO_YCRCB", INT2FIX(CV_BGR2YCrCb));
15
+
16
+ // Gray
17
+ rb_define_const(ColorSpaceModule, "GRAY_TO_BGR", INT2FIX(CV_GRAY2BGR));
18
+ rb_define_const(ColorSpaceModule, "GRAY_TO_RGB", INT2FIX(CV_GRAY2RGB));
19
+
20
+ // HLS
21
+ rb_define_const(ColorSpaceModule, "HLS_TO_BGR", INT2FIX(CV_HLS2BGR));
22
+ rb_define_const(ColorSpaceModule, "HLS_TO_RGB", INT2FIX(CV_HLS2RGB));
23
+
24
+ // HSV
25
+ rb_define_const(ColorSpaceModule, "HSV_TO_BGR", INT2FIX(CV_HSV2BGR));
26
+ rb_define_const(ColorSpaceModule, "HSV_TO_RGB", INT2FIX(CV_HSV2RGB));
27
+
28
+ // RGB
29
+ rb_define_const(ColorSpaceModule, "RGB_TO_GRAY", INT2FIX(CV_RGB2GRAY));
30
+ rb_define_const(ColorSpaceModule, "RGB_TO_HLS", INT2FIX(CV_RGB2HLS));
31
+ rb_define_const(ColorSpaceModule, "RGB_TO_HSV", INT2FIX(CV_RGB2HSV));
32
+ rb_define_const(ColorSpaceModule, "RGB_TO_YCRCB", INT2FIX(CV_RGB2YCrCb));
33
+
34
+ // YCrCb
35
+ rb_define_const(ColorSpaceModule, "YCRCB_TO_BGR", INT2FIX(CV_YCrCb2BGR));
36
+ rb_define_const(ColorSpaceModule, "YCRCB_TO_RGB", INT2FIX(CV_YCrCb2RGB));
37
+ }
38
+ }
39
+ }
@@ -0,0 +1,13 @@
1
+ #ifndef SPYGLASS_COLOR_SPACE_H_
2
+ #define SPYGLASS_COLOR_SPACE_H_
3
+
4
+ #include "spyglass.h"
5
+
6
+ namespace Spyglass {
7
+ namespace ColorSpace {
8
+ void define_ruby_module();
9
+ VALUE get_ruby_module();
10
+ }
11
+ }
12
+
13
+ #endif
@@ -0,0 +1,92 @@
1
+ #include "contour.h"
2
+
3
+ static VALUE ContourClass;
4
+
5
+ namespace Spyglass {
6
+ namespace Contour {
7
+ void define_ruby_class() {
8
+ // Class definition
9
+ ContourClass = rb_define_class_under(Spyglass::get_ruby_module(), "Contour", rb_cObject);
10
+ rb_define_alloc_func(ContourClass, rb_alloc);
11
+ rb_define_method(ContourClass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1);
12
+
13
+ // Instance methods
14
+ rb_define_method(ContourClass, "rect", RUBY_METHOD_FUNC(rb_get_rect), 0);
15
+ }
16
+
17
+ VALUE get_ruby_class() {
18
+ return ContourClass;
19
+ }
20
+
21
+ static VALUE rb_alloc(VALUE self) {
22
+ std::vector<cv::Point *> *contour = new std::vector<cv::Point *>();
23
+ return Data_Wrap_Struct(ContourClass, NULL, rb_free, contour);
24
+ }
25
+
26
+ static void rb_free(std::vector<cv::Point *> *contour) {
27
+ contour->clear();
28
+ delete contour;
29
+ }
30
+
31
+ static VALUE rb_initialize(int argc, VALUE *argv, VALUE self) {
32
+ VALUE points;
33
+ rb_scan_args(argc, argv, "01", &points);
34
+
35
+ if(!RTEST(points))
36
+ return self;
37
+
38
+ Check_Type(points, T_ARRAY);
39
+
40
+ std::vector<cv::Point *> *contour = SG_GET_CONTOUR(self);
41
+ for(int idx = 0; idx < RARRAY_LEN(points); idx++) {
42
+ VALUE point = rb_ary_entry(points, idx);
43
+ if(CLASS_OF(point) != Point::get_ruby_class()) {
44
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected Spyglass::Point)",
45
+ rb_obj_classname(point));
46
+ }
47
+
48
+ cv::Point *_point = new cv::Point(* SG_GET_POINT(point));
49
+ contour->push_back(_point);
50
+ }
51
+
52
+ return self;
53
+ }
54
+
55
+ static VALUE rb_get_rect(VALUE self) {
56
+ std::vector<cv::Point *> *contour = SG_GET_CONTOUR(self);
57
+ cv::Rect rect = cv::boundingRect(to_value_vector(contour));
58
+ cv::Rect *_rect = new cv::Rect(rect);
59
+ return Rect::from_cvrect(_rect);
60
+ }
61
+
62
+ std::vector<cv::Point> to_value_vector(std::vector<cv::Point *> *contour) {
63
+ std::vector<cv::Point> result;
64
+ for(int idx = 0; idx < contour->size(); idx++) {
65
+ cv::Point *point = (*contour)[idx];
66
+ result.push_back(*point);
67
+ }
68
+
69
+ return result;
70
+ }
71
+
72
+ VALUE from_cvpoint_vector(std::vector<cv::Point> contours) {
73
+ std::vector<cv::Point *> *ctrs = new std::vector<cv::Point *>();
74
+
75
+ for(int idx = 0; idx < contours.size(); idx++) {
76
+ ctrs->push_back(new cv::Point(contours[idx]));
77
+ }
78
+
79
+ return Data_Wrap_Struct(ContourClass, NULL, rb_free, ctrs);
80
+ }
81
+
82
+ VALUE from_contour_vector(std::vector<std::vector<cv::Point> > contours) {
83
+ VALUE ctrs = rb_ary_new2(contours.size());
84
+ for(int idx = 0; idx < contours.size(); idx++) {
85
+ rb_ary_store(ctrs, idx, from_cvpoint_vector(contours[idx]));
86
+ }
87
+
88
+ return ctrs;
89
+ }
90
+
91
+ }
92
+ }
@@ -0,0 +1,22 @@
1
+ #ifndef SPYGLASS_CONTOUR_H_
2
+ #define SPYGLASS_CONTOUR_H_
3
+
4
+ #include "spyglass.h"
5
+
6
+ namespace Spyglass {
7
+ namespace Contour {
8
+ void define_ruby_class();
9
+ VALUE get_ruby_class();
10
+
11
+ static VALUE rb_alloc(VALUE self);
12
+ static void rb_free(std::vector<cv::Point *> *contour);
13
+ static VALUE rb_initialize(int argc, VALUE *argv, VALUE self);
14
+ static VALUE rb_get_rect(VALUE self);
15
+
16
+ std::vector<cv::Point> to_value_vector(std::vector<cv::Point *> *contour);
17
+ VALUE from_cvpoint_vector(std::vector<cv::Point> contours);
18
+ VALUE from_contour_vector(std::vector<std::vector<cv::Point> > contours);
19
+ }
20
+ }
21
+
22
+ #endif // SPYGLASS_CONTOUR_H_
@@ -0,0 +1,6 @@
1
+ require 'mkmf'
2
+
3
+ $CFLAGS = ENV["CFLAGS"].to_s + " " + `pkg-config opencv --cflags`.chomp
4
+ $LOCAL_LIBS = ENV["LIBS"].to_s + " " + `pkg-config opencv --libs`.chomp
5
+
6
+ create_makefile("spyglass/spyglass")
@@ -0,0 +1,27 @@
1
+ #include "gui.h"
2
+
3
+ static VALUE GuiModule;
4
+
5
+ namespace Spyglass {
6
+ namespace GUI {
7
+ void define_ruby_module() {
8
+ GuiModule = rb_define_module_under(Spyglass::get_ruby_module(), "GUI");
9
+
10
+ // Module methods
11
+ rb_define_singleton_method(GuiModule, "wait_key", RUBY_METHOD_FUNC(rb_wait_key), 1);
12
+ }
13
+
14
+ VALUE get_ruby_module() {
15
+ return GuiModule;
16
+ }
17
+
18
+ static VALUE rb_wait_key(VALUE klass, VALUE timeout) {
19
+ Check_Type(timeout, T_FIXNUM);
20
+
21
+ int msecs = FIX2INT(timeout);
22
+ int key = cv::waitKey(msecs);
23
+
24
+ return INT2FIX(key);
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,15 @@
1
+ #ifndef SPYGLASS_GUI_H_
2
+ #define SPYGLASS_GUI_H_
3
+
4
+ #include "spyglass.h"
5
+
6
+ namespace Spyglass {
7
+ namespace GUI {
8
+ void define_ruby_module();
9
+ VALUE get_ruby_module();
10
+
11
+ static VALUE rb_wait_key(VALUE klass, VALUE timeout);
12
+ }
13
+ }
14
+
15
+ #endif // SPYGLASS_GUI_H_
@@ -0,0 +1,482 @@
1
+ #include "image.h"
2
+
3
+ static VALUE ImageClass;
4
+
5
+ namespace Spyglass {
6
+ namespace Image {
7
+ void define_ruby_class() {
8
+ // Class definition
9
+ ImageClass = rb_define_class_under(Spyglass::get_ruby_module(), "Image", rb_cObject);
10
+ rb_define_alloc_func(ImageClass, rb_alloc);
11
+ rb_define_method(ImageClass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1);
12
+
13
+ // Class methods
14
+ rb_define_singleton_method(ImageClass, "load", RUBY_METHOD_FUNC(rb_load), -1);
15
+ rb_define_singleton_method(ImageClass, "zeros", RUBY_METHOD_FUNC(rb_zeros), -1);
16
+
17
+ // Instance methods
18
+ rb_define_method(ImageClass, "canny", RUBY_METHOD_FUNC(rb_canny), 2);
19
+ rb_define_method(ImageClass, "canny!", RUBY_METHOD_FUNC(rb_canny_inplace), 2);
20
+ rb_define_method(ImageClass, "cols", RUBY_METHOD_FUNC(rb_get_cols), 0);
21
+ rb_define_method(ImageClass, "contours", RUBY_METHOD_FUNC(rb_get_contours), 0);
22
+ rb_define_method(ImageClass, "convert", RUBY_METHOD_FUNC(rb_convert), 1);
23
+ rb_define_method(ImageClass, "convert!", RUBY_METHOD_FUNC(rb_convert_inplace), 1);
24
+ rb_define_method(ImageClass, "copy!", RUBY_METHOD_FUNC(rb_copy_inplace), -1);
25
+ rb_define_method(ImageClass, "crop", RUBY_METHOD_FUNC(rb_crop), 1);
26
+ rb_define_method(ImageClass, "crop!", RUBY_METHOD_FUNC(rb_crop_inplace), 1);
27
+ rb_define_method(ImageClass, "dilate", RUBY_METHOD_FUNC(rb_dilate), -1);
28
+ rb_define_method(ImageClass, "dilate!", RUBY_METHOD_FUNC(rb_dilate_inplace), -1);
29
+ rb_define_method(ImageClass, "draw_contours", RUBY_METHOD_FUNC(rb_draw_contours), 2);
30
+ rb_define_method(ImageClass, "draw_rectangle", RUBY_METHOD_FUNC(rb_draw_rectangle), 2);
31
+ rb_define_method(ImageClass, "erode", RUBY_METHOD_FUNC(rb_erode), -1);
32
+ rb_define_method(ImageClass, "erode!", RUBY_METHOD_FUNC(rb_erode_inplace), -1);
33
+ rb_define_method(ImageClass, "fill", RUBY_METHOD_FUNC(rb_fill), -1);
34
+ rb_define_method(ImageClass, "fill!", RUBY_METHOD_FUNC(rb_fill_inplace), -1);
35
+ rb_define_method(ImageClass, "mean", RUBY_METHOD_FUNC(rb_mean), -1);
36
+ rb_define_method(ImageClass, "rows", RUBY_METHOD_FUNC(rb_get_rows), 0);
37
+ rb_define_method(ImageClass, "size", RUBY_METHOD_FUNC(rb_get_size), 0);
38
+ rb_define_method(ImageClass, "threshold", RUBY_METHOD_FUNC(rb_threshold), -1);
39
+ rb_define_method(ImageClass, "threshold!", RUBY_METHOD_FUNC(rb_threshold_inplace), -1);
40
+ rb_define_method(ImageClass, "threshold_inv", RUBY_METHOD_FUNC(rb_threshold_inv), -1);
41
+ rb_define_method(ImageClass, "threshold_inv!", RUBY_METHOD_FUNC(rb_threshold_inv_inplace), -1);
42
+ rb_define_method(ImageClass, "write", RUBY_METHOD_FUNC(rb_write), 1);
43
+
44
+ // Constants
45
+ rb_define_const(ImageClass, "TYPE_8UC1", INT2NUM(CV_8UC1));
46
+ rb_define_const(ImageClass, "TYPE_8UC3", INT2NUM(CV_8UC3));
47
+ }
48
+
49
+ VALUE get_ruby_class() {
50
+ return ImageClass;
51
+ }
52
+
53
+ static VALUE rb_alloc(VALUE self) {
54
+ cv::Mat *mat = new cv::Mat();
55
+ return Data_Wrap_Struct(ImageClass, NULL, rb_free, mat);
56
+ }
57
+
58
+ static void rb_free(cv::Mat *img) {
59
+ img->~Mat();
60
+ delete img;
61
+ }
62
+
63
+ static VALUE rb_initialize(int argc, VALUE *argv, VALUE self) {
64
+ if(argc == 0)
65
+ return self;
66
+
67
+ VALUE size, type;
68
+ rb_scan_args(argc, argv, "02", &size, &type);
69
+
70
+ if(RTEST(size) && CLASS_OF(size) != Size::get_ruby_class()) {
71
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected Spyglass::Size)",
72
+ rb_obj_classname(size));
73
+ }
74
+
75
+ if(RTEST(type))
76
+ Check_Type(type, T_FIXNUM);
77
+
78
+ cv::Mat *img = SG_GET_IMAGE(self);
79
+ rb_free(img);
80
+
81
+ cv::Size *_size = RTEST(size) ? SG_GET_SIZE(size) : new cv::Size();
82
+ int _type = RTEST(type) ? NUM2INT(type) : CV_8UC3;
83
+
84
+ img = new cv::Mat(*_size, _type);
85
+ Data_Set_Struct(self, img);
86
+
87
+ return self;
88
+ }
89
+
90
+ cv::Mat *_do_canny(VALUE self, VALUE threshold1, VALUE threshold2, bool inplace) {
91
+ Check_Type(threshold1, T_FIXNUM);
92
+ Check_Type(threshold2, T_FIXNUM);
93
+
94
+ cv::Mat *img = SG_GET_IMAGE(self);
95
+ cv::Mat *dest;
96
+
97
+ if(inplace)
98
+ dest = img;
99
+ else
100
+ dest = new cv::Mat();
101
+
102
+ cv::Canny(*img, *dest, NUM2INT(threshold1), NUM2INT(threshold2));
103
+ return dest;
104
+ }
105
+
106
+ static VALUE rb_canny(VALUE self, VALUE threshold1, VALUE threshold2) {
107
+ cv::Mat *img = _do_canny(self, threshold1, threshold2, false);
108
+ return Data_Wrap_Struct(ImageClass, NULL, rb_free, img);
109
+ }
110
+
111
+ static VALUE rb_canny_inplace(VALUE self, VALUE threshold1, VALUE threshold2) {
112
+ _do_canny(self, threshold1, threshold2, true);
113
+ return self;
114
+ }
115
+
116
+ static VALUE rb_copy_inplace(int argc, VALUE *argv, VALUE self) {
117
+ VALUE src, mask;
118
+ rb_scan_args(argc, argv, "11", &src, &mask);
119
+
120
+ if(CLASS_OF(src) != ImageClass) {
121
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected Spyglass::Image)",
122
+ rb_obj_classname(src));
123
+ }
124
+
125
+ if(RTEST(mask) && CLASS_OF(mask) != ImageClass) {
126
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected Spyglass::Rect)",
127
+ rb_obj_classname(mask));
128
+ }
129
+
130
+ cv::Mat *dest = SG_GET_IMAGE(self);
131
+
132
+ rb_free(dest);
133
+ dest = new cv::Mat();
134
+
135
+ cv::Mat *_src = SG_GET_IMAGE(src);
136
+
137
+ if(RTEST(mask)) {
138
+ cv::Mat *_mask = SG_GET_IMAGE(mask);
139
+ _src->copyTo(*dest, *_mask);
140
+ } else {
141
+ _src->copyTo(*dest);
142
+ }
143
+
144
+
145
+ Data_Set_Struct(self, dest);
146
+ return self;
147
+ }
148
+
149
+ cv::Mat *_do_dilate(int argc, VALUE *argv, VALUE self, bool inplace) {
150
+ VALUE iterations;
151
+ rb_scan_args(argc, argv, "01", &iterations);
152
+
153
+ if(RTEST(iterations) && TYPE(iterations) != T_FIXNUM) {
154
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected Fixnum)",
155
+ rb_obj_classname(iterations));
156
+ }
157
+
158
+ int iter = RTEST(iterations) ? FIX2INT(iterations) : 1;
159
+
160
+ cv::Mat *img = SG_GET_IMAGE(self);
161
+ cv::Mat *dest;
162
+
163
+ if(inplace)
164
+ dest = img;
165
+ else
166
+ dest = new cv::Mat();
167
+
168
+ cv::dilate(*img, *dest, cv::Mat(), cv::Point(-1, -1), iter);
169
+ return dest;
170
+ }
171
+
172
+ static VALUE rb_dilate(int argc, VALUE *argv, VALUE self) {
173
+ cv::Mat *img = _do_dilate(argc, argv, self, false);
174
+ return Data_Wrap_Struct(ImageClass, NULL, rb_free, img);
175
+ }
176
+
177
+ static VALUE rb_dilate_inplace(int argc, VALUE *argv, VALUE self) {
178
+ _do_dilate(argc, argv, self, true);
179
+ return self;
180
+ }
181
+
182
+ static VALUE rb_draw_contours(VALUE self, VALUE contours, VALUE color) {
183
+ if(TYPE(contours) != T_ARRAY && CLASS_OF(contours) != Contour::get_ruby_class())
184
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected Array or Spyglass::Contour)",
185
+ rb_obj_classname(contours));
186
+
187
+ if(CLASS_OF(color) != Color::get_ruby_class()) {
188
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected Spyglass::Color)",
189
+ rb_obj_classname(color));
190
+ }
191
+
192
+ cv::Mat *img = SG_GET_IMAGE(self);
193
+ cv::Scalar *_color = SG_GET_COLOR(color);
194
+ std::vector<std::vector<cv::Point> > ctrs;
195
+
196
+ if(TYPE(contours) == T_ARRAY) {
197
+ for(int idx = 0; idx < RARRAY_LEN(contours); idx++) {
198
+ std::vector<cv::Point *> *contour = SG_GET_CONTOUR(rb_ary_entry(contours, idx));
199
+ ctrs.push_back(Contour::to_value_vector(contour));
200
+ }
201
+ } else {
202
+ std::vector<cv::Point *> *contour = SG_GET_CONTOUR(contours);
203
+ ctrs.push_back(Contour::to_value_vector(contour));
204
+ }
205
+
206
+ for(int idx = 0; idx < ctrs.size(); idx++)
207
+ cv::drawContours(*img, ctrs, idx, *_color, CV_FILLED);
208
+
209
+ return self;
210
+ }
211
+
212
+ static VALUE rb_draw_rectangle(VALUE self, VALUE rect, VALUE color) {
213
+ if(CLASS_OF(rect) != Rect::get_ruby_class()) {
214
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected Spyglass::Rect)",
215
+ rb_obj_classname(rect));
216
+ }
217
+
218
+ cv::Mat *img = SG_GET_IMAGE(self);
219
+ cv::Rect *_rect = SG_GET_RECT(rect);
220
+ cv::Scalar *_color = SG_GET_COLOR(color);
221
+
222
+ cv::Point bottom_right(_rect->x + _rect->width, _rect->y + _rect->height);
223
+
224
+ cv::rectangle(*img, _rect->tl(), bottom_right, *_color);
225
+ return self;
226
+ }
227
+
228
+ cv::Mat *_do_erode(int argc, VALUE *argv, VALUE self, bool inplace) {
229
+ VALUE iterations;
230
+ rb_scan_args(argc, argv, "01", &iterations);
231
+
232
+ if(RTEST(iterations) && TYPE(iterations) != T_FIXNUM) {
233
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected Fixnum)",
234
+ rb_obj_classname(iterations));
235
+ }
236
+
237
+ int iter = RTEST(iterations) ? FIX2INT(iterations) : 1;
238
+
239
+ cv::Mat *img = SG_GET_IMAGE(self);
240
+ cv::Mat *dest;
241
+
242
+ if(inplace)
243
+ dest = img;
244
+ else
245
+ dest = new cv::Mat();
246
+
247
+ cv::erode(*img, *dest, cv::Mat(), cv::Point(-1, -1), iter);
248
+ return dest;
249
+ }
250
+
251
+ static VALUE rb_erode(int argc, VALUE *argv, VALUE self) {
252
+ cv::Mat *img = _do_erode(argc, argv, self, false);
253
+ return Data_Wrap_Struct(ImageClass, NULL, rb_free, img);
254
+ }
255
+
256
+ static VALUE rb_erode_inplace(int argc, VALUE *argv, VALUE self) {
257
+ _do_erode(argc, argv, self, true);
258
+ return self;
259
+ }
260
+
261
+ cv::Mat *_do_fill(int argc, VALUE *argv, VALUE self, bool inplace) {
262
+ VALUE color, mask;
263
+ rb_scan_args(argc, argv, "11", &color, &mask);
264
+
265
+ if(CLASS_OF(color) != Color::get_ruby_class())
266
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected Spyglass::Color)",
267
+ rb_obj_classname(color));
268
+
269
+ if(RTEST(mask) && CLASS_OF(mask) != ImageClass)
270
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected Spyglass::Image)",
271
+ rb_obj_classname(mask));
272
+
273
+ cv::Mat *img = SG_GET_IMAGE(self);
274
+ cv::Mat *dest;
275
+
276
+ cv::Scalar *_color = SG_GET_COLOR(color);
277
+ cv::Mat *_mask = RTEST(mask) ? SG_GET_IMAGE(mask) : new cv::Mat();
278
+
279
+ if(inplace)
280
+ dest = img;
281
+ else
282
+ dest = new cv::Mat(*img);
283
+
284
+ (*dest).setTo(*_color, *_mask);
285
+ return dest;
286
+ }
287
+
288
+ static VALUE rb_fill(int argc, VALUE *argv, VALUE self) {
289
+ cv::Mat *img = _do_fill(argc, argv, self, false);
290
+ return Data_Wrap_Struct(ImageClass, NULL, rb_free, img);
291
+ }
292
+
293
+ static VALUE rb_fill_inplace(int argc, VALUE *argv, VALUE self) {
294
+ _do_fill(argc, argv, self, true);
295
+ return self;
296
+ }
297
+
298
+ static VALUE rb_load(int argc, VALUE *argv, VALUE klass) {
299
+ VALUE filename;
300
+ rb_scan_args(argc, argv, "10", &filename);
301
+ Check_Type(filename, T_STRING);
302
+
303
+ cv::Mat _img = cv::imread(StringValueCStr(filename));
304
+ cv::Mat *img = new cv::Mat(_img);
305
+ return Data_Wrap_Struct(ImageClass, NULL, rb_free, img);
306
+ }
307
+
308
+ static VALUE rb_get_cols(VALUE self) {
309
+ cv::Mat *img = SG_GET_IMAGE(self);
310
+ return INT2FIX(img->cols);
311
+ }
312
+
313
+ static VALUE rb_get_contours(VALUE self) {
314
+ cv::Mat *img = SG_GET_IMAGE(self);
315
+
316
+ std::vector<std::vector<cv::Point> > contours;
317
+ cv::findContours(*img, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
318
+
319
+ return Contour::from_contour_vector(contours);
320
+ }
321
+
322
+ cv::Mat *_do_convert(VALUE self, VALUE color_space, bool inplace) {
323
+ int code = FIX2INT(color_space);
324
+
325
+ cv::Mat *img = SG_GET_IMAGE(self);
326
+ cv::Mat *dest;
327
+ if(inplace)
328
+ dest = img;
329
+ else
330
+ dest = new cv::Mat();
331
+
332
+ cvtColor(*img, *dest, code);
333
+ return dest;
334
+ }
335
+
336
+ static VALUE rb_convert(VALUE self, VALUE color_space) {
337
+ cv::Mat *img = _do_convert(self, color_space, false);
338
+ return Data_Wrap_Struct(ImageClass, NULL, rb_free, img);
339
+ }
340
+
341
+ static VALUE rb_convert_inplace(VALUE self, VALUE color_space) {
342
+ cv::Mat *img = _do_convert(self, color_space, true);
343
+ return self;
344
+ }
345
+
346
+ cv::Mat *_do_crop(VALUE self, VALUE rect) {
347
+ if(CLASS_OF(rect) != Rect::get_ruby_class()) {
348
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected Spyglass::Rect)",
349
+ rb_obj_classname(rect));
350
+ }
351
+
352
+ cv::Mat *img = SG_GET_IMAGE(self);
353
+ cv::Rect *boundaries = SG_GET_RECT(rect);
354
+ cv::Mat *dest = new cv::Mat();
355
+
356
+ (*img)(*boundaries).copyTo(*dest);
357
+ return dest;
358
+ }
359
+
360
+ static VALUE rb_crop(VALUE self, VALUE rect) {
361
+ cv::Mat *img = _do_crop(self, rect);
362
+ return Data_Wrap_Struct(ImageClass, NULL, rb_free, img);
363
+ }
364
+
365
+ static VALUE rb_crop_inplace(VALUE self, VALUE rect) {
366
+ // This difers slightly from the other methods for memory reasons.
367
+ // Whenever you crop an image, OpenCV doesn't automatically reallocate
368
+ // memory for a smaller size, so we just copy the pixels into a new
369
+ // instance and get rid of the old one.
370
+ cv::Mat *old_img = SG_GET_IMAGE(self);
371
+ cv::Mat *img = _do_crop(self, rect);
372
+ rb_free(old_img);
373
+
374
+ Data_Set_Struct(self, img);
375
+ return self;
376
+ }
377
+
378
+ static VALUE rb_mean(int argc, VALUE *argv, VALUE self) {
379
+ VALUE mask;
380
+ rb_scan_args(argc, argv, "01", &mask);
381
+
382
+ if(RTEST(mask) && CLASS_OF(mask) != Image::get_ruby_class()) {
383
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected Spyglass::Image)",
384
+ rb_obj_classname(mask));
385
+ }
386
+
387
+ cv::Mat *img = SG_GET_IMAGE(self);
388
+ cv::Scalar mean;
389
+
390
+ if(RTEST(mask)) {
391
+ cv::Mat *_mask = SG_GET_IMAGE(mask);
392
+ mean = cv::mean(*img, *_mask);
393
+ } else {
394
+ mean = cv::mean(*img);
395
+ }
396
+
397
+ cv::Scalar *_mean = new cv::Scalar(mean);
398
+ return Color::from_cvscalar(_mean);
399
+ }
400
+
401
+ static VALUE rb_get_rows(VALUE self) {
402
+ cv::Mat *img = SG_GET_IMAGE(self);
403
+ return INT2FIX(img->rows);
404
+ }
405
+
406
+ static VALUE rb_get_size(VALUE self) {
407
+ cv::Mat *img = SG_GET_IMAGE(self);
408
+ return Size::from_cvmat(img);
409
+ }
410
+
411
+ cv::Mat *_do_threshold(int argc, VALUE *argv, VALUE self, bool inverse, bool inplace) {
412
+ VALUE threshold, replacement, opts;
413
+ rb_scan_args(argc, argv, "21", &threshold, &replacement, &opts);
414
+
415
+ Check_Type(threshold, T_FLOAT);
416
+ Check_Type(replacement, T_FLOAT);
417
+
418
+ cv::Mat *img = SG_GET_IMAGE(self);
419
+ cv::Mat *dest;
420
+
421
+ int method = inverse ? cv::THRESH_BINARY_INV : cv::THRESH_BINARY;
422
+
423
+ if(inplace)
424
+ dest = img;
425
+ else
426
+ dest = new cv::Mat();
427
+
428
+ cv::threshold(*img, *dest, NUM2DBL(threshold), NUM2DBL(replacement), method);
429
+ return dest;
430
+ }
431
+
432
+ static VALUE rb_threshold(int argc, VALUE *argv, VALUE self) {
433
+ cv::Mat *img = _do_threshold(argc, argv, self, false, false);
434
+ return Data_Wrap_Struct(ImageClass, NULL, rb_free, img);
435
+ }
436
+
437
+ static VALUE rb_threshold_inplace(int argc, VALUE *argv, VALUE self) {
438
+ _do_threshold(argc, argv, self, false, true);
439
+ return self;
440
+ }
441
+
442
+ static VALUE rb_threshold_inv(int argc, VALUE *argv, VALUE self) {
443
+ cv::Mat *img = _do_threshold(argc, argv, self, true, false);
444
+ return Data_Wrap_Struct(ImageClass, NULL, rb_free, img);
445
+ }
446
+
447
+ static VALUE rb_threshold_inv_inplace(int argc, VALUE *argv, VALUE self) {
448
+ _do_threshold(argc, argv, self, true, true);
449
+ return self;
450
+ }
451
+
452
+ static VALUE rb_write(VALUE self, VALUE filename) {
453
+ Check_Type(filename, T_STRING);
454
+
455
+ cv::Mat *img = SG_GET_IMAGE(self);
456
+ bool res = cv::imwrite(StringValueCStr(filename), *img);
457
+ return (res) ? Qtrue : Qfalse;
458
+ }
459
+
460
+ static VALUE rb_zeros(int argc, VALUE *argv, VALUE klass) {
461
+ VALUE size, type;
462
+ rb_scan_args(argc, argv, "11", &size, &type);
463
+
464
+ if(CLASS_OF(size) != Size::get_ruby_class()) {
465
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected Spyglass::Size)",
466
+ rb_obj_classname(size));
467
+ }
468
+
469
+ cv::Size *_size = SG_GET_SIZE(size);
470
+
471
+ int _type = RTEST(type) ? NUM2INT(type) : CV_8UC1;
472
+
473
+ cv::Mat zeros = cv::Mat::zeros(*_size, _type);
474
+ cv::Mat *img = new cv::Mat(zeros);
475
+ return Data_Wrap_Struct(ImageClass, NULL, rb_free, img);
476
+ }
477
+
478
+ VALUE from_cvmat(cv::Mat *mat) {
479
+ return Data_Wrap_Struct(ImageClass, NULL, rb_free, mat);
480
+ }
481
+ }
482
+ }