diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..81f4ea0
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+paperclip-facecrop
\ No newline at end of file
diff --git a/.idea/.rakeTasks b/.idea/.rakeTasks
new file mode 100644
index 0000000..336edcd
--- /dev/null
+++ b/.idea/.rakeTasks
@@ -0,0 +1,7 @@
+
+
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..e206d70
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..f415bd5
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,25 @@
+
+
+
+ http://www.w3.org/1999/xhtml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..b7cd248
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/.idea/paperclip-facecrop.iml b/.idea/paperclip-facecrop.iml
new file mode 100644
index 0000000..82133fd
--- /dev/null
+++ b/.idea/paperclip-facecrop.iml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml
new file mode 100644
index 0000000..922003b
--- /dev/null
+++ b/.idea/scopes/scope_settings.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..c80f219
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..31b7098
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,401 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1347506012506
+ 1347506012506
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/README.md b/README.md
index fb2bbc4..576e1d2 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@ Paperclip::FaceCrop
====================
`Paperclip::FaceCrop` is a [Paperclip][paperclip] processor that is aware of the faces found on the image
so that they aren't cropped or aren't shown too small while generating the thumbnails.
-It can use the [OpenCV][opencv] library or the [Face.com][face_com] web service(or both at the same time) for the facial recognition.
+It can use the [OpenCV][opencv] library, the [Face.com][face_com] or [LambdaLabs][lambda_labs] web service(or all three at the same time) for the facial recognition.
![](https://github.com/dagi3d/paperclip-facecrop/raw/master/README_example.jpg)
@@ -25,6 +25,12 @@ checkout the OpenCV_2.2 branch or just remove the line 143 from `/ext/opencv/cve
In order to use the Face.com service, you will also need to register in order to get your api key and api secret for your application.
+### lambdal.com
+- [rest-client][rest-client]
+
+In order to use the lambdal.com service, you will also need to register in order to get your api key for your application.
+
+
Installation:
-------------
@@ -85,6 +91,13 @@ only the found areas that contain parts like a mouth, an eye or a nose will be c
'FaceCom' => { :api_key => "", :api_secret => ""}
}
+### lambdal.com
+
+ Paperclip::FaceCrop.detectors = {
+ 'LambdaLabs' => {:mashape_authorization => ""}
+ }
+
+
Usage:
------
@@ -114,6 +127,7 @@ Copyright (c) 2011 Borja Martín Sánchez de Vivar
The photo used as example belongs to [Jesper Rønn-Jensen](http://www.flickr.com/photos/jesper/)
[face_com]: http://face.com
+[lambda_labs]: http://lambdal.com
[rest-client]: https://rubygems.org/gems/rest-client
[paperclip]: https://github.com/thoughtbot/paperclip
[opencv]: http://opencv.willowgarage.com/
diff --git a/lib/detectors/face_com.rb b/lib/detectors/face_com.rb
index d70ba8a..8281f40 100755
--- a/lib/detectors/face_com.rb
+++ b/lib/detectors/face_com.rb
@@ -4,7 +4,7 @@ class FaceCrop::Detector::FaceCom < FaceCrop::Detector::Base
URL = "http://api.face.com/faces/detect.json"
def detect_faces(file)
- query = @options.to_query
+ query = @options.to_query + "&detector=Aggressive"
url = "#{URL}?#{query}"
response = RestClient.post url, :file => File.new(file)
diff --git a/lib/detectors/lambda_labs.rb b/lib/detectors/lambda_labs.rb
new file mode 100644
index 0000000..e12a8b1
--- /dev/null
+++ b/lib/detectors/lambda_labs.rb
@@ -0,0 +1,27 @@
+require 'rest_client'
+
+class FaceCrop::Detector::LambdaLabs < FaceCrop::Detector::Base
+ URL = "https://lambda-face-recognition.p.mashape.com/detect"
+
+ def detect_faces(file)
+ response = RestClient.post(URL,
+ {:files => File.new(file)},
+ {:content_type => 'json', "X-Mashape-Authorization" => @options[:mashape_authorization]})
+
+ response = JSON.parse(response)
+
+ photo = response['photos'].first
+ photo['tags'].map do |tag|
+ # values are returned as percentual values
+
+ x = tag['center']['x'].to_i
+ y = tag['center']['y'].to_i
+ w = tag['width'].to_i
+ h = tag['height'].to_i
+
+ region = FaceCrop::Detector::Region.new(x, y, w, h)
+ region.color = "blue"
+ region
+ end
+ end
+end
\ No newline at end of file
diff --git a/lib/face_crop.rb b/lib/face_crop.rb
index dff20d9..4012357 100755
--- a/lib/face_crop.rb
+++ b/lib/face_crop.rb
@@ -5,6 +5,7 @@ module FaceCrop
module Detector
autoload :FaceCom, File.expand_path('../detectors/face_com', __FILE__)
+ autoload :LambdaLabs, File.expand_path('../detectors/lambda_labs', __FILE__)
autoload :OpenCV, File.expand_path('../detectors/opencv', __FILE__)
# Base
diff --git a/lib/processor.rb b/lib/processor.rb
index 5816c40..16d56eb 100755
--- a/lib/processor.rb
+++ b/lib/processor.rb
@@ -4,10 +4,10 @@ module Paperclip
class FaceCrop < Paperclip::Thumbnail
@@debug = false
-
+
#cattr_accessor :classifiers
cattr_accessor :debug
-
+
def self.detectors=(detectors)
@@detectors = detectors.map do |name, options|
#require File.expand_path("../detectors/#{name}", __FILE__)
@@ -15,16 +15,16 @@ def self.detectors=(detectors)
detector = detector_class.new(options)
end
end
-
+
def initialize(file, options = {}, attachment = nil)
super(file, options, attachment)
-
-
+
+
raise "No detectors were defined" if @@detectors.nil?
-
+
faces_regions = []
faces_parts_regions = []
-
+
@@detectors.each do |detector|
begin
faces_regions += detector.detect(file.path)
@@ -33,82 +33,92 @@ def initialize(file, options = {}, attachment = nil)
Rails.logger.error(e)
end
end
-
-
+
+
x_coords, y_coords, widths, heights = [], [], [], []
-
+
faces_regions.each do |region|
x_coords << region.top_left.x << region.bottom_right.x
y_coords << region.top_left.y << region.bottom_right.y
widths << region.width
heights << region.height
end
-
-
+
+
@has_faces = faces_regions.size > 0
-
+
if @has_faces
@top_left_x = x_coords.min
@top_left_y = y_coords.min
@bottom_right_x = x_coords.max
@bottom_right_y = y_coords.max
-
-
-
+
+
+
#puts @top_left_x.to_s
-
+
# average faces areas
average_face_width = widths.sum / widths.size
average_face_height = heights.sum / heights.size
-
+
# calculating the surrounding margin of the area that covers all the found faces
#
-
+
# new width
@top_left_x -= average_face_width / 1.2
@bottom_right_x += average_face_width / 1.2
-
-
-
+
+
# new height
#puts ":::#{@top_left_x}---#{average_face_width}"
#return
-
+
@top_left_y -= average_face_height / 1.2
- @bottom_right_y += average_face_height / 1.6
+ @bottom_right_y += average_face_height / 1.2
+
calculate_bounds
-
-
-
+
+
+
# if the new area is smaller than the target geometry, it's scaled so the final image isn't resampled
#
- if @faces_width < @target_geometry.width
+ if @faces_width < @target_geometry.width
delta_width = (@target_geometry.width - @faces_width) / 2
@top_left_x -= delta_width
@bottom_right_x += delta_width
calculate_bounds
end
-
+
# scale the image so the cropped image still displays the faces
if @faces_width > @target_geometry.width && crop?
ratio = @faces_width / @target_geometry.width
@faces_height = @target_geometry.height * ratio
end
-
+
#raise (@target_geometry.height > 0 and @faces_height < @target_geometry.height).to_s
-
+
if (@target_geometry.height > 0 and @faces_height < @target_geometry.height)
delta_height = (@target_geometry.height - @faces_height) / 2
@top_left_y -= delta_height
@bottom_right_y += delta_height
calculate_bounds
end
-
+
+
+ #fix image position for extrem aspect ratios
+ if @target_geometry.width / @target_geometry.height < 0.6
+ @top_left_x = x_coords.min * 1.2
+ end
+
+ if @target_geometry.width / @target_geometry.height > 1.4
+ @top_left_y = y_coords.min * 1.2
+ end
+
@faces_height = @faces_width if @target_geometry.height == 0
-
+
@current_geometry = Paperclip::Geometry.new(@faces_width, @faces_height)
-
+
if @@debug
parameters = []
parameters << "-stroke" << "green"
@@ -117,43 +127,43 @@ def initialize(file, options = {}, attachment = nil)
parameters << ":source"
parameters << ":dest"
parameters = parameters.flatten.compact.join(" ").strip.squeeze(" ")
-
+
Paperclip.run("convert", parameters, :source => "#{File.expand_path(file.path)}", :dest => "#{File.expand_path(file.path)}")
end
-
-
+
+
end
end
-
-
+
+
def transformation_command
return super unless @has_faces
-
+
scale, crop = @current_geometry.transformation_to(@target_geometry, crop?)
faces_crop = "%dx%d+%d+%d" % [@faces_width, @faces_height, @top_left_x, @top_left_y]
-
+
trans = []
trans << "-crop" << %["#{faces_crop}"] << "+repage"
trans << "-resize" << %["#{scale}"] unless scale.nil? || scale.empty?
trans << "-crop" << %["#{crop}"] << "+repage" if crop
-
+
trans
end
-
+
private
-
+
# calculate_bounds
#
def calculate_bounds
- @top_left_x = 0 if @top_left_x < 0
+ @top_left_x = 0 if @top_left_x < 0
@bottom_right_x = @current_geometry.width if @bottom_right_x > @current_geometry.width
@top_left_y = 0 if @top_left_y < 0
@bottom_right_y = @current_geometry.height if @bottom_right_y > @current_geometry.height
-
+
@faces_width = @bottom_right_x - @top_left_x
@faces_height = @bottom_right_y - @top_left_y
end
-
+
end
end
\ No newline at end of file