spyglass 0.0.2
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 +7 -0
- data/.gitignore +18 -0
- data/.rspec +6 -0
- data/.travis.yml +11 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +5 -0
- data/examples/background_subtractor.rb +35 -0
- data/examples/cascade_classifier.rb +21 -0
- data/examples/contours.rb +24 -0
- data/examples/images/apple.jpg +0 -0
- data/examples/images/beach.jpg +0 -0
- data/examples/video_capture.rb +15 -0
- data/ext/spyglass/background_subtractor.cc +78 -0
- data/ext/spyglass/background_subtractor.h +18 -0
- data/ext/spyglass/cascade_classifier.cc +70 -0
- data/ext/spyglass/cascade_classifier.h +18 -0
- data/ext/spyglass/color.cc +83 -0
- data/ext/spyglass/color.h +22 -0
- data/ext/spyglass/color_space.cc +39 -0
- data/ext/spyglass/color_space.h +13 -0
- data/ext/spyglass/contour.cc +92 -0
- data/ext/spyglass/contour.h +22 -0
- data/ext/spyglass/extconf.rb +6 -0
- data/ext/spyglass/gui.cc +27 -0
- data/ext/spyglass/gui.h +15 -0
- data/ext/spyglass/image.cc +482 -0
- data/ext/spyglass/image.h +46 -0
- data/ext/spyglass/point.cc +78 -0
- data/ext/spyglass/point.h +23 -0
- data/ext/spyglass/prelude.h +42 -0
- data/ext/spyglass/rect.cc +131 -0
- data/ext/spyglass/rect.h +30 -0
- data/ext/spyglass/size.cc +89 -0
- data/ext/spyglass/size.h +25 -0
- data/ext/spyglass/spyglass.cc +35 -0
- data/ext/spyglass/spyglass.h +29 -0
- data/ext/spyglass/video_capture.cc +96 -0
- data/ext/spyglass/video_capture.h +20 -0
- data/ext/spyglass/window.cc +93 -0
- data/ext/spyglass/window.h +23 -0
- data/lib/spyglass.rb +6 -0
- data/lib/spyglass/color_space.rb +12 -0
- data/lib/spyglass/version.rb +3 -0
- data/spec/fixtures/haarcascade_frontalface_default.xml +35712 -0
- data/spec/fixtures/lena.jpg +0 -0
- data/spec/matchers/close_to.rb +6 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/spyglass/background_subtractor_spec.rb +23 -0
- data/spec/spyglass/cascade_classifier_spec.rb +28 -0
- data/spec/spyglass/color_space_spec.rb +13 -0
- data/spec/spyglass/color_spec.rb +54 -0
- data/spec/spyglass/contour_spec.rb +26 -0
- data/spec/spyglass/gui/window_spec.rb +21 -0
- data/spec/spyglass/image_spec.rb +116 -0
- data/spec/spyglass/point_spec.rb +41 -0
- data/spec/spyglass/rect_spec.rb +103 -0
- data/spec/spyglass/size_spec.rb +52 -0
- data/spyglass.gemspec +26 -0
- data/tasks/compile.rake +6 -0
- data/tasks/gem.rake +2 -0
- data/tasks/rspec.rake +21 -0
- metadata +177 -0
Binary file
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spyglass::BackgroundSubtractor do
|
4
|
+
let(:bg) { Spyglass::BackgroundSubtractor.new }
|
5
|
+
let(:lena) { Spyglass::Image.load(fixture_path('lena.jpg')) }
|
6
|
+
|
7
|
+
describe '.new' do
|
8
|
+
it 'should work with no arguments' do
|
9
|
+
expect( bg ).to be_a Spyglass::BackgroundSubtractor
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should work with an options hash' do
|
13
|
+
expect { Spyglass::BackgroundSubtractor.new(history: 50, threshold: 64) }.not_to raise_error
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#subtract' do
|
18
|
+
it 'should return a Spyglass::Image' do
|
19
|
+
delta = bg.subtract(lena, 1)
|
20
|
+
expect( delta ).to be_a Spyglass::Image
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spyglass::CascadeClassifier do
|
4
|
+
let(:classifier) { Spyglass::CascadeClassifier.new(fixture_path('haarcascade_frontalface_default.xml')) }
|
5
|
+
let(:lena) { Spyglass::Image.load(fixture_path('lena.jpg')) }
|
6
|
+
|
7
|
+
describe '.new' do
|
8
|
+
it 'should receive an argument' do
|
9
|
+
expect { Spyglass::CascadeClassifier.new }.to raise_error ArgumentError;
|
10
|
+
expect( classifier ).to be_a Spyglass::CascadeClassifier
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '.detect' do
|
15
|
+
it 'should return an array of Spyglass::Rect' do
|
16
|
+
rects = classifier.detect(lena, scale_factor: 1.3)
|
17
|
+
|
18
|
+
expect( rects ).to be_a Array
|
19
|
+
|
20
|
+
rect = rects.first
|
21
|
+
expect( rect ).to be_a Spyglass::Rect
|
22
|
+
expect( rect.x ).to be_close_to 215, threshold: 10
|
23
|
+
expect( rect.y ).to be_close_to 202, threshold: 10
|
24
|
+
expect( rect.width ).to be_close_to 174, threshold: 10
|
25
|
+
expect( rect.height ).to be_close_to 174, threshold: 10
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spyglass::ColorSpace do
|
4
|
+
describe '[]' do
|
5
|
+
it 'should return a valid color space code when the conversion is defined' do
|
6
|
+
expect(Spyglass::ColorSpace[:RGB => :Gray]).to eq(7)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should throw an exception when a conversion isnt defined' do
|
10
|
+
expect { Spyglass::ColorSpace[:RGB => :FairyDust] }.to raise_error ArgumentError
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spyglass::Color do
|
4
|
+
let(:color) { Spyglass::Color.new(255, 123, 234) }
|
5
|
+
|
6
|
+
describe '.new' do
|
7
|
+
it 'should accept between 1 to 4 arguments' do
|
8
|
+
expect( Spyglass::Color.new(255) ).to be_a Spyglass::Color
|
9
|
+
expect( Spyglass::Color.new(255, 255) ).to be_a Spyglass::Color
|
10
|
+
expect( Spyglass::Color.new(255, 255, 255) ).to be_a Spyglass::Color
|
11
|
+
expect( Spyglass::Color.new(255, 255, 255, 255) ).to be_a Spyglass::Color
|
12
|
+
|
13
|
+
expect { Spyglass::Color.new }.to raise_error ArgumentError
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'getters' do
|
18
|
+
describe '#to_a' do
|
19
|
+
it 'should return an array with the color values' do
|
20
|
+
expected = [255, 123, 234, 0]
|
21
|
+
colors = color.to_a
|
22
|
+
|
23
|
+
expect( colors ).to eq(expected)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#[]' do
|
28
|
+
it 'should return the correct color values for indices between 0..3' do
|
29
|
+
expected = [255, 123, 234, 0]
|
30
|
+
colors = color.to_a
|
31
|
+
|
32
|
+
4.times do |idx|
|
33
|
+
expect( color[idx] ).to eq(expected[idx])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should return nil for anything < 0 or > 3' do
|
38
|
+
expect( color[-2] ).to be_nil
|
39
|
+
expect( color[4] ).to be_nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#zeros?' do
|
44
|
+
it 'should return true when the color is comprised only by zeros' do
|
45
|
+
zeros = Spyglass::Color.new(0, 0, 0, 0)
|
46
|
+
expect( zeros.zeros? ).to be_true
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should return false when the color has at least one element that is not zero' do
|
50
|
+
expect( color.zeros? ).to be_false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spyglass::Contour do
|
4
|
+
let(:empty_contour) { Spyglass::Contour.new }
|
5
|
+
let(:contour) do
|
6
|
+
points = 10.times.map { |i| Spyglass::Point.new(i + 1, i + 1) }
|
7
|
+
Spyglass::Contour.new points
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '.new' do
|
11
|
+
it 'should work without arguments' do
|
12
|
+
expect( empty_contour ).to be_a Spyglass::Contour
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should work with an array of points' do
|
16
|
+
expect { contour }.not_to raise_error
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#rect' do
|
21
|
+
it 'should return the bounding rect' do
|
22
|
+
expect( contour.rect.size.width ).to eq(10)
|
23
|
+
expect( contour.rect.size.height ).to eq(10)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spyglass::GUI::Window, gui: true do
|
4
|
+
let(:window) { Spyglass::GUI::Window.new("Image preview") }
|
5
|
+
let(:lena) { Spyglass::Image.load(fixture_path('lena.jpg')) }
|
6
|
+
|
7
|
+
describe '.new' do
|
8
|
+
it 'should require one argument' do
|
9
|
+
expect { Spyglass::GUI::Window.new }.to raise_error ArgumentError
|
10
|
+
expect( window ).to be_a Spyglass::GUI::Window
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'accessors' do
|
15
|
+
describe '#title' do
|
16
|
+
it 'should return the correct title' do
|
17
|
+
expect( window.title ).to eq("Image preview")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spyglass::Image do
|
4
|
+
let(:lena) { Spyglass::Image.load(fixture_path('lena.jpg')) }
|
5
|
+
|
6
|
+
describe '.load' do
|
7
|
+
it 'should require an argument' do
|
8
|
+
expect { Spyglass::Image.load }.to raise_error ArgumentError
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should return an instance of OpenCV::Image when passing a path' do
|
12
|
+
expect( Spyglass::Image.load(fixture_path('lena.jpg')) ).to be_a described_class
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '.zeros' do
|
17
|
+
it 'should require a size' do
|
18
|
+
expect { Spyglass::Image.zeros }.to raise_error ArgumentError
|
19
|
+
|
20
|
+
expect( Spyglass::Image.zeros(Spyglass::Size.new(20, 20)) ).to be_a Spyglass::Image
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should create an image filled with zeros' do
|
24
|
+
img = Spyglass::Image.zeros Spyglass::Size.new(50, 50)
|
25
|
+
mean = img.mean
|
26
|
+
|
27
|
+
expect( mean.zeros? ).to be_true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'accessors' do
|
32
|
+
describe '#rows' do
|
33
|
+
it 'should return the right number of rows for an image' do
|
34
|
+
expect( lena.rows ).to eq(512)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#cols' do
|
39
|
+
it 'should return the right number of columns for an image' do
|
40
|
+
expect( lena.cols ).to eq(512)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#size' do
|
45
|
+
it 'should be an instance of Spyglass::Size' do
|
46
|
+
expect( lena.size ).to be_a Spyglass::Size
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should return the correct values' do
|
50
|
+
expect( lena.size.width ).to eq( lena.cols )
|
51
|
+
expect( lena.size.height ).to eq( lena.rows )
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#erode' do
|
57
|
+
it 'should erode the image' do
|
58
|
+
eroded = lena.erode
|
59
|
+
|
60
|
+
expect( eroded.cols ).to eq( lena.cols )
|
61
|
+
expect( eroded.rows ).to eq( lena.rows )
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#crop' do
|
66
|
+
it 'should crop the image to the correct proportions' do
|
67
|
+
rect = Spyglass::Rect.new(0, 0, 256, 256)
|
68
|
+
cropped = lena.crop(rect)
|
69
|
+
|
70
|
+
expect( cropped.cols ).to eq(256)
|
71
|
+
expect( cropped.rows ).to eq(256)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#crop!' do
|
76
|
+
it 'should crop the image in place to the correct proportions' do
|
77
|
+
rect = Spyglass::Rect.new(0, 0, 256, 256)
|
78
|
+
lena.crop!(rect)
|
79
|
+
|
80
|
+
expect( lena.cols ).to eq(256)
|
81
|
+
expect( lena.rows ).to eq(256)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '#mean' do
|
86
|
+
it 'should return a Spyglass::Color' do
|
87
|
+
expect( lena.mean ).to be_a Spyglass::Color
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe '#write' do
|
92
|
+
it 'should write the image onto disk' do
|
93
|
+
Dir.mktmpdir do |dir|
|
94
|
+
path = File.join(dir, 'lena.jpg')
|
95
|
+
|
96
|
+
res = lena.write(path)
|
97
|
+
expect( File.exists?(path) ).to be_true
|
98
|
+
expect( res ).to be_true
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe '#copy!' do
|
104
|
+
it 'should copy the image inplace' do
|
105
|
+
im = Spyglass::Image.new
|
106
|
+
|
107
|
+
expect( im.rows ).to eq(0)
|
108
|
+
expect( im.cols ).to eq(0)
|
109
|
+
|
110
|
+
im.copy!(lena)
|
111
|
+
|
112
|
+
expect( im.rows ).to eq(512)
|
113
|
+
expect( im.cols ).to eq(512)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spyglass::Point do
|
4
|
+
let(:point) { Spyglass::Point.new(10, 20) }
|
5
|
+
|
6
|
+
describe '.new' do
|
7
|
+
it 'should require two arguments' do
|
8
|
+
expect { Spyglass::Point.new }.to raise_error ArgumentError
|
9
|
+
expect( point ).to be_a Spyglass::Point
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'accessors' do
|
14
|
+
describe '#x' do
|
15
|
+
it 'should return the correct X coordinate' do
|
16
|
+
expect( point.x ).to eq(10)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#y' do
|
21
|
+
it 'should return the correct Y coordinate' do
|
22
|
+
expect( point.y ).to eq(20)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'setters' do
|
28
|
+
describe '#x=' do
|
29
|
+
it 'should set the value of the X coordinate' do
|
30
|
+
point.x = 20
|
31
|
+
expect( point.x ).to eq(20)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
describe '#y=' do
|
35
|
+
it 'should set the value of the Y coordinate' do
|
36
|
+
point.y = 40
|
37
|
+
expect( point.y ).to eq(40)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spyglass::Rect do
|
4
|
+
let(:rect) { Spyglass::Rect.new(10, 20, 100, 200) }
|
5
|
+
|
6
|
+
describe '.new' do
|
7
|
+
it 'should require four arguments' do
|
8
|
+
expect { Spyglass::Rect.new }.to raise_error ArgumentError
|
9
|
+
expect( rect ).to be_a Spyglass::Rect
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'accessors' do
|
14
|
+
describe '#x' do
|
15
|
+
it 'should return the correct X coordinate' do
|
16
|
+
expect( rect.x ).to eq(10)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#y' do
|
21
|
+
it 'should return the correct Y coordinate' do
|
22
|
+
expect( rect.y ).to eq(20)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#width' do
|
27
|
+
it 'should return the correct value' do
|
28
|
+
expect( rect.width ).to eq(100)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#height' do
|
33
|
+
it 'should return the correct value' do
|
34
|
+
expect( rect.height ).to eq(200)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#area' do
|
39
|
+
it 'should return `width * height`' do
|
40
|
+
expect( rect.area ).to eq(20_000)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#size' do
|
45
|
+
it 'should be an instance of Spyglass::Size' do
|
46
|
+
expect( rect.size ).to be_a Spyglass::Size
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should return the correct values' do
|
50
|
+
expect( rect.size.width ).to eq( rect.width )
|
51
|
+
expect( rect.size.height ).to eq( rect.height )
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#point' do
|
56
|
+
it 'should be an instance of Spyglass::Point' do
|
57
|
+
expect( rect.point ).to be_a Spyglass::Point
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should return the correct values' do
|
61
|
+
expect( rect.point.x ).to eq( rect.x )
|
62
|
+
expect( rect.point.y ).to eq( rect.y )
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe 'setters' do
|
68
|
+
describe '#height=' do
|
69
|
+
it 'should set the value of the height' do
|
70
|
+
rect.height = 150
|
71
|
+
|
72
|
+
expect( rect.height ).to eq(150)
|
73
|
+
expect( rect.area ).to eq(15_000)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe '#width=' do
|
78
|
+
it 'should set the value of the width' do
|
79
|
+
rect.width = 300
|
80
|
+
|
81
|
+
expect( rect.width ).to eq(300)
|
82
|
+
expect( rect.area ).to eq(60_000)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe '#x=' do
|
87
|
+
it 'should set the value of the X coordinate' do
|
88
|
+
rect.x = 20
|
89
|
+
|
90
|
+
expect( rect.x ).to eq(20)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '#y=' do
|
95
|
+
it 'should set the value of the Y coordinate' do
|
96
|
+
rect.y = 40
|
97
|
+
|
98
|
+
expect( rect.y ).to eq(40)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|