paperclip-facecrop 0.0.1 → 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.
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