【问题标题】:Editing an index only if it exists仅在索引存在时编辑索引
【发布时间】:2015-09-24 10:03:41
【问题描述】:

我需要创建一个代表图像的 0 和 1 的 2D 网格,并创建一个模糊方法,它将 1 旁边的任何 0(左、右、上或下)更改为 1,如下所示:

0000 => 0000
0000    0010
0010    0111
0000    0010

接下来我必须允许用户传入一个数字,该数字将允许模糊在每个方向上扩展多个空间。如果我调用image.blur(2),它会在每个方向上扩展 2 个空格,但每个第一步都必须再次调用 blur 来解释对角线。例如:

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

这是我的代码。

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)

我的函数有效,但前提是 1 不超出数组的边界。如果我把 1 放在角落里,看起来我的函数试图编辑一个不存在的索引的值,并且我收到以下消息:

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>'

我试图告诉它仅在索引存在时将 1 分配给索引。如有任何帮助,我将不胜感激。

【问题讨论】:

  • 我不认为“模糊”是正确的术语,“扩张”似乎更合适,尤其是对于二值图像。
  • 我很好奇 - 为什么不实例化一个新的 Image 以存储在您的 blurred_image 变量中?为递归解决方案打开大门,如果那是你的一杯茶。

标签: arrays ruby class multidimensional-array


【解决方案1】:

看起来您要先检查两个级别,然后再检查一个级别。

例如,picture[1] 可能不存在...因此,如果您随后尝试检查 picture[i][j] 它会失败。

您可以尝试在索引之前检查每个级别是否存在...

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] 

【讨论】:

    【解决方案2】:

    我的第一个想法是放弃这样的基于查找的解决方案:

    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
    

    请注意,&amp;&amp;= 运算符仅在左侧为真时才会执行赋值。所以它会失败,例如,如果你用 nil 值初始化你的内部数组。

    【讨论】:

      【解决方案3】:

      感谢您的帮助。我昨晚看到了这个问题的另一个答案,但我认为海报出于某种原因删除了它?无论如何,我最终做了他们推荐的事情,即让我的 blurred_image 索引大于图像本身 - 基本上每个方向都有一个额外的行/列。然后当我向图像添加 1 时,我只是相应地调整了我的位置,以便图像仍然居中,然后我会在每次迭代结束时删除额外的行和列。我也可以尝试这些其他方法,但这种方法对我来说效果很好。

      def blur(distance=1)
          #create new array of zeroes with 1 layer of extra 'padding', so any edges can push outwards without getting a nil error
          @blurred_image = Array.new(@picture.length+2, 0) {Array.new(@picture[0].length+2, 0)} 
      
          @picture.each_index do |i|
              @picture[i].each_index do |j|
                  if @picture[i][j] == 1
                      @blurred_image[i+1][j+1] = 1 
                      @blurred_image[i+1][j]   = 1 
                      @blurred_image[i+1][j+2] = 1 
                      @blurred_image[i][j+1]   = 1 
                      @blurred_image[i+2][j+1] = 1  
                  end
              end     
          end
      
          #remove padding after checking and editing array to make it original size
          @blurred_image.pop
          @blurred_image.shift
          @blurred_image.each_index do |i|
              @blurred_image[i].pop
              @blurred_image[i].shift
          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
      

      【讨论】:

        猜你喜欢
        • 2017-11-16
        • 1970-01-01
        • 2016-08-14
        • 2011-02-05
        • 1970-01-01
        • 1970-01-01
        • 2016-05-27
        • 2019-07-08
        • 1970-01-01
        相关资源
        最近更新 更多