2015-07-07 18 views
5

Devo creare una griglia 2D di 0 e 1 che rappresenta un'immagine e creare un metodo di sfocatura che cambierebbe qualsiasi 0 accanto a 1 (a sinistra, a destra, sopra o sotto) in un 1, in questo modo:Modifica di un indice solo se esiste

0000 => 0000 
0000 0010 
0010 0111 
0000 0010 

prossima devo per consentire all'utente di passare in un numero che consenta la sfocatura di estendere spazi multipli in ciascuna direzione. Se chiamo image.blur(2), estenderei 2 spazi in ciascuna direzione, ma ogni primo passaggio dovrebbe richiamare nuovamente la sfocatura per tenere conto delle diagonali. Ad esempio:

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

Ecco il mio codice.

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) 

La mia funzione funziona, ma solo se le 1 non si estendono oltre i limiti dell'array. Se metto un 1 in un angolo, sembra che la mia funzione tenta di modificare il valore di un indice che non esiste, e ottengo il seguente messaggio:

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

che sto cercando di dire a assegna solo un 1 a un indice se l'indice esiste. Apprezzerei qualsiasi aiuto.

+0

Non penso che "sfocatura" sia il termine giusto, "dilatare" sembra più appropriato, soprattutto per le immagini binarie. – Stefan

+0

Sono curioso: perché non istanziare una nuova immagine per memorizzare nella variabile 'blurred_image'? Apre la porta per una soluzione ricorsiva, se questa è la tua tazza di tè. – Kimball

risposta

2

Sembra che tu stia cercando di controllare due livelli in profondità prima di controllare un livello in profondità.

ad esempio è possibile che picture[1] non esista ... quindi se si prova a verificare picture[i][j] non riesce.

Si può provare a controllare se ogni livello è presente prima indicizzazione in esso ...

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] 
1

Il mio primo pensiero sarebbe quello di cadere una soluzione basata su ricerca come questo 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 

Nota l'operatore &&= eseguirà l'assegnazione solo se il lato sinistro è sincero. Quindi, ad esempio, fallirebbe se inizializzassi i tuoi array interni con i valori nil.

0

Apprezzo l'aiuto. Ho visto un'altra risposta a questa domanda la scorsa notte, ma penso che il manifesto l'abbia cancellato per qualche motivo? Ad ogni modo, ho finito per fare quello che mi consigliavano, il che rendeva il mio indice blurred_image più grande dell'immagine stessa - fondamentalmente una riga/colonna in più in ogni direzione. Poi, quando ho aggiunto 1 all'immagine, ho appena regolato le posizioni di conseguenza in modo che l'immagine fosse ancora centrata, quindi avrei rimosso le righe e le colonne in più alla fine di ogni iterazione. Potrei anche provare questi altri metodi, ma in questo modo ha funzionato benissimo per me.

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 
Problemi correlati