yearbook 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
data/go.rb CHANGED
@@ -4,7 +4,10 @@ require 'yearbook'
4
4
  include Yearbook
5
5
  PIMGS = Dir.glob "#{File.expand_path '../spec/fixtures/images', '__FILE__'}/*.jpg"
6
6
 
7
+ =begin
7
8
  img = Yearbook::Image.new(PIMGS.first)
8
9
  img.write('test.jpg') do |i|
9
10
  i.bw
10
- end
11
+ i.resize_to_fit 200, 500
12
+ end
13
+ =end
@@ -0,0 +1,15 @@
1
+ require 'delegate'
2
+ class AttHash < SimpleDelegator
3
+ def initialize
4
+ @hsh = {}
5
+ super(@hsh)
6
+ end
7
+
8
+ def method_missing(foo, *args, &blk)
9
+ if @hsh.respond_to?(foo)
10
+ @hsh.send(foo, *args, &blk)
11
+ else
12
+ @hsh[foo.to_sym] = args
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ module Yearbook
2
+ module Classifier
3
+
4
+ DATA_DIR = File.expand_path('../../../data/classifiers', __FILE__ )
5
+ DATA_FILES = {
6
+ faces: File.join(DATA_DIR, 'haarcascade_frontalface_default.xml')
7
+
8
+ }
9
+
10
+
11
+ # returns an array of detected objects
12
+ def self.detect_objects(cv_image, object_type)
13
+ detector = load_detector(object_type.to_sym)
14
+
15
+ detector.detect_objects(cv_image)
16
+ end
17
+
18
+
19
+ def self.load_detector(object_type)
20
+ fname = DATA_FILES[object_type]
21
+ puts fname
22
+ OpenCV::CvHaarClassifierCascade::load( fname )
23
+ end
24
+
25
+ end
26
+ end
@@ -1,62 +1,96 @@
1
1
  require 'rmagick'
2
2
  require 'hashie'
3
+ require_relative 'att_hash'
4
+ require_relative 'classifier'
3
5
 
4
6
 
5
7
 
6
- require 'delegate'
7
- class AttHash < SimpleDelegator
8
8
 
9
- def initialize
10
- @hsh = {}
11
- super(@hsh)
12
- end
9
+ module Yearbook
10
+ class Image
13
11
 
14
- def method_missing(foo, *args, &blk)
15
- if @hsh.respond_to?(foo)
16
- @hsh.send(foo, *args, &blk)
17
- else
18
- @hsh[foo.to_sym] = args
12
+ attr_reader :filename
13
+ def initialize(fname)
14
+ @filename = fname
15
+ @objects = []
19
16
  end
20
- end
21
- end
22
17
 
23
18
 
19
+ def detect_objects(obj_type)
20
+ @objects = Classifier.detect_objects(cv_object, obj_type).to_a
21
+ end
24
22
 
25
- module Yearbook
26
- class Image
27
-
28
- def initialize(fname)
29
- @magick_image = read_magick_image(fname)
23
+ def detect_faces
24
+ detect_objects(:faces)
30
25
  end
31
26
 
27
+ def detected_objects
28
+ @objects
29
+ end
32
30
 
33
- def write(out_fname, &blk)
31
+ def write(base_out_fname, &blk)
34
32
  klass = self.class
35
- image_out = image_object
36
33
 
37
- if block_given?
38
- h = AttHash.new
39
- yield h
34
+ if @objects.empty?
35
+ img_objects = Array(image_object)
36
+ else
37
+ img_objects = @objects.map{|o| constitute_from_cv(o, image_object)}
38
+ end
40
39
 
41
-
42
- image_out = h.inject(image_out) do |img, (foo, args)|
43
- klass.send(foo, img, *args)
40
+ img_objects.each_with_index do |image_out, idx|
41
+ if block_given?
42
+ h = AttHash.new
43
+ yield h
44
+
45
+ # transform the image
46
+ image_out = h.inject(image_out) do |img, (foo, args)|
47
+ klass.send(foo, img, *args)
48
+ end
44
49
  end
45
- end
46
50
 
47
- klass.output(image_out, out_fname)
51
+ if idx == 0
52
+ out_fname = base_out_fname
53
+ else
54
+ out_fname = base_out_fname.sub(/\.(?=\w+$)/, "-#{idx}.")
55
+ end
56
+
57
+ klass.output(image_out, out_fname)
58
+ end
48
59
  end
49
60
 
50
61
 
62
+
63
+
64
+
51
65
  private
52
- def read_magick_image(fname)
53
- Magick::Image::read(fname).first
54
- end
55
66
 
67
+
68
+ # defer loading until it is needed
56
69
  def image_object
57
- @magick_image
70
+ @magick_image ||= load_magick_image(@filename)
58
71
  end
59
72
 
73
+ def cv_object
74
+ @cv_image ||= load_cv_image(@filename)
75
+ end
76
+
77
+
78
+
79
+ def constitute_from_cv(c, img)
80
+ pixels = img.dispatch(c.x, c.y, c.width, c.height, "RGB")
81
+
82
+ return Magick::Image.constitute(c.width, c.height, "RGB", pixels)
83
+ end
84
+
85
+
86
+ def load_magick_image(fname)
87
+ Magick::Image::read(fname).first
88
+ end
89
+
90
+
91
+ def load_cv_image(fname)
92
+ IplImage::load(fname)
93
+ end
60
94
 
61
95
 
62
96
  # Image manipulation methods at the class level
@@ -9,6 +9,10 @@ require 'yearbook'
9
9
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
10
10
 
11
11
 
12
+ IMAGE_DIR ||= File.expand_path '../spec/fixtures/images', '__FILE__'
13
+
14
+
15
+
12
16
  RSpec.configure do |config|
13
17
 
14
18
  config.filter_run_excluding skip: true
@@ -1,8 +1,59 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require 'spec_helper'
2
2
 
3
- describe "Yearbook" do
4
- it "passes" do
5
- expect(1).to eq 1
6
- end
7
- end
3
+ module Yearbook
4
+ describe Image do
5
+
6
+ context 'instance' do
7
+ before do
8
+ @fname = File.join(IMAGE_DIR, 'bush-george-w.jpg')
9
+ @image = Image.new(@fname)
10
+ @tempfile = Tempfile.new 'bush.jpg'
11
+ end
12
+
13
+ after do
14
+ @tempfile.unlink
15
+ end
16
+
17
+
18
+ describe 'initialization' do
19
+ it 'should have :filename reader' do
20
+ expect(@image.filename).to eq @fname
21
+ end
22
+ end
23
+
24
+ describe '#detect_faces' do
25
+ it 'should return an Array' do
26
+ expect( @image.detect_faces ).to be_an Array
27
+ end
28
+ end
29
+
30
+ describe '#write' do
31
+ it 'should write to disk' do
32
+ @image.write(@tempfile.path)
33
+ expect(@tempfile.size > 10000).to be_true
34
+ end
35
+
36
+ context 'after faces have been detected' do
37
+ before do
38
+ @image.detect_faces
39
+ end
8
40
 
41
+ it 'should write each object to disk' do
42
+ last_num = @image.detected_objects.count - 1
43
+ path = @tempfile.path
44
+ last_path = path.sub(/\.(?=\w+$)/, "-#{last_num}.")
45
+
46
+ @image.write(path)
47
+ expect(File.exists?(last_path)).to be_true
48
+ end
49
+
50
+ end
51
+ end
52
+
53
+
54
+
55
+ end
56
+
57
+
58
+ end
59
+ end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "yearbook"
8
- s.version = "0.1.0"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["dannguyen"]
12
- s.date = "2013-11-05"
12
+ s.date = "2013-11-06"
13
13
  s.description = "Easy face-cropping"
14
14
  s.email = "dansonguyen@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -32,6 +32,8 @@ Gem::Specification.new do |s|
32
32
  "data/classifiers/shameem_haarcascade_eye.xml",
33
33
  "go.rb",
34
34
  "lib/yearbook.rb",
35
+ "lib/yearbook/att_hash.rb",
36
+ "lib/yearbook/classifier.rb",
35
37
  "lib/yearbook/image.rb",
36
38
  "spec/fixtures/images/bush-george-w.jpg",
37
39
  "spec/fixtures/images/obama-barack.jpg",
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yearbook
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-11-05 00:00:00.000000000 Z
12
+ date: 2013-11-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rmagick
@@ -178,6 +178,8 @@ files:
178
178
  - data/classifiers/shameem_haarcascade_eye.xml
179
179
  - go.rb
180
180
  - lib/yearbook.rb
181
+ - lib/yearbook/att_hash.rb
182
+ - lib/yearbook/classifier.rb
181
183
  - lib/yearbook/image.rb
182
184
  - spec/fixtures/images/bush-george-w.jpg
183
185
  - spec/fixtures/images/obama-barack.jpg
@@ -203,7 +205,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
203
205
  version: '0'
204
206
  segments:
205
207
  - 0
206
- hash: 577978153578569035
208
+ hash: -163145999741884676
207
209
  required_rubygems_version: !ruby/object:Gem::Requirement
208
210
  none: false
209
211
  requirements: