开发者

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

开发者 https://www.devze.com 2023-01-01 14:25 出处:网络
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.

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 w开发者_运维技巧ritten. 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


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


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

link


You could use BSXFUN for at least some of your tasks. It performs an element-wise operation among two arrays by expanding the size 1 - dimensions to match the size in the other array. The 'reddish tint' function would become

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

All the above statement requires in order to work is that the third dimension of img has size 1 or 3. Number and size of the other dimensions can be chosen freely.


If you are consistently trying to apply a function to a vector comprised by the 3 dimension in a block of images, I recommend using a pair reshapes, for instance:

Img = rand(480,640,3);

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

This way you can swap in any function that operates on matrices along their first dimension.

edit. The above code will crash if you input an image which has only one layer: The function below can fix it.

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)])';


Well, if you are only concerned with multiplying vectors together you could just use the dot product, like this:

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

taking care that the shapes of your vectors conform.

0

精彩评论

暂无评论...
验证码 换一张
取 消