spyglass 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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