Cicli for annidati: matlab si blocca (?)

di il
6 risposte

Cicli for annidati: matlab si blocca (?)

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

  • Re: Cicli for annidati: matlab si blocca (?)

    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"
  • Re: Cicli for annidati: matlab si blocca (?)

    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.
  • Re: Cicli for annidati: matlab si blocca (?)

    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
  • Re: Cicli for annidati: matlab si blocca (?)

    Grazie mille per la risposta. funziona alla perfezione
  • Re: Cicli for annidati: matlab si blocca (?)

    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
  • Re: Cicli for annidati: matlab si blocca (?)

    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