paperclip-facecrop 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
Binary file
data/README.md CHANGED
@@ -13,19 +13,47 @@ Requirements:
13
13
 
14
14
  Installation:
15
15
  -------------
16
- - Install the gem
17
-
18
- `gem install paperclip-facecrop'`
19
-
20
- - Add to `Gemfile`
16
+ - Add to your application `Gemfile`
21
17
 
22
18
  gem 'paperclip-facecrop'
19
+
20
+ - Type
21
+
22
+ bundle install
23
23
 
24
24
  - Write an initializer setting the path of the haarcascade filters(`initializers/paperclip.rb` for example):
25
25
 
26
- Paperclip::FaceCrop.classifiers = ["/usr/local/share/opencv/haarcascades/haarcascade_frontalface_alt_tree.xml"]
26
+ Paperclip::FaceCrop.classifiers = {
27
+ :face => ["/usr/local/share/opencv/haarcascades/haarcascade_frontalface_alt.xml"]
28
+ }
29
+
30
+ You can use more than one filter to try more accurate searches:
31
+
32
+ Paperclip::FaceCrop.classifiers = {
33
+ :face => [
34
+ "/usr/local/share/opencv/haarcascades/haarcascade_frontalface_alt.xml",
35
+ "/usr/local/share/opencv/haarcascades/haarcascade_frontalface_alt_tree.xml",
36
+ "/usr/local/share/opencv/haarcascades/haarcascade_profileface.xml"
37
+ ]
38
+ }
39
+
40
+ In order to try to avoid some false positives, you can also specify other classifiers to detect other parts of the face. In that case,
41
+ only the found areas that contain parts like a mouth, an eye or a nose will be considered a face:
42
+
43
+ Paperclip::FaceCrop.classifiers = {
44
+ :face => [
45
+ "/usr/local/share/opencv/haarcascades/haarcascade_frontalface_alt.xml",
46
+ "/usr/local/share/opencv/haarcascades/haarcascade_frontalface_alt_tree.xml",
47
+ "/usr/local/share/opencv/haarcascades/haarcascade_profileface.xml"
48
+ ],
49
+ :parts => [
50
+ "/usr/local/share/opencv/haarcascades/haarcascade_mcs_nose.xml",
51
+ "/usr/local/share/opencv/haarcascades/haarcascade_mcs_lefteye.xml",
52
+ "/usr/local/share/opencv/haarcascades/haarcascade_mcs_righteye.xml"
53
+ ]
54
+ }
55
+
27
56
 
28
- You can use more than one filter if you want in order to try more accurate searches.
29
57
 
30
58
  Usage:
31
59
  ------
@@ -40,6 +68,13 @@ Just specify your image styles as usual and set :face_crop as the processor:
40
68
 
41
69
  In case no faces were found, it will behave simply as the `Paperclip::Thumbnail` processor
42
70
 
71
+
72
+ You can also set the debug mode to draw on the image the detected regions:
73
+
74
+ Paperclip::FaceCrop.debug = (Rails.env == 'development')
75
+
76
+ ![](https://github.com/dagi3d/paperclip-facecrop/raw/master/README_example_b.jpg)
77
+
43
78
  Credits:
44
79
  --------
45
80
  Copyright (c) 2011 Borja Martín Sánchez de Vivar <borjamREMOVETHIS@dagi3d.net> - <http://dagi3d.net>, released under the MIT license
Binary file
@@ -1,33 +1,57 @@
1
1
  require 'opencv'
2
2
 
3
+ class OpenCV::CvAvgComp
4
+ def to_s
5
+ "#{self.x},#{self.y}-#{self.width}x#{self.height}"
6
+ end
7
+ end
8
+
3
9
  class Paperclip::FaceCrop < Paperclip::Thumbnail
10
+
11
+ @@debug = false
4
12
 
5
13
  cattr_accessor :classifiers
6
-
14
+ cattr_accessor :debug
15
+
7
16
  def initialize(file, options = {}, attachment = nil)
8
17
  super(file, options, attachment)
9
18
 
10
- x_coords = []
11
- y_coords = []
12
- widths = []
13
- heights = []
19
+ faces_regions = []
20
+ faces_parts_regions = []
21
+
22
+ raise "No classifiers were defined" if self.classifiers.nil?
14
23
 
15
- raise "No classifiers were defined" if Paperclip::FaceCrop.classifiers.nil?
24
+ image = OpenCV::IplImage.load(file.path, 1)
16
25
 
17
- image = OpenCV::IplImage.load(file.path)
26
+ faces_regions = detect_regions(image, self.classifiers[:face])
18
27
 
19
- Paperclip::FaceCrop.classifiers.each do |classifier|
20
- detector = OpenCV::CvHaarClassifierCascade::load(classifier)
21
- detector.detect_objects(image) do |region|
22
- x_coords << region.top_left.x << region.bottom_right.x
23
- y_coords << region.top_left.y << region.bottom_right.y
24
- widths << region.width
25
- heights << region.height
28
+ #Paperclip::FaceCrop.classifiers[:nose]
29
+ unless self.classifiers[:parts].nil?
30
+ faces_parts_regions = detect_regions(image, self.classifiers[:parts], OpenCV::CvColor::Red)
31
+
32
+ faces_regions.reject! do |face_region|
33
+ region = faces_parts_regions.detect do |part_region|
34
+ regions_overlap?(face_region, part_region)
35
+ end
36
+
37
+ region.nil?
26
38
  end
27
39
  end
28
40
 
29
- @has_faces = x_coords.size > 0
41
+ x_coords = []
42
+ y_coords = []
43
+ widths = []
44
+ heights = []
45
+
46
+ faces_regions.each do |region|
47
+ x_coords << region.top_left.x << region.bottom_right.x
48
+ y_coords << region.top_left.y << region.bottom_right.y
49
+ widths << region.width
50
+ heights << region.height
51
+ end
30
52
 
53
+ @has_faces = faces_regions.size > 0
54
+
31
55
  if @has_faces
32
56
  @top_left_x = x_coords.min
33
57
  @top_left_y = y_coords.min
@@ -37,7 +61,7 @@ class Paperclip::FaceCrop < Paperclip::Thumbnail
37
61
  # average faces areas
38
62
  average_face_width = widths.sum / widths.size
39
63
  average_face_height = heights.sum / heights.size
40
-
64
+
41
65
  # calculating the surrounding margin of the area that covers all the found faces
42
66
  #
43
67
 
@@ -53,25 +77,45 @@ class Paperclip::FaceCrop < Paperclip::Thumbnail
53
77
 
54
78
  # if the new area is smaller than the target geometry, it's scaled so the final image isn't resampled
55
79
  #
56
- if @faces_width < @target_geometry.width
80
+ if @faces_width < @target_geometry.width
57
81
  delta_width = (@target_geometry.width - @faces_width) / 2
58
82
  @top_left_x -= delta_width
59
83
  @bottom_right_x += delta_width
60
84
  calculate_bounds
61
85
  end
62
86
 
63
- if @faces_height < @target_geometry.height
87
+ #raise (@target_geometry.height > 0 and @faces_height < @target_geometry.height).to_s
88
+
89
+ if (@target_geometry.height > 0 and @faces_height < @target_geometry.height)
64
90
  delta_height = (@target_geometry.height - @faces_height) / 2
65
91
  @top_left_y -= delta_height
66
92
  @bottom_right_y += delta_height
67
93
  calculate_bounds
68
94
  end
69
95
 
96
+ @faces_height = @faces_width if @target_geometry.height == 0
97
+
70
98
  @current_geometry = Paperclip::Geometry.new(@faces_width, @faces_height)
71
99
  end
72
100
 
73
101
  end
74
-
102
+
103
+
104
+ def transformation_command
105
+ return super unless @has_faces
106
+
107
+ scale, crop = @current_geometry.transformation_to(@target_geometry, crop?)
108
+ faces_crop = "%dx%d+%d+%d" % [@faces_width, @faces_height, @top_left_x, @top_left_y]
109
+
110
+ trans = []
111
+ trans << "-crop" << %["#{faces_crop}"] << "+repage"
112
+ trans << "-resize" << %["#{scale}"] unless scale.nil? || scale.empty?
113
+ trans << "-crop" << %["#{crop}"] << "+repage" if crop
114
+ trans
115
+ end
116
+
117
+ private
118
+
75
119
  # calculate_bounds
76
120
  #
77
121
  def calculate_bounds
@@ -85,17 +129,30 @@ class Paperclip::FaceCrop < Paperclip::Thumbnail
85
129
  @faces_height = @bottom_right_y - @top_left_y
86
130
  end
87
131
 
88
-
89
- def transformation_command
90
- return super unless @has_faces
132
+ # detect_regions
133
+ #
134
+ def detect_regions(image, classifiers, color = OpenCV::CvColor::Blue)
135
+ regions = []
91
136
 
92
- scale, crop = @current_geometry.transformation_to(@target_geometry, crop?)
93
- faces_crop = "%dx%d+%d+%d" % [@faces_width, @faces_height, @top_left_x, @top_left_y]
137
+ classifiers.each do |classifier|
138
+ detector = OpenCV::CvHaarClassifierCascade::load(classifier)
139
+ detector.detect_objects(image) do |region|
140
+ regions << region
141
+ image.rectangle!(region.top_left, region.bottom_right, :color => color) if self.debug
142
+ end
143
+ end
94
144
 
95
- trans = []
96
- trans << "-crop" << %["#{faces_crop}"] << "+repage"
97
- trans << "-resize" << %["#{scale}"] unless scale.nil? || scale.empty?
98
- trans << "-crop" << %["#{crop}"] << "+repage" if crop
99
- trans
145
+ if self.debug
146
+ image.save_image(@file.path)
147
+ Rails.logger.info(regions)
148
+ end
149
+
150
+ regions
151
+ end
152
+
153
+ def regions_overlap?(r1, r2)
154
+ dx = (r2.x - r1.x).abs + r2.width
155
+ dy = (r2.y - r1.y).abs + r2.height;
156
+ return (dx < r1.width + r2.width && dy < r1.height + r2.height);
100
157
  end
101
158
  end
data/lib/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  class Paperclip
2
2
  class FaceCrop
3
- VERSION = "0.0.1"
3
+ VERSION = "0.0.2"
4
4
  end
5
5
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 1
9
- version: 0.0.1
8
+ - 2
9
+ version: 0.0.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - "Borja Mart\xC3\xADn"
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-05-03 00:00:00 +02:00
17
+ date: 2011-05-06 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -58,6 +58,7 @@ files:
58
58
  - Gemfile
59
59
  - README.md
60
60
  - README_example.jpg
61
+ - README_example_b.jpg
61
62
  - Rakefile
62
63
  - lib/paperclip-facecrop.rb
63
64
  - lib/version.rb