Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Editing an index only if it exists

I need to create a 2D grid of 0's and 1's representing an image, and create a blur method which would change any 0 next to a 1 (left, right, above or below) into a 1, like so:

0000 => 0000
0000    0010
0010    0111
0000    0010

Next I have to allow the user to pass in a number that would allow the blur to extend multiple spaces in each direction. If I call image.blur(2), it would extend 2 spaces in each direction, but each first step would have to call blur again to account for diagonals. For example:

00000000 => 00010000
00000000    00111000
00010000    01111100
00000000    00111000
00000000    00010000

Here is my code.

class Image
  attr_accessor :picture
  def initialize(*rows)
    @picture = *rows
  end
  def output_image
    @picture.each_index do |i|
      puts @picture[i].join
    end
  end
  def blur(distance=1)
    @blurred_image = Array.new(@picture.length, 0) {Array.new(@picture[0].length, 0)} #create new array of zeroes the size of @picture
    @picture.each_index do |i|
      @picture[i].each_index do |j|
        if @picture[i][j] == 1
          @blurred_image[i][j]   = 1 if @blurred_image[i][j] 
          @blurred_image[i][j-1] = 1 if @blurred_image[i][j-1] 
          @blurred_image[i][j+1] = 1 if @blurred_image[i][j+1] 
          @blurred_image[i-1][j] = 1 if @blurred_image[i-1][j] 
          @blurred_image[i+1][j] = 1 if @blurred_image[i+1][j] 
        end
      end       
    end
    if distance > 1
      @picture = @blurred_image #save progress of image blur in @picture so we can continue in recursive call 
      blur(distance-1) #iterate as long as distance > 1
      elsif distance == 1 #necessary so blurred image isn't printed 'distance' times
      @blurred_image.each_index do |i|
        puts @blurred_image[i].join
      end
    end
  end
end

pic = Image.new(
  [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,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]
)
pic.blur(3)

My function works, but only if the 1's don't extend past the bounds of the array. If I put a 1 in a corner, it looks like my function attempts to edit the value of an index that doesn't exist, and I get the following message:

image_blur.rb:28:in `block (2 levels) in blur': undefined method `[]' for nil:NilClass (NoMethodError)
from image_blur.rb:22:in `each_index'
from image_blur.rb:22:in `block in blur'
from image_blur.rb:21:in `each_index'
from image_blur.rb:21:in `blur'
from image_blur.rb:35:in `blur'
from image_blur.rb:35:in `blur'
from image_blur.rb:47:in `<main>'

I'm trying to tell it to only assign a 1 to an index if the index exists. I'd appreciate any help.

like image 302
Shaun Avatar asked Oct 19 '22 07:10

Shaun


2 Answers

Looks like you're trying to check two levels deep before you check one level deep.

eg it's possible that picture[1] doesn't exist... so if you then try to check picture[i][j] it fails.

You can try checking if each level is present before indexing into it...

if @picture[i] && @picture[i][j] && @picture[i][j] == 1
   if @blurred_image[i].present?
      @blurred_image[i][j]   = 1 if @blurred_image[i][j] 
      @blurred_image[i][j-1] = 1 if @blurred_image[i][j-1] 
      @blurred_image[i][j+1] = 1 if @blurred_image[i][j+1]
   end
   @blurred_image[i-1][j] = 1 if @blurred_image[i-1] && @blurred_image[i-1][j] 
   @blurred_image[i+1][j] = 1 if @blurred_image[i+1] && @blurred_image[i+1][j] 
like image 124
Taryn East Avatar answered Oct 22 '22 00:10

Taryn East


My first thought would be to drop a lookup based solution like this in:

adjacents = [[-1, 0], [0, -1], [0, 0], [1, 0], [0, 1]].freeze
@blurred_image = Array.new(@picture.length, 0) { Array.new(@picture[0].length, 0) }

@picture.each_index do |i|
  @picture[i].each_index do |j|
    if @picture[i][j] == 1
      adjacents.each { |x, y| (a = @blurred_image[i+x]) && a[j+y] &&= 1 }
    end
  end
end

Note the &&= operator will perform the assignment only if the left hand side is truthy. So it would fail, for instance, if you initialised your inner arrays with nil values.

like image 36
Kimball Avatar answered Oct 21 '22 23:10

Kimball