Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Distributing a function over a single dimension of an array in MATLAB?

I often find myself wanting to collapse an n-dimensional matrix across one dimension using a custom function, and can't figure out if there is a concise incantation I can use to do this.

For example, when parsing an image, I often want to do something like this. (Note! Illustrative example only. I know about rgb2gray for this specific case.)

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

I would love to express this as something like:

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

or

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

Is there a short way to do this?


EDIT: Apparently mean already does this; I want to be able to do this for any function I've written. E.g.,
...
  filtered_img(i,j) = reddish_tint(img(i,j,:));
...

where

function out = reddish_tint(in)
  out = in(1) * 0.5 + in(2) * 0.25 + in(3) * 0.25;
end
like image 764
Alex Feinman Avatar asked Jun 01 '10 14:06

Alex Feinman


2 Answers

Many basic MATLAB functions, like MEAN, MAX, MIN, SUM, etc., are designed to operate across a specific dimension:

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

You can also take advantage of the fact that MATLAB arithmetic operators are designed to operate in an element-wise fashion on matrices. For example, the operation in your function reddish_tint can be applied to all pixels of your image with this single line:

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

To handle a more general case where you want to apply a function to an arbitrary dimension of an N-dimensional matrix, you will probably want to write your function such that it accepts an additional input argument for which dimension to operate over (like the above-mentioned MATLAB functions do) and then uses some simple logic (i.e. if-else statements) and element-wise matrix operations to apply its computations to the proper dimension of the matrix.

Although I would not suggest using it, there is a quick-and-dirty solution, but it's rather ugly and computationally more expensive. You can use the function NUM2CELL to collect values along a dimension of your array into cells of a cell array, then apply your function to each cell using the function CELLFUN:

cellArray = num2cell(img,3);  %# Collect values in dimension 3 into cells
filtered_img = cellfun(@reddish_tint,cellArray);  %# Apply function to each cell
like image 194
gnovice Avatar answered Sep 22 '22 08:09

gnovice


I wrote a helper function called 'vecfun' that might be useful for this, if it's what you're trying to achieve?

link

like image 26
Adam Gripton Avatar answered Sep 25 '22 08:09

Adam Gripton