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