2
\$\begingroup\$

Custom class Image takes a 2-D array of 0's and 1's upon initialization. Method transform returns a modified array by modifying 0's adjacent to a 1, such that

[[0,0,0],
 [0,1,0],
 [0,0,0]]

returns

[[0,1,0],
 [1,1,1],
 [0,1,0]]

I've been working on method blur(n), which outputs an array that has been transformed n times, such that n=3 changes

[[0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,1,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0]]

into

[[0, 0, 0, 0, 0, 0, 0, 0, 0]
 [0, 0, 0, 0, 1, 0, 0, 0, 0]
 [0, 0, 0, 1, 1, 1, 0, 0, 0]
 [0, 0, 1, 1, 1, 1, 1, 0, 0]
 [0, 1, 1, 1, 1, 1, 1, 1, 0]
 [0, 0, 1, 1, 1, 1, 1, 0, 0]
 [0, 0, 0, 1, 1, 1, 0, 0, 0]
 [0, 0, 0, 0, 1, 0, 0, 0, 0]
 [0, 0, 0, 0, 0, 0, 0, 0, 0]
 [0, 0, 0, 0, 0, 0, 0, 0, 0]
 [0, 0, 0, 0, 0, 0, 0, 0, 0]
 [0, 0, 0, 0, 0, 0, 0, 0, 0]]

Right now my solution to blur(n) works, by first creating a new Image object, transforming and then transforming additional instances of Image an additional (n-1) times. I've been getting errors if I try to apply blur without instantiating a new Image and transforming it — the transform method is not available to class Array. How could I go about applying transform iteratively without having to instantiate Image inside the class?

class Image
 attr_accessor :arr
 def initialize(arr)
 @arr = arr
 end
 def transform 
 cloned = self.arr.map(&:clone)
 #scan original array for 1; map crosses into clone if found
 self.arr.each.with_index do |row, row_index|
 row.each.with_index do |cell, col|
 if cell == 1
 cloned[row_index][col+1] = 1 unless col+1 >= row.length #copy right
 cloned[row_index+1][col] = 1 unless row_index+1 >= cloned.length # copy down
 cloned[row_index][col-1] = 1 unless col.zero? # copy left
 cloned[row_index-1][col] = 1 unless row_index.zero? #copy up
 end
 end
 end
 cloned
 end
 def blur(n) 
 blurred = Image.new(self).arr.transform
 (n-1).times do 
 blurred = Image.new(blurred).transform
 end
 blurred
 end
end
image = Image.new([[0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,1,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0]])
image.blur(3)
#returns...
# [[0, 0, 0, 0, 0, 0, 0, 0, 0], 
# [0, 0, 0, 0, 1, 0, 0, 0, 0], 
# [0, 0, 0, 1, 1, 1, 0, 0, 0], 
# [0, 0, 1, 1, 1, 1, 1, 0, 0], 
# [0, 1, 1, 1, 1, 1, 1, 1, 0], 
# [0, 0, 1, 1, 1, 1, 1, 0, 0], 
# [0, 0, 0, 1, 1, 1, 0, 0, 0], 
# [0, 0, 0, 0, 1, 0, 0, 0, 0], 
# [0, 0, 0, 0, 0, 0, 0, 0, 0], 
# [0, 0, 0, 0, 0, 0, 0, 0, 0], 
# [0, 0, 0, 0, 0, 0, 0, 0, 0], 
# [0, 0, 0, 0, 0, 0, 0, 0, 0]]
asked May 3, 2016 at 13:05
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Very relevant: blog.ostermiller.org/dilate-and-erode \$\endgroup\$ Commented May 3, 2016 at 14:04
  • \$\begingroup\$ The best way is to use SVG when dealing with image blur or zooming issues. \$\endgroup\$ Commented May 3, 2016 at 20:07

1 Answer 1

2
\$\begingroup\$

I assume you are trying to do something like:

def blur(n) 
 blurred = Image.new(self).arr.transform
 (n-1).times do 
 blurred = blurred.transform
 end
 blurred
end

And getting an error like:

`block in blur': undefined method `transform' for #<Array:0x00000002d51ba8>

The reason is that transform is a instance method of Image, which is why you need to convert back into an image before calling it.

There are a couple of way this can be handled. I've chosen to make transform a static method that only works on arrays. The instance methods transform and blur call the static method as needed

class Image
 attr_accessor :arr
 def initialize(arr)
 @arr = arr
 end
 def transform
 result = Image.arr_transform(@arr)
 Image.new(result)
 end
 def self.arr_transform(array) 
 cloned = array.map(&:clone)
 #scan original array for 1; map crosses into clone if found
 array.each.with_index do |row, row_index|
 row.each.with_index do |cell, col|
 if cell == 1
 cloned[row_index][col+1] = 1 unless col+1 >= row.length #copy right
 cloned[row_index+1][col] = 1 unless row_index+1 >= cloned.length # copy down
 cloned[row_index][col-1] = 1 unless col.zero? # copy left
 cloned[row_index-1][col] = 1 unless row_index.zero? #copy up
 end
 end
 end
 cloned
 end
 def blur(n)
 blurred = @arr
 (n).times do 
 blurred = Image.arr_transform(blurred)
 end
 Image.new(blurred)
 end
end

Testing:

image = Image.new([[0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,1,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0]])
require 'pp'
pp image.blur(3)

Returns:

#<Image:0x00000002e9fb40
 @arr=
 [[0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 1, 0, 0, 0, 0],
 [0, 0, 0, 1, 1, 1, 0, 0, 0],
 [0, 0, 1, 1, 1, 1, 1, 0, 0],
 [0, 1, 1, 1, 1, 1, 1, 1, 0],
 [0, 0, 1, 1, 1, 1, 1, 0, 0],
 [0, 0, 0, 1, 1, 1, 0, 0, 0],
 [0, 0, 0, 0, 1, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0]]>
answered May 3, 2016 at 14:03
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.