Skip to content

Commit

Permalink
Added sobel edge algorhytm.
Browse files Browse the repository at this point in the history
  • Loading branch information
mudasobwa committed Oct 22, 2014
1 parent cb06e00 commit 3b576f6
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 1 deletion.
54 changes: 54 additions & 0 deletions bin/magick_sobel
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env ruby
# Encoding: utf-8

require 'optparse'

lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
$LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)

require 'rmagick/screwdrivers'

# options = {
# :thoroughly => false,
# :logger => nil
# }.merge(options)

options = {}

OptionParser.new do |opts|
opts.banner = "Usage: #{$0} [options] FILE"

# Quality
opts.on("-q", "--quality [1-100]", Integer, "Quality of resulting JPEG (default: 90)") do |quality|
options[:quality] = quality
end

# Thoroughly
opts.on("-r", "--roughly", "If set, the image will not be grayscaled before processing (requires less resources, default: false)") do |roughly|
options[:roughly] = !!roughly
end

# Verbose?
opts.on("-v", "--verbose", "Run verbosely (default: false)") do |v|
if v
require 'logger'
options[:logger] = Logger.new STDOUT
end
end

# No argument, shows at tail. This will print an options summary.
opts.on_tail("-h", "--help", "Show this message") do
puts opts
exit
end

end.parse!

raise "Run `#{$0} --help` for execution examples. Exiting…" if ARGV.size < 1

file = ARGV.shift

outfile = File.basename(file).sub(/(\.\w+)$/, "-sobel\\1")
Magick::Screwdrivers::sobel(file, options).write(File.join File.dirname(file), outfile) {
self.quality = options[:quality] || 90
}
1 change: 1 addition & 0 deletions lib/rmagick/screwdrivers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require "rmagick/screwdrivers/poster"
require "rmagick/screwdrivers/collage"
require "rmagick/screwdrivers/scale"
require "rmagick/screwdrivers/sobel"

module Magick
module Screwdrivers
Expand Down
74 changes: 74 additions & 0 deletions lib/rmagick/screwdrivers/sobel.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# encoding: utf-8

require 'RMagick'

module Magick
class Image # monkeypatch
def at x, y
px = self.pixel_color(x, y)
(px.red + px.green + px.blue) / 3
end
end

module Screwdrivers
# based on http://blog.saush.com/2011/04/20/edge-detection-with-the-sobel-operator-in-ruby/
def self.sobel file, options={}
options = {
:roughly => false,
:logger => nil
}.merge(options)

sobel_x = [[-1,0,1], [-2,0,2], [-1,0,1]]
sobel_y = [[-1,-2,-1], [0,0,0], [1,2,1]]

begin
orig = img_from_file(file)
orig = orig.quantize 256, Magick::GRAYColorspace unless options[:roughly]
rescue
warn(options[:logger], "Skipping invalid file #{file}…")
return nil
end

# 500×375
scale = Math.sqrt(187_500.0 / (orig.columns * orig.rows))

info(options[:logger], "Original is [#{orig.columns}×#{orig.rows}] image")
info(options[:logger], "Scale factor: [#{scale}]")
img = scale < 1 ? orig.scale(scale) : orig

info(options[:logger], "Will process [#{img.columns}×#{img.rows}] image")

edge = Image.new(img.columns, img.rows) {
self.background_color = 'transparent'
}

for x in 1..img.columns-2
for y in 1..img.rows-2
pixel_x = (sobel_x[0][0] * img.at(x-1,y-1)) + (sobel_x[0][1] * img.at(x,y-1)) + (sobel_x[0][2] * img.at(x+1,y-1)) +
(sobel_x[1][0] * img.at(x-1,y)) + (sobel_x[1][1] * img.at(x,y)) + (sobel_x[1][2] * img.at(x+1,y)) +
(sobel_x[2][0] * img.at(x-1,y+1)) + (sobel_x[2][1] * img.at(x,y+1)) + (sobel_x[2][2] * img.at(x+1,y+1))

pixel_y = (sobel_y[0][0] * img.at(x-1,y-1)) + (sobel_y[0][1] * img.at(x,y-1)) + (sobel_y[0][2] * img.at(x+1,y-1)) +
(sobel_y[1][0] * img.at(x-1,y)) + (sobel_y[1][1] * img.at(x,y)) + (sobel_y[1][2] * img.at(x+1,y)) +
(sobel_y[2][0] * img.at(x-1,y+1)) + (sobel_y[2][1] * img.at(x,y+1)) + (sobel_y[2][2] * img.at(x+1,y+1))

val = Math.sqrt((pixel_x * pixel_x) + (pixel_y * pixel_y)).ceil
edge.pixel_color x, y, Pixel.new(val, val, val)
end
end

edge = edge.scale(orig.columns, orig.rows) if scale < 1

case orig.orientation
when Magick::RightTopOrientation
edge.rotate!(90)
when Magick::BottomRightOrientation
edge.rotate!(180)
when Magick::LeftBottomOrientation
edge.rotate!(-90)
end

edge
end
end
end
2 changes: 1 addition & 1 deletion rmagick-screwdrivers.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Gem::Specification.new do |s|
s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
s.bindir = 'bin'
s.executables = ['magick_collage', 'magick_poster', 'magick_scale']
s.executables = ['magick_collage', 'magick_poster', 'magick_scale', 'magick_sobel']
s.require_paths = ['lib']

s.add_development_dependency 'rspec'
Expand Down

0 comments on commit 3b576f6

Please sign in to comment.