spyglass 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 368c20a70c719acceb1244b9cab1ad6274622eaa
4
- data.tar.gz: 00e92f3dd911a30304ec83269b254420f5acdc57
3
+ metadata.gz: ea79e0513a6b15e030d22e55cb61f1281976d6d2
4
+ data.tar.gz: a90524336749778e856803ace12316f3ae0fd88e
5
5
  SHA512:
6
- metadata.gz: b4fac2a901002853912daf86ce7192a6b6fe05d8167c26bcdf7c30ff14e46dacab58c55186527084fcb5eeb80eabc76ac65933e962ad4cbfefbc44dbf0ef6bf3
7
- data.tar.gz: 6880d0ee03bd34737d78fa8609b0feaf672618074612386ee22e27750da780f120f0246f3996a7a197962ea62715c180d19357c544d269bd451a6bde3e58bc35
6
+ metadata.gz: a103029705c35d69271b0f527d7bd94e19eaff10218677ec4c70d715164696df900a837b0feea5d4dab35dec14dfff2044c98d2fdf3a38c393a31556d9e2dfad
7
+ data.tar.gz: e01a216cab093e8db29631f3db6224d6525a2197a38e24c7ac6d2ef169b6a10f42437e0dc2102ba8803d5f06528faf342390443ca57fc0f19408a4be68d320c8
@@ -32,4 +32,6 @@ loop do
32
32
  result.copy!(frame, delta);
33
33
 
34
34
  window.show result
35
+
36
+ break if GUI::wait_key(10) > 0
35
37
  end
@@ -12,7 +12,7 @@ loop do
12
12
  cap >> frame
13
13
 
14
14
  rects = classifier.detect(frame, scale_factor: 1.5, min_size: Size.new(30, 30))
15
- rects.map { |r| frame.draw_rectangle(r) }
15
+ rects.map { |r| frame.draw_rectangle(r, Color.new(255, 0, 0)) }
16
16
 
17
17
  window.show(frame)
18
18
 
data/examples/contours.rb CHANGED
@@ -13,7 +13,7 @@ canny.canny!(200, 300)
13
13
 
14
14
  result = Image.new
15
15
  result.copy!(apple)
16
- result.draw_contours(canny.contours)
16
+ result.draw_contours(canny.contours, Color.new(255, 0, 0))
17
17
 
18
18
  result_window = GUI::Window.new "Contours"
19
19
  result_window.show(result)
@@ -0,0 +1,24 @@
1
+ $LOAD_PATH.unshift('lib')
2
+ require 'spyglass'
3
+
4
+ include Spyglass
5
+
6
+ window = GUI::Window.new "Original"
7
+ output = GUI::Window.new "Output"
8
+ card = Image.load File.expand_path('images/card.jpg', File.dirname(__FILE__))
9
+
10
+ window.show(card)
11
+
12
+ canny = card.convert(ColorSpace[:BGR => :Gray])
13
+
14
+ canny.canny!(200, 300)
15
+ contours = canny.contours
16
+ corners = contours[0].corners
17
+
18
+ warped = card.warp_perspective(corners, Size.new(220, 300))
19
+
20
+ output.show(warped)
21
+
22
+ loop do
23
+ break if GUI::wait_key(10) > 0
24
+ end
Binary file
@@ -11,7 +11,12 @@ namespace Spyglass {
11
11
  rb_define_method(ContourClass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1);
12
12
 
13
13
  // Instance methods
14
+ rb_define_method(ContourClass, "corners", RUBY_METHOD_FUNC(rb_get_corners), 0);
15
+ rb_define_method(ContourClass, "convex?", RUBY_METHOD_FUNC(rb_is_convex), 0);
14
16
  rb_define_method(ContourClass, "rect", RUBY_METHOD_FUNC(rb_get_rect), 0);
17
+
18
+ // Aliases
19
+ rb_define_alias(ContourClass, "closed?", "convex?");
15
20
  }
16
21
 
17
22
  VALUE get_ruby_class() {
@@ -52,6 +57,57 @@ namespace Spyglass {
52
57
  return self;
53
58
  }
54
59
 
60
+ static VALUE rb_get_corners(VALUE self) {
61
+ // This method is a bit of a misnomer in terms of how OpenCV works,
62
+ // seen as it's not a simple getter. It's implemented for ease of
63
+ // use. This code was blatantly based on:
64
+ //
65
+ // http://opencv-code.com/tutorials/automatic-perspective-correction-for-quadrilateral-objects/
66
+ std::vector<cv::Point> contour = to_value_vector(SG_GET_CONTOUR(self));
67
+ cv::approxPolyDP(contour, contour, cv::arcLength(cv::Mat(contour), true) * 0.02, true);
68
+ if (contour.size() != 4) {
69
+ // TODO: Throw exception here?
70
+ std::cout << "The object is not quadrilateral!" << std::endl;
71
+ return Qnil;
72
+ }
73
+
74
+ // Get mass center
75
+ cv::Point center(0,0);
76
+ for (int i = 0; i < contour.size(); i++)
77
+ center += contour[i];
78
+ center *= (1. / contour.size());
79
+
80
+ // Grab TL, TR, BL, and BR corners.
81
+ std::vector<cv::Point> top, bot;
82
+ for (int i = 0; i < contour.size(); i++) {
83
+ if (contour[i].y < center.y)
84
+ top.push_back(contour[i]);
85
+ else
86
+ bot.push_back(contour[i]);
87
+ }
88
+
89
+ cv::Point tl = top[0].x > top[1].x ? top[1] : top[0];
90
+ cv::Point tr = top[0].x > top[1].x ? top[0] : top[1];
91
+ cv::Point bl = bot[0].x > bot[1].x ? bot[1] : bot[0];
92
+ cv::Point br = bot[0].x > bot[1].x ? bot[0] : bot[1];
93
+
94
+ contour.clear();
95
+ contour.push_back(tl);
96
+ contour.push_back(tr);
97
+ contour.push_back(br);
98
+ contour.push_back(bl);
99
+
100
+ return from_cvpoint_vector(contour);
101
+ }
102
+
103
+ static VALUE rb_is_convex(VALUE self) {
104
+ std::vector<cv::Point> contour = to_value_vector(SG_GET_CONTOUR(self));
105
+ std::vector<cv::Point> simplified;
106
+ cv::approxPolyDP(contour, simplified, cv::arcLength(cv::Mat(contour), true) * 0.02, true);
107
+
108
+ return cv::isContourConvex(simplified) ? Qtrue : Qfalse;
109
+ }
110
+
55
111
  static VALUE rb_get_rect(VALUE self) {
56
112
  std::vector<cv::Point *> *contour = SG_GET_CONTOUR(self);
57
113
  cv::Rect rect = cv::boundingRect(to_value_vector(contour));
@@ -11,7 +11,9 @@ namespace Spyglass {
11
11
  static VALUE rb_alloc(VALUE self);
12
12
  static void rb_free(std::vector<cv::Point *> *contour);
13
13
  static VALUE rb_initialize(int argc, VALUE *argv, VALUE self);
14
+ static VALUE rb_get_corners(VALUE self);
14
15
  static VALUE rb_get_rect(VALUE self);
16
+ static VALUE rb_is_convex(VALUE self);
15
17
 
16
18
  std::vector<cv::Point> to_value_vector(std::vector<cv::Point *> *contour);
17
19
  VALUE from_cvpoint_vector(std::vector<cv::Point> contours);
@@ -33,12 +33,15 @@ namespace Spyglass {
33
33
  rb_define_method(ImageClass, "fill", RUBY_METHOD_FUNC(rb_fill), -1);
34
34
  rb_define_method(ImageClass, "fill!", RUBY_METHOD_FUNC(rb_fill_inplace), -1);
35
35
  rb_define_method(ImageClass, "mean", RUBY_METHOD_FUNC(rb_mean), -1);
36
+ rb_define_method(ImageClass, "resize", RUBY_METHOD_FUNC(rb_resize), 1);
37
+ rb_define_method(ImageClass, "resize!", RUBY_METHOD_FUNC(rb_resize_inplace), 1);
36
38
  rb_define_method(ImageClass, "rows", RUBY_METHOD_FUNC(rb_get_rows), 0);
37
39
  rb_define_method(ImageClass, "size", RUBY_METHOD_FUNC(rb_get_size), 0);
38
40
  rb_define_method(ImageClass, "threshold", RUBY_METHOD_FUNC(rb_threshold), -1);
39
41
  rb_define_method(ImageClass, "threshold!", RUBY_METHOD_FUNC(rb_threshold_inplace), -1);
40
42
  rb_define_method(ImageClass, "threshold_inv", RUBY_METHOD_FUNC(rb_threshold_inv), -1);
41
43
  rb_define_method(ImageClass, "threshold_inv!", RUBY_METHOD_FUNC(rb_threshold_inv_inplace), -1);
44
+ rb_define_method(ImageClass, "warp_perspective", RUBY_METHOD_FUNC(rb_warp_perspective), 2);
42
45
  rb_define_method(ImageClass, "write", RUBY_METHOD_FUNC(rb_write), 1);
43
46
 
44
47
  // Constants
@@ -312,9 +315,10 @@ namespace Spyglass {
312
315
 
313
316
  static VALUE rb_get_contours(VALUE self) {
314
317
  cv::Mat *img = SG_GET_IMAGE(self);
318
+ cv::Mat tmp(*img);
315
319
 
316
320
  std::vector<std::vector<cv::Point> > contours;
317
- cv::findContours(*img, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
321
+ cv::findContours(tmp, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
318
322
 
319
323
  return Contour::from_contour_vector(contours);
320
324
  }
@@ -408,6 +412,33 @@ namespace Spyglass {
408
412
  return Size::from_cvmat(img);
409
413
  }
410
414
 
415
+ cv::Mat *_do_resize(VALUE self, VALUE size, bool inplace) {
416
+ cv::Mat *img = SG_GET_IMAGE(self);
417
+ cv::Mat *dest;
418
+
419
+ cv::Size *_size = SG_GET_SIZE(size);
420
+
421
+ if(inplace)
422
+ dest = img;
423
+ else
424
+ dest = new cv::Mat();
425
+
426
+ cv::resize(*img, *dest, *_size);
427
+
428
+ return dest;
429
+ }
430
+
431
+ static VALUE rb_resize(VALUE self, VALUE size) {
432
+ cv::Mat *img = _do_resize(self, size, false);
433
+ return Data_Wrap_Struct(ImageClass, NULL, rb_free, img);
434
+ }
435
+
436
+ static VALUE rb_resize_inplace(VALUE self, VALUE size) {
437
+ _do_resize(self, size, true);
438
+ return self;
439
+ }
440
+
441
+
411
442
  cv::Mat *_do_threshold(int argc, VALUE *argv, VALUE self, bool inverse, bool inplace) {
412
443
  VALUE threshold, replacement, opts;
413
444
  rb_scan_args(argc, argv, "21", &threshold, &replacement, &opts);
@@ -449,6 +480,33 @@ namespace Spyglass {
449
480
  return self;
450
481
  }
451
482
 
483
+ static VALUE rb_warp_perspective(VALUE self, VALUE corners, VALUE size) {
484
+ std::vector<cv::Point> _corners = Contour::to_value_vector(SG_GET_CONTOUR(corners));
485
+ cv::Size *_size = SG_GET_SIZE(size);
486
+ cv::Mat *img = SG_GET_IMAGE(self);
487
+ cv::Mat *result = new cv::Mat(_size->height, _size->width, CV_8UC3);
488
+
489
+ // Convert the corner points to `Point2f`, as `getPerspectiveTransform` only
490
+ // works with that kind of array.
491
+ std::vector<cv::Point2f> corner_pts;
492
+ for(int i = 0; i < _corners.size(); i++) {
493
+ cv::Point2f pt;
494
+ pt.x = _corners[i].x;
495
+ pt.y = _corners[i].y;
496
+ corner_pts.push_back(pt);
497
+ }
498
+
499
+ std::vector<cv::Point2f> quad_pts;
500
+ quad_pts.push_back(cv::Point2f(0, 0));
501
+ quad_pts.push_back(cv::Point2f(_size->width, 0));
502
+ quad_pts.push_back(cv::Point2f(_size->width, _size->height));
503
+ quad_pts.push_back(cv::Point2f(0, _size->height));
504
+
505
+ cv::Mat transmtx = cv::getPerspectiveTransform(corner_pts, quad_pts);
506
+ cv::warpPerspective(*img, *result, transmtx, result->size());
507
+ return Data_Wrap_Struct(ImageClass, NULL, rb_free, result);
508
+ }
509
+
452
510
  static VALUE rb_write(VALUE self, VALUE filename) {
453
511
  Check_Type(filename, T_STRING);
454
512
 
data/ext/spyglass/image.h CHANGED
@@ -28,6 +28,8 @@ namespace Spyglass {
28
28
  static VALUE rb_fill_inplace(int argc, VALUE *argv, VALUE self);
29
29
  static VALUE rb_load(int argc, VALUE *argv, VALUE klass);
30
30
  static VALUE rb_mean(int argc, VALUE *argv, VALUE klass);
31
+ static VALUE rb_resize(VALUE self, VALUE size);
32
+ static VALUE rb_resize_inplace(VALUE self, VALUE size);
31
33
  static VALUE rb_threshold(int argc, VALUE *argv, VALUE klass);
32
34
  static VALUE rb_threshold_inplace(int argc, VALUE *argv, VALUE klass);
33
35
  static VALUE rb_threshold_inv(int argc, VALUE *argv, VALUE klass);
@@ -36,6 +38,7 @@ namespace Spyglass {
36
38
  static VALUE rb_get_contours(VALUE self);
37
39
  static VALUE rb_get_rows(VALUE self);
38
40
  static VALUE rb_get_size(VALUE self);
41
+ static VALUE rb_warp_perspective(VALUE self, VALUE corners, VALUE size);
39
42
  static VALUE rb_write(VALUE self, VALUE filename);
40
43
  static VALUE rb_zeros(int argc, VALUE *argv, VALUE klass);
41
44
 
@@ -1,3 +1,3 @@
1
1
  module Spyglass
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -113,4 +113,22 @@ describe Spyglass::Image do
113
113
  expect( im.cols ).to eq(512)
114
114
  end
115
115
  end
116
+
117
+ describe '#resize' do
118
+ it 'should resize the image' do
119
+ new_img = lena.resize(Spyglass::Size.new(1024, 1024))
120
+
121
+ expect( new_img.rows ).to eq(1024)
122
+ expect( new_img.cols ).to eq(1024)
123
+ end
124
+ end
125
+
126
+ describe '#resize!' do
127
+ it 'should resize the image in place' do
128
+ lena.resize!(Spyglass::Size.new(1024, 1024))
129
+
130
+ expect( lena.rows ).to eq(1024)
131
+ expect( lena.cols ).to eq(1024)
132
+ end
133
+ end
116
134
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spyglass
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - André Medeiros
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-09-06 00:00:00.000000000 Z
11
+ date: 2013-09-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -84,8 +84,10 @@ files:
84
84
  - examples/background_subtractor.rb
85
85
  - examples/cascade_classifier.rb
86
86
  - examples/contours.rb
87
+ - examples/corners.rb
87
88
  - examples/images/apple.jpg
88
89
  - examples/images/beach.jpg
90
+ - examples/images/card.jpg
89
91
  - examples/video_capture.rb
90
92
  - ext/spyglass/background_subtractor.cc
91
93
  - ext/spyglass/background_subtractor.h