Cicli for annidati: matlab si blocca (?)

di Anonimizzato12622 il
6 risposte
Buongiorno a tutti mi chiamo Enrico e sono uno studente di Fisica. Sto scrivendo un programma nell'ambito dell'elaborazione di immagini. Il problema è il seguente. Data una matrice a di dimensioni m x n (immagine data in input) devo aggiungere ad essa un numero di righe nulle a dx,sx,sopra e sotto. Il numero di righe da aggiungere, dato in input un determinato valore chiamato order, è order-1.
Non so se la via che ho scelto è troppo complessa e se ne esistano altre comunque ho operato come segue:
[m,n]=size(a);
t=m+(2*(order-1));
e=n+(2*(order-1));
b=double(zeros(t,e));
for i=order:(t-(order-1))
    for j=order:(e-(order-1))
        for h=1:m
            for k=1:n
                b(i,j)= a(h,k);
            end
       end
    end
end
imshow(b)
Il poblema è che si blocca (o forse è lentissimo??), anche se mi sembra strano: non è la prima volta che scrivo 4 for annidati e non ho avuto problemi.
Avreste qualche consiglio da darmi? Esiste un metodo più semplice oppure ho sbagliato qualcosa?
grazie a tutti

6 Risposte

  • La domanda risale a parecchio tempo fa ed il problema sarà stato risolto, ma, forse (e spero), questa risposta può essere utile a qualcuno.

    La lentezza dello script allegato alla domanda è dovuta al fatto che vengono utilizzati dei "cicli for" per assegnare valori alla matrice target "b".
    In aggiunta, lo script contiene un errore: i due loop più interni ("h" ed "m") assegnano, in sequenza, all'elemento "b(i,j)" tutti i valori della matrice "a". Infatti durante i due cicli, gli indici "i" e "j" non cambiano; questo fa si che, al termine dell'esecuzione dello script, tutti gli elementi della matrice "" contengono l'ultimo valore della matrice "a"

    L'errore si risolve rimuovendo i due loop più interni e sostituendo l'istruzione:

    b(i,j)= a(h,k);

    con l'istruzione:

    b(i,j)= a(i-order+1,j-order+1);

    Un metodo molto più veloce per assegnare i valori della matrice "a" alla matrice "b" ed aggiungere un certo numero di righe alla stessa matrice "b" è quello che utilizza la "colon notation" (operatore ":").
    Nello specifico, il set di istruzioni definite nello script originale comprendente i due loop più esterni (quelli interni sono da eliminare) e l'istruzione di assegnazione a "b" dei valori di "a" si possono sostituire con la sola istruzione che segue:

    c(order:end-order+1,order:end-order+1)=a;

    in essa, l'intera matrice "a" viene direttamente assegnata (copiata) all'interno della matrice "c" nell'area definita da:

    [*] order:end-order+1 ==> dalla riga "order" alla riga "end - order +1" ("end" identifica l'ultimo elemento - riga o colonna - di un vettore o matrice)
    [*] order:end-order+1 ==> dalla colonna "order" alla colonna "end - order +1"

    A titolo di esempio, nello script che segue i tempi di esecuzione dei due metodi vengono messi a confronto:

    [*] tempo di esecuzione del "metodo loop" [s]: 11.700627
    [*] tempo di esecuzione del "metodo colon notation" [s]: 0.019433

    dimensione della matrice "a": 901 x 1201 x 3
    % 
    % Lettura immagine: l'immagine è stata creata salvando la "figure" creata
    % con l'istruzione "peak", con la seguente istruzione:
    %
    % print -djpeg99 peaks_img
    % 
    a=imread('peaks_img.jpg');
    % 
    % Definizione numero di righe da aggiungere
    % 
    order=13;
    % 
    % Inizializzazione misuratore tempo di esecuzione
    % 
    tic
    % 
    % Script originale
    % 
    [m,n,x]=size(a);
    t=m+(2*(order-1));
    e=n+(2*(order-1));
    b=zeros(t,e,3,'uint8');
    for i=order:(t-(order-1))
       for j=order:(e-(order-1))
    %       
    %       I due lop seguenti e l'istruzione che segue sono da cancellare
    %       
    % % %       for h=1:m
    % % %          for k=1:n
    % % %             b(i,j)= a(h,k);
    % 
    % Istruzione corretta
    % 
                b(i,j,:)= a(i-order+1,j-order+1,:);
    % % %          end
    % % %       end
       end
    end
    % 
    % Print del tempo impiegato per l'esecuzione del codice che precede
    % 
    toc
    % 
    % Medodo alternativo basato sull'utilizzo di "colon notation"
    % 
    % Inizializzazione misuratore tempo di esecuzione
    % 
    tic
    % 
    % Come da script originale
    % 
    t=m+(2*(order-1));
    e=n+(2*(order-1));
    c=zeros(t,e,3,'uint8');
    % 
    % Questa istruzione è equivalente ai due loop dello script originale
    % 
    c(order:end-order+1,order:end-order+1,:)=a;
    % 
    % Print del tempo impiegato per l'esecuzione del codice che precede
    % 
    toc
    
    figure('name','Immagine Originale')
    imshow(a)
    figure('name','Immagine Metodo "loop"')
    imshow(b)
    figure('name','Immagine Metodo "colon notation')
    imshow(c)
    
    Hope this helps.
    Allegati:
    Immagine originale
    Immagine originale

    Immagine ottenuta con il metodo "loop"
    Immagine ottenuta con il metodo "loop"

    Immagine ottenuta con il metodo "colon notation"
    Immagine ottenuta con il metodo "colon notation"
  • Salve ragazzi, grazie per avermi accettato. ho due matrici su matlab formate da una colonna per matrice di 720 valori ciascuna. vorrei creare un ciclo in modo da chiedere di: controllare se l'iesimo valore della matrice A è <2, compreso tra due e tre, ecc e a secondo di quale condizione è andare nella matrice B sempre all'iesimo valore e controllare anche qui se questo è <500, compreso tra 500 e 700 ed assegnare una classe.
    classe a se a<2 e b<500
    classe b se a < 2 e b compreso tra 500 e 700
    classe c se a compreso tra 2 e 3 e b<500
    classe d se a compreso tra 2 e 3 e b tra 500 e 700.
    mettendo queste classi trovate in una nuova matrice. grazie in anticipo a tutti ragazzi.
  • Qualche considerazione:

    [*] non pubblicare una domanda come "risposta" ad un'altra domanda, crea invece una "nuova domanda"
    [*] dovresti spiegare quale sia la difficoltà che hai incontrato
    [*] nella domanda dovresti inserire anche il codice che hai scritto, in modo che si posa capire quale / dove sia il problema

    Nella domanda non è chiaro cosa intendi con "assegnare una classe" e "mettendo queste classi trovate in una nuova matrice": sono delle stringhe?

    Il problema che hai proposto nella domanda si può risolvere con poche linee di codice e senza "cicli for" sfruttando le caratteristiche di "indexing" di MatLab.

    Dato infatti l'array "a", l'istruzione:
    a < 2 & b < 500
    ritorna un array di tipo "logical" con "1" in corrispondenza delle locazioni del vettore "a" nel quale la condizione è verificata, "0" in caso contrariio.

    Lo stesso approccio si può usare per le altre condizioni:
    
    a < 2 & (b >= 500 & b <= 700)
    (a >= 2 & a <= 3) & b < 500
    (a >= 2 & a <= 3) & (b >= 500 & b <= 700)
    
    quest array "logici" possono essere utilizzati come indici per assegnare valori in un array solo nelle posizioni nelle quali le condizioni sono verificate, vale a dire nelle locazioni nelle quali compare il valore "logico" "1".

    Una possibile implementazione, potrebbe essere (fatta salve l'incertezza su cosa intendi con "assegnare una classe" - vedi commenti iniziali):
    
    % Creazione dei dati di input di esempio
    a=rand(1,10)*3;
    b=randi([333 700],1,10);
    % Identificazione del numero di dati
    n_data=length(a);
    % Definizione dei velori delle possibili classi
    classes='abcd';
    % Inizializzazione dell'array di output
    class_m=repmat('_',1,n_data);
    % Definizione delle condizioni
    a_min_2=a < 2;
    a_2_3= a >= 2 & a <= 3;
    b_min_500=b < 500;
    b_500_700=b >= 500 & b <= 700;
    % Utilizzo dei vettori logici per l'assegnazione delle classi
    class_m(a_min_2 & b_min_500)=classes(1)
    class_m(a_min_2 & b_500_700)=classes(2)
    class_m(a_2_3 & b_min_500)=classes(3)
    class_m(a_2_3 & b_500_700)=classes(4)
    
    Se proprio si vuole / deve usare un "ciclo for" ne basta uno e qualche "if / else if".

    Per entrambi gli approcci, ti consiglio caldamente di familiarizzare con i principi di base del linguaggio MatLab.

    https://www.mathworks.com/help/pdf_doc/matlab/getstart.pdf
  • Grazie mille per la risposta. funziona alla perfezione
  • Scusate , con repmat mi crea una matrice che in realtà non lo è(tipo immagine). se io invece vorrei creare una matrice formata da una colonna come potrei fare? class_m (:,tot)=('_',1,n_data)?grazie mille
  • Cosa vuol dire "mi crea una matrice che in realtà non lo è(tipo immagine)"?

    Hai provato a leggere la documentazione della funzione "repmat" ()?

    Hai provato ad invertire gli ultimi due parametri di input nella chiamata alla funzione?
Devi accedere o registrarti per scrivere nel forum
6 risposte