2010-06-01 9 views
6

Spesso mi ritrovo a voler comprimere una matrice n-dimensionale attraverso una dimensione usando una funzione personalizzata, e non riesco a capire se c'è un incantesimo conciso che posso usare per farlo.Distribuire una funzione su una singola dimensione di un array in MATLAB?

Ad esempio, durante l'analisi di un'immagine, spesso desidero fare qualcosa di simile. (Nota Esempio illustrativo solo io so rgb2gray per questo caso specifico!..)

img = imread('whatever.jpg'); 
s = size(img); 
for i=1:s(1) 
    for j=1:s(2) 
    bw_img(i,j) = mean(img(i,j,:)); 
    end 
end 

Mi piacerebbe esprimere questo come qualcosa di simile:

bw = on(color, 3, @mean); 

o

bw(:,:,1) = mean(color); 

Is c'è un modo per farlo?


MODIFICA: Apparentemente lo mean lo fa già; Voglio essere in grado di farlo per qualsiasi funzione che ho scritto. Ad esempio,

... 
    filtered_img(i,j) = reddish_tint(img(i,j,:)); 
... 

dove

function out = reddish_tint(in) 
    out = in(1) * 0.5 + in(2) * 0.25 + in(3) * 0.25; 
end 

risposta

6

Molte funzioni di base di MATLAB, come MEAN, MAX, MIN, SUM, ecc, sono progettati per operare in una dimensione specifica:

bw = mean(img,3); %# Mean across dimension 3 

È inoltre possibile sfruttare il fatto che lo MATLAB arithmetic operators sono progettati per funzionare in un elemento Modo saggio su matrici. Per esempio, l'operazione nella funzione reddish_tint può essere applicato a tutti i pixel dell'immagine con questa sola riga:

filtered_img = 0.5.*img(:,:,1)+0.25.*img(:,:,2)+0.25.*img(:,:,3); 

per trattare un caso più generale in cui si desidera applicare una funzione a una dimensione arbitraria di un N -matrice tridimensionale, probabilmente vorrai scrivere la tua funzione in modo tale che accetti un argomento di input addizionale per la dimensione su cui operare (come fanno le funzioni MATLAB sopra menzionate) e poi usa una logica semplice (cioè istruzioni if-else) e operazioni a matrice element-wise per applicare i suoi calcoli alla giusta dimensione della matrice.

Sebbene non suggerirei di utilizzarlo, lo è una soluzione rapida e sporca, ma è piuttosto brutto e computazionalmente più costoso. È possibile utilizzare la funzione NUM2CELL per raccogliere valori lungo una dimensione dell'array in cellule di un array di celle, quindi applicare la funzione a ciascuna cella utilizzando la funzione di CELLFUN:

cellArray = num2cell(img,3); %# Collect values in dimension 3 into cells 
filtered_img = cellfun(@reddish_tint,cellArray); %# Apply function to each cell 
+0

Mm, utile per quei casi. Dovrei essere più chiaro - sto spesso cercando di usare una funzione che ho scritto come '0,3 * r + 0,2 * g + 0,5 * b'. –

+0

@Alex: Ho aggiornato la risposta per indicare come gli operatori a livello di elemento possono essere utilizzati per applicare una funzione a una matrice. – gnovice

+0

Non è necessario convertirlo in un array di celle. Basta usare 'arrayfun' vedi: http://www.mathworks.com/access/helpdesk/help/techdoc/ref/arrayfun.html – Geoff

1

Beh, se siete interessati solo moltiplicando insieme i vettori potresti semplicemente utilizzare il prodotto dot, come questo:

bw(:,:,1)*[0.3;0.2;0.5] 

avendo cura che le forme dei tuoi vettori siano conformi.

2

Se si sta costantemente cercando di applicare una funzione ad un vettore costituito dalla dimensione 3 in un blocco di immagini, mi consiglia di utilizzare un paio rimodella, per esempio:

Img = rand(480,640,3); 

sz = size(Img); 
output = reshape(myFavoriteFunction(reshape(Img,[prod(sz(1:2)),sz(3)])'),sz); 

In questo modo è possibile scambiare in qualsiasi funzione che opera su matrici lungo la loro prima dimensione.

modifica. Il codice sopra si arresta in modo anomalo se si immette un'immagine con un solo livello: la funzione seguente può risolverlo.

function o = nLayerImage2MatrixOfPixels(i) 
%function o = nLayerImage2MatrixOfPixels(i) 
s = size(i); 
if(length(s) == 2) 
    s3 = 1; 
else 
    s3 = s(3); 
end 
o = reshape(i,[s(1)*s(2),s(3)])'; 
3

È possibile utilizzare BSXFUN per almeno alcune delle attività. Esegue un'operazione basata sull'elemento tra due array espandendo la dimensione 1 - dimensioni per adattarsi alla dimensione nell'altra matrice. La funzione 'tinta rossastra' diventerebbe

reddish_image = bsxfun(@times,img,cat(3,0.5,0.25,0.25)); 
filtered_img = sum(reddish_image,3); 

Tutti comunicazione precedente richiede per funzionare è che la terza dimensione di img ha dimensione 1 o 3. Numero e dimensioni delle altre dimensioni possono essere scelti liberamente.

+0

Penso che potrei essere in grado di accodare qualcosa usando bsxfun ... –

5

Ho scritto una funzione di supporto chiamata 'vecfun' che potrebbe essere utile per questo, se è quello che stai cercando di ottenere?

link

Problemi correlati