diff --git a/.gitignore b/.gitignore index 4ee6b64..58aa30f 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ /spec/reports/ /tmp/ /vendor +.DS_Store +/test/output/ diff --git a/lib/edge_detect.rb b/lib/edge_detect.rb index 3604be2..7d07aea 100644 --- a/lib/edge_detect.rb +++ b/lib/edge_detect.rb @@ -8,3 +8,4 @@ require 'edge_detect/differ' require 'edge_detect/horizontal_differ' require 'edge_detect/vertical_differ' require 'edge_detect/edge_detector' +require 'edge_detect/sobel_edge_detector' diff --git a/lib/edge_detect/edge_detector.rb b/lib/edge_detect/edge_detector.rb index 5f58b71..7af04dd 100644 --- a/lib/edge_detect/edge_detector.rb +++ b/lib/edge_detect/edge_detector.rb @@ -11,16 +11,19 @@ module EdgeDetect end def detect_edges - h_differ = HorizontalDiffer.new(self.image) - v_differ = VerticalDiffer.new(self.image) + image = ChunkyPNG::Image.new(@image.width, @image.height, ChunkyPNG::Color::TRANSPARENT) + h_diff = HorizontalDiffer.new(self.image) + v_diff = VerticalDiffer.new(self.image) self.image.width.times do |i| self.image.height.times do |j| + value = (h_diff[i, j] + v_diff[i, j]).abs + image[i, j] = ChunkyPNG::Color.rgb(value, value, value) end end - - end + image + end end diff --git a/lib/edge_detect/gray_scaler.rb b/lib/edge_detect/gray_scaler.rb index 7e5529a..a5ea450 100644 --- a/lib/edge_detect/gray_scaler.rb +++ b/lib/edge_detect/gray_scaler.rb @@ -6,7 +6,23 @@ module EdgeDetect end def [](x, y) - ChunkyPNG::Color.to_grayscale(@image[x, y]) + begin + (ChunkyPNG::Color.to_grayscale(@image[x, y]) & 0x0000ff00) >> 8 + rescue ChunkyPNG::OutOfBounds => e + 0 + end + end + + def nearby(x, y, radius) + output = [] + ((x - radius)..(x + radius)).each do |i| + row = [] + ((y - radius)..(y + radius)).each do |j| + row << self[i, j] + end + output << row + end + output end end diff --git a/lib/edge_detect/sobel_edge_detector.rb b/lib/edge_detect/sobel_edge_detector.rb new file mode 100644 index 0000000..a32f546 --- /dev/null +++ b/lib/edge_detect/sobel_edge_detector.rb @@ -0,0 +1,39 @@ +module EdgeDetect + class SobelEdgeDetector < EdgeDetector + def detect_edges + image = ChunkyPNG::Image.new(@image.width, @image.height, ChunkyPNG::Color::TRANSPARENT) + gray = GrayScaler.new(self.image) + + self.image.width.times do |i| + self.image.height.times do |j| + v_x = (sobel_x * Matrix.columns(gray.nearby(i, j, 1))).sum + v_y = (sobel_y * Matrix.columns(gray.nearby(i, j, 1))).sum + + # / 10 because otherwise it's too much noise + value = Math.sqrt(v_x ** 2 + v_y ** 2).to_i / 10 + image[i, j] = ChunkyPNG::Color.rgb(value, value, value) + end + end + image + end + + private + + def sobel_x + @sobel_x ||= Matrix[ + [1, 0, -1], + [2, 0, -2], + [1, 0, -1] + ] + end + + def sobel_y + @sobel_y ||= Matrix[ + [1, 2, 1], + [0, 0, 0], + [-1, -2, -1] + ] + end + + end +end \ No newline at end of file diff --git a/test/edge_detect/edge_detector_test.rb b/test/edge_detect/edge_detector_test.rb index 827c090..239aecc 100644 --- a/test/edge_detect/edge_detector_test.rb +++ b/test/edge_detect/edge_detector_test.rb @@ -2,31 +2,35 @@ require 'test_helper' class EdgeDetectorTest < Minitest::Test - def setup - @vertical_line = create_vertical_line - @horizontal_line = create_horizontal_line + + def test_vertical_line + input = File.expand_path('../../pictures/airplane.png', __FILE__) + image = ChunkyPNG::Image.from_file(input) + + standard = EdgeDetector.new(image) + sobel = SobelEdgeDetector.new(image) + + output_standard = File.expand_path('../../output/airplane_standard.png', __FILE__) + output_sobel = File.expand_path('../../output/airplane_sobel.png', __FILE__) + + standard.detect_edges.save(output_standard) + sobel.detect_edges.save(output_sobel) end - def test_a - edge = EdgeDetector.new(@vertical_line) - edge.detect_edges + def test_horizontal_line + input = File.expand_path('../../pictures/robot.png', __FILE__) + image = ChunkyPNG::Image.from_file(input) + + standard = EdgeDetector.new(image) + sobel = SobelEdgeDetector.new(image) + + output_standard = File.expand_path('../../output/robot_standard.png', __FILE__) + output_sobel = File.expand_path('../../output/robot_sobel.png', __FILE__) + + standard.detect_edges.save(output_standard) + sobel.detect_edges.save(output_sobel) end - private - def create_horizontal_line - image = ChunkyPNG::Image.new(7, 3, ChunkyPNG::Color::TRANSPARENT) - (1..5).each do |i| - image[i, 1] = ChunkyPNG::Color('black') - end - image - end - def create_vertical_line - image = ChunkyPNG::Image.new(3, 7, ChunkyPNG::Color::TRANSPARENT) - (1..5).each do |i| - image[1, i] = ChunkyPNG::Color('black') - end - image - end end \ No newline at end of file diff --git a/test/pictures/airplane.png b/test/pictures/airplane.png new file mode 100644 index 0000000..d6eca14 Binary files /dev/null and b/test/pictures/airplane.png differ diff --git a/test/pictures/robot.png b/test/pictures/robot.png new file mode 100644 index 0000000..c502347 Binary files /dev/null and b/test/pictures/robot.png differ