Skip to content

Instantly share code, notes, and snippets.

@rondale-sc
Created September 21, 2011 23:05
Show Gist options
  • Save rondale-sc/1233581 to your computer and use it in GitHub Desktop.
Save rondale-sc/1233581 to your computer and use it in GitHub Desktop.
The hough transform in ruby. Only looks for straight black lines.
begin
['oily_png', 'pp'].each do |g|
require g
end
rescue LoadError => e
puts "Could not load '#{e}'"; exit
end
class Hough
Convert = "/usr/local/bin/convert"
def initialize(image_path, options={})
@verbose = options.delete(:verbose)
@image = ChunkyPNG::Image.from_file(image_path)
@image_path = image_path
end
def is_dark?(color)
ChunkyPNG::Color.r(color) + ChunkyPNG::Color.g(color) + ChunkyPNG::Color.b(color) < 40
end
def is_light?(color)
ChunkyPNG::Color.r(color) + ChunkyPNG::Color.g(color) + ChunkyPNG::Color.b(color) > 600
end
def angles(theta)
@angles ||= {}
@angles[theta] ||= {:cos => Math.cos(theta), :sin => Math.sin(theta)}
end
def get_hough_matrix
hough = Hash.new(0)
@image.height.times do |y|
@image.width.times do |x|
if is_dark?(@image[x,y]) && is_light?(@image[x,y + 1])
(0..20).step(0.2).each do |theta|
distance = (x * angles(theta)[:cos] + y * angles(theta)[:sin]).to_i
hough[[theta, distance]] += 1 if distance >= 0
end
end
end
end
return hough
end
def average_theta
at = (get_hough_matrix.sort_by {|k,v| v }.take(20).inject(0.0) {|m,v| m + v[0][0] } / 20)
pp "Average theta: #{at}"
return at
end
def rotate(output_path)
`#{Convert} #{@image_path} -rotate #{average_theta} #{output_path}`
end
end
if __FILE__ == $0
output_path = "path/to/output"
image_path = "path/to/image"
h = Hough.new(image_path, :verbose => true)
h.rotate(output_path)
`open #{output_path}`
end
@damncabbage
Copy link

I'd love to use parts of this gist for a (non-commercial) project of mine.

If you don't mind me using it, could you please specify under what license it's available for use (or if it's flat-out just public domain)?

(I know this request sounds dumb, but I'd prefer to avoid trouble if at all possible.)

@rondale-sc
Copy link
Author

Sure, would love if you'd use it, and thanks for asking. I would mention that the parameter for rotate that convert accepts is incorrect you need to calculate the arc-tangent to get the angle. (Check out Math.atan()) Use it however you like, I'm not going to license the gist. Attribution would be nice, but I don't really care. Wish you the best of luck, have fun.

@wheresalice
Copy link

Ooh nice. This is just what I was looking for!

There is however a small bug, it sometimes tries accessing a coordinate out of bounds on line 35. So I've changed line 33 to read (@image.height - 1).times do |y| which has fixed it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment