2010-06-01 18 views
6

A menudo me encuentro queriendo colapsar una matriz n-dimensional en una dimensión utilizando una función personalizada, y no puedo averiguar si hay un encantamiento conciso que pueda usar para hacer esto.Distribuir una función en una dimensión única de una matriz en MATLAB?

Por ejemplo, cuando analizo una imagen, a menudo quiero hacer algo como esto. (Nota Ejemplo ilustrativo solamente lo que sé sobre rgb2gray para este caso específico!..)

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 

me gustaría expresar esto como algo parecido a:

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

o

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

Es hay una manera corta de hacer esto?


EDITAR: Aparentemente mean ya lo hace; Quiero poder hacer esto para cualquier función que haya escrito. Por ejemplo,

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

donde

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

Respuesta

6

Muchas de las funciones básicas de MATLAB, como MEAN, MAX, MIN, SUM, etc., están diseñados para operar a través de una dimensión específica:

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

También puede aprovechar el hecho de que MATLAB arithmetic operators están diseñados para operar en un elemento- moda sabia en matrices. Por ejemplo, la operación en su función reddish_tint se puede aplicar a todos los píxeles de la imagen con esta sola línea:

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

para tratar un caso más general en el que desea aplicar una función a una dimensión arbitraria de un N matriz tridimensional, es probable que desee escribir su función de modo que acepte un argumento de entrada adicional para qué dimensión operar (como las funciones de MATLAB mencionadas anteriormente) y luego utilice una lógica simple (es decir, declaraciones if-else) y operaciones matriciales de elementos para aplicar sus cálculos a la dimensión adecuada de la matriz.

Aunque no recomendaría usarlo, es una solución rápida y sucia, pero es bastante feo y más costoso desde el punto de vista informático. Puede utilizar la función NUM2CELL para recoger los valores a lo largo de una dimensión de la matriz en células de un conjunto de celdas, a continuación, aplicar la función a cada celda usando la función 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, útil para esos casos. Debería ser más claro: a menudo trato de usar alguna función que escribí como '0.3 * r + 0.2 * g + 0.5 * b'. –

+0

@Alex: actualicé la respuesta para señalar cómo los operadores de elementos pueden usarse para aplicar una función a una matriz. – gnovice

+0

No necesita convertirlo a una matriz de celdas. Simplemente use 'arrayfun', consulte: http://www.mathworks.com/access/helpdesk/help/techdoc/ref/arrayfun.html – Geoff

1

Bueno, si sólo está preocupada por la multiplicación vectores juntos podría usar el producto de puntos, así:

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

teniendo cuidado de que las formas de sus vectores se ajusten.

2

Si está intentando constantemente para aplicar una función a un vector compuesto por la dimensión 3 en un bloque de imágenes, recomiendo el uso de un par cambia la forma de, por ejemplo:

Img = rand(480,640,3); 

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

esta manera se puede intercambiar en cualquier función que opera en matrices a lo largo de su primera dimensión.

editar. El código anterior se bloqueará si ingresa una imagen que tiene solo una capa: la siguiente función puede corregirlo.

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

Puede usar BSXFUN para al menos algunas de sus tareas. Realiza una operación de elemento entre dos arrays al expandir el tamaño 1 - dimensiones para que coincida con el tamaño en la otra matriz. La función 'tinte rojizo' se convertiría en

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

Toda la declaración anterior requiere con el fin de trabajo es que la tercera dimensión de img tiene un tamaño de 1 o 3. Número y tamaño de las otras dimensiones se pueden elegir libremente.

+0

Creo que puedo improvisar algo usando bsxfun ... –

5

Escribí una función auxiliar llamada 'vecfun' que podría ser útil para esto, si es lo que estás tratando de lograr?

link

Cuestiones relacionadas