Archive

Posts Tagged ‘matlab’

Counting the number of dimensions

6th November, 2010 Leave a comment

Knowing how many dimensions your array has is important, if only to know that your pie chart really is 4d. MATLAB is a little odd in that scalar values are, under the bonnet, matrices with one row and one column. Likewise, vectors are matrices with one dimension of length one. Mostly, you don’t notice this but when you are trying to count the number of dimensions, you can see some odd results.

ndims(1)        % 2
ndims(1:5)      % 2

Often, you may prefer to know the number of nontrivial dimensions: that is, how many dimensions an array has that have length greater than one. I noticed this problem while browsing the code of the rather excellent xml_io_tools by Jarek Tuszynski. The solution is easy to wrap into a function.

function n = nntdims(x)
%NNTDIMS Number of non-trivial dimensions.
   n = nnz(size(x) > 1);
end

nntdims(1)        % 0
nntdims(1:5)      % 1

Two amigos: follow up

13th October, 2010 Leave a comment

Brett and Jiro have announced the results of the competition to make a Bob-free image. There were five entries, two prizes and … I didn’t win either. Still, it was a fun challenge and a useful learning experience so I’m consoling myself with cliches like “it’s not the winning that’s important but the taking part”. I’m certainly not using MATLAB to construct a voodoo-doll image of Brett and Jiro.
jiro and brett with pins in their heads

%% Read in image and display
theAmigos = imread('the amigos better blur.jpg');
image(theAmigos)

%% Add lines
pinColour = [.5 .5 .5];

xcoords = { ...
   [130 180] ...
   [132 182] ...
   [136 184] ...
   [140 186] ...
   [148 190] ...
   [165 195] ...
   [182 200] ...
   [200 205] ...
   [215 214] ...
   [230 223] ...
   [243 228] ...
   [255 234] ...
   [270 237] ...
   [283 244] ...
   [295 247] ...
   [300 246] ...
   [303 248] ...
   ...
   [465 515] ...
   [465 516] ...
   [466 517] ...
   [469 519] ...
   [475 522] ...
   [487 526] ...
   [505 534] ...
   [528 540] ...
   [548 546] ...
   [567 551] ...
   [588 554] ...
   [606 557] ...
   [621 560] ...
   [628 563] ...
   [633 566] ...
   [633 567] ...
   [634 568] ...
};

ycoords = { ...
   [295 300] ...
   [275 290] ...
   [260 280] ...
   [240 275] ...
   [225 274] ...
   [220 274] ...
   [215 273] ...
   [212 273] ...
   [212 273] ...
   [214 273] ...
   [217 274] ...
   [221 274] ...
   [230 275] ...
   [240 277] ...
   [250 280] ...
   [275 285] ...
   [290 292] ...
   ...
   [320 322] ...
   [305 315] ...
   [288 310] ...
   [272 304] ...
   [253 300] ...
   [240 296] ...
   [233 292] ...
   [230 291] ...
   [230 291] ...
   [232 292] ...
   [236 294] ...
   [246 297] ...
   [262 300] ...
   [280 302] ...
   [296 307] ...
   [309 312] ...
   [320 320] ...
};

xstart = cellfun(@(x) x(1), xcoords);
ystart = cellfun(@(x) x(1), ycoords);

hold on
cellfun(@(x, y) line(x, y, 'Color', pinColour), xcoords, ycoords);
arrayfun(@(x, y) plot(x, y, '.', 'Color', pinColour), xstart, ystart);
hold off

%% Remove the extra bits created by plot calls and write to file
set(gca, 'Visible', 'off')
set(gca, 'Position', [0 0 1 1])

print(gcf, '-djpeg', 'the amigos voodoo.jpg')

Two amigos MATLAB contest

6th October, 2010 1 comment

Today I discovered a MATLAB mini-contest called The Two Amigos. The idea is two use MATLAB to remove Bob from a photo of the three Pick-of-the-Week bloggers. The contest officially closed last week but they had no entries by submission day so you’re still in with a chance, if you’re quick.

I hadn’t done any image processing in MATLAB until earlier today, and I don’t have access to the image processing toolbox, so my attempt is pretty basic. I’m posting my submission here to give you a headstart. As with all the other code on this blog, it is licensed under the WTFPL, so you can literally do “what the f*ck” you want with it.  ( If you submit something based upon my code though, an attribution would be appreciated.)

First up: reading and displaying an image in MATLAB is easy.

theAmigos = imread('threeamigos-800w.jpg');
image(theAmigos)

My first idea was to simply place a black rectangle over a region roughly corresponding to Bob.

% Take a copy of the basic image
theAmigosBlackout = theAmigos;

% Select 'Bob' region
bobRectX = 220:563;
bobRectY = 300:470;

% Make this region black
theAmigosBlackout(bobRectX, bobRectY, : ) = 0;

image(theAmigosBlackout)

Bob is blacked out from the photo of the three amigos

Hmm. The black region looks a little severe. It would be easier on the eye to simply blur him out. My homemade blur technique uses the filter2 function to create a moving average filter (a very simple smoother) to blur the region.

theAmigosBlur = theAmigos;
blurRadius = 20;

% Calculate weights for the blur filter
w = [(blurRadius + 1):-1:1 2:(blurRadius + 1)];
w2 = repmat(w, length(w), 1);
weights = 1 ./ (w2 + w2');
weights = weights / sum(weights(:));

% Apply filter to each colour channel
for i = 1:3
   theAmigosBlur(bobRectX, bobRectY, i) = ...
      filter2(weights, theAmigosBlur(bobRectX, bobRectY, i));
end
image(theAmigosBlur)

Bob is blurred in the photo of the three amigos

The problem here is that the edges of the blurred region look darker. Presumably missing values are considered as black, for some reason. To solve this we only use the central “valid” region of the filter. This involves some fiddling to extend the rectangle’s region, which in turn involves some fiddling to extend the base of the image.

theAmigosBetterBlur = theAmigos;

% Temporarily extend image bottom
bottom = repmat(theAmigosBetterBlur(end, :, : ), blurRadius, 1);
theAmigosBetterBlur = [theAmigosBetterBlur; bottom];

% Extend rectangle
extendedX = (min(bobRectX) - blurRadius):(max(bobRectX) + blurRadius);
extendedY = (min(bobRectY) - blurRadius):(max(bobRectY) + blurRadius);

% Apply filter to valid region
for i = 1:3
   theAmigosBetterBlur(bobRectX, bobRectY, i) = ...
      filter2(weights, theAmigosBetterBlur(extendedX, extendedY, i), 'valid');
end

% Remove the extension to the bottom of the image
theAmigosBetterBlur = theAmigosBetterBlur(1:(end - blurRadius), :, : );

image(theAmigosBetterBlur)

The edges to the blur of Bob are better now

Can you do better than this? Maybe you can figure out how to do edge detection, or find a better way to find the ‘Bob’ region? Can you think of a more appropriate substitute than blurring? Maybe a few MATLAB logos in there might swing the judges decision. Or you could recreate the special effect used when they transport people on Star Trek.

Let me know how you get on.

Tags: ,

Fun, fun fun! (array, cell and struct)

3rd October, 2010 Leave a comment

The other day I was asked what the point of MATLAB’s cellfun function was. “Surely I can do what it does with a for loop?”, they said. The quick answer is, “yes you can use a for loop, but it’s still very useful”. This post tells you why.

The three functions arrayfun, cellfun and structfun are for solving split-apply-combine problems. That is, you split your data up into chunks, you apply some function to each chunk, then you combine the results together. The difference between them is the type of input variable that they accept: arrayfun takes arrays, and so forth. (It should be noted that having just three functions for this is very restrained. R has half a dozen functions in the apply family, plus aggregate and by, not to mention the plyr package.)

A simple example is to try and get the number of characters in each string of a cell array. We start by defining some data (in this case, the first four metasyntactic variables).

msv = {'foo' 'bar' 'baz' 'quux'};

Now compare using a for loop

n = zeros(size(msv));
for i = 1:numel(msv)
   n(i) = numel(msv{i});
end

with cellfun

n = cellfun(@numel, msv)      %The @ symbol denotes a handle to numel 

Aside from the obvious benefit that we’ve hugely cut down on the amount of typing, I think the second method expresses the intent of the code much more clearly. The use of cellfun means that you must have a split-apply-combine problem, whereas for loops are more general concepts, so you need to study the code more closely to understand what is happening.

There is one little niggle with cellfun that I hope The MathWorks will correct one day. If the result of applying the function to each chunk can have a different size, then the result needs to be stored in a cell array rather than a vector. In this case, you need to explicitly set 'UniformOutput' to false. Ideally, cellfun would be able to automatically know when the output doesn’t have uniform size and act appropriately. Keep your fingers crossed that this gets sorted eventually.

Tags: ,

Update to shortcut tools

1st October, 2010 Leave a comment

I’ve made a small update to the MATLAB shortcut tools collection in the File Exchange. (See the previous post A Shortcut to Success for advice on usage.) The main change is that I’ve been persuaded of the virtue of hiding code in private folders, after finding myself with an increasingly mangled search path. AddShortcutCategory has been replaced with AddShortcutCategories, since you’ll naturally want to add a few at a time, and I’ve added the IconDir function which simply returns the name of the directory of the icons that ship with MATLAB since R2009a. It should be available in the FEX shortly.

Tags: ,

MATLAB Conference 2010

1st October, 2010 Leave a comment

I went to the MATLAB conference at Wembley Stadium yesterday. There were two presentations and a lot of discussion about parallel computing (more on that later). One of the most interesting things to me was that The MathWorks have gotten command history files from a bunch of students learning MATLAB, which they are using to weed out some of the problems that users get when they first learn the language. I can proudly report that I’ve been bitten by several of the examples that were presented.

round 1.234

ans =
    49    46    50    51    52

Here, the input is converted to a character array, then returns the ascii values of each character.   (round is being altered to throw an error upon character input.)

Likewise the unhelpful error message that occurs when you mess up a multiplication is being revamped.

eye(3) * magic(4)
??? Error using ==> mtimes
Inner matrix dimensions must agree.

mtimes is the underlying function that * calls. The error message should now display *, as expected.

I’m really glad to see that The MathWorks are taking in interest in cleaning up these niggles. Little improvements can save users hours of frustration. It reminds me of Canonical’s 100 paper cuts project for Ubuntu.

The parallel computing discussions focussed on two areas: gpu computing and scaling from a single core to multiple cores on a single machine, through to clusters of machines. The gpu and mulicore cases are dealt with via the parallel computing toolbox; scaling to multiple machines requires the rather-more-expensive distributed computing toolbox.

Both products seem to be in a teenage-state: mature enough to get some useful things done with them, but missing a few features.   For example, it’s really easy to parallelise a for loop: you simply replace for with parfor, but arrayfun only works in parallel with gpus, not cpus.   (John Walley, an application engineer with The MathWorks, is discussing rectifying this.) In fairness to The Mathworks, parallel computing from your desktop is in its infancy everywhere.

If I successfully bat my eyelids at the people in charge of the software budget, I’m hoping to be able to play with the parallel computing toolbox in the near future;  I’ll give you some code examples once that happens.

Tags:

A shortcut to success

23rd August, 2010 2 comments

The MATLAB user interface is laid out in a way so you spend a fair amount of time with one hand on your mouse.  When that happens, toolbar shortcuts are a great way to run chunks of code that you use regularly.  The trouble is, in order to set them up, you need to do lots of clicking to interact with the MATLAB UI.  This has two big problems.  Every time you install a new copy of MATLAB, you need to set up your shortcuts again.  Click, click, click.  Sigh.  It also means that shortcuts are difficult to share with your colleagues/friends/that hot chick you want to impress with your scientific coding skillz.

The solution to this is to generate the shortcuts programmatically.  Write your shortcut script once, and you can reuse the code  to your heart’s content.  The trouble is, MATLAB doesn’t ship with any tools to manipulate shortcuts.  All the details of your shortcuts (that’s the toolbar shortcuts your help browser favourites, and any other shortcuts you care to define) are stored in the file shortcuts.xml in your preferences directory (as returned by prefdir).

There are two ways to write methods to add and remove shortcuts.  You can use some XML tools, of which my favourite is the xml_io_tools package by Jaroslaw Tuszynski.  The other alternative is to delve into the mostly undocumented MATLAB UI functions.  These are mostly built out of Java Swing widgets, and while the documentation is sketchy to non existent, it is possible to utilise their features.  I don’t want to dwell on the technicalities of these widgets; if you want to know more then Yair Altman’s Undocumented Matlab blog is the best place to look.

My shortcut tools package uses this second method. It contains methods for adding, moving and removing toolbar shortcuts and browser favourites, and a few other utility functions.  I going to discuss two possible use cases for the toolbox, one really simple and another that’s slightly more advanced.

First of all, we need some code to be called by the shortcut.  This is a very simple function to tidy up your workspace:


function tidy()
%TIDY Clear workspace and command window; close plots.
close all hidden;
clear all;
clc;
end

MATLAB secretly ships with a set of icons; I’m using a cross, which is available from R2009a onwards. Feel free to use any icon you like, or leave the icon argument blank to use the standard icon. Adding a shortcut is as easy as calling AddShortcut.


iconPath = fullfile( ...
matlabroot, ...
   'toolbox', ...
   'shared', ...
   'dastudio', ...
   'resources', ...
   'TTE_delete.gif');
AddShortcut('Tidy', 'tidy();', iconPath);

You should see the shortcut appear in your toolbar. If you decide you don’t want this shortcut, you can remove it with


RemoveShortcuts([], 'Tidy');

(The first parameter requests the category of shortcut, which by default is 'Toolbar Shortcuts'. We don’t want to change this, so we can just leave it empty.)

An idea that was suggested to me by Iram Weinstein was to have different shortcuts available when you work on different projects. This requires a little more setting up, but when you can script it, it’s easy enough to do.  Let’s imagine that you like to work on both cellular automatons and 3D graphics.  Some shortcuts you use will be needed by both projects, but others will be specific to each research area.

First we need to create some categories to contain the shortcuts; one for each project and one to contain the shortcuts common to all your projects.


project1 = 'Cellular Automaton Project';
project2 = '3D Graphics Project';
common = 'Common';
AddShortcutCategory(project1);
AddShortcutCategory(project2);
AddShortcutCategory(common);

Then we add shortcuts to each category, using AddShortcut, like before. You’ll probably want several shortcuts per project, but for now let’s stick to one shortcut for each.


AddShortcut('Life', 'life();', [], project1);
AddShortcut('Teapot', 'teapotdemo();', [], project2);
AddShortcut('Tidy', 'tidy();', iconPath, common);
AddShortcut('Cellular', 'SetupCelluarProject();', [], common);
AddShortcut('Graphics', 'SetupGraphicsProject();', [], common);

In the common section, at the very least you need a shortcut to initialize each project. All that is left is to write the callback functions for those shortcuts.


function SetupCellularProject()
%SETUPCELLULARPROJECT Sets up the Cellular Automaton Project.

% Get rid of work from other projects.
tidy();

% Clear the existing toolbar
RemoveShortcuts();

% Copy the shortcuts from the common category and the project category
% to the toolbar. (The toolbar is the default target location.)
CopyShortcuts('Common');
CopyShortcuts('Cellular Automaton Project');

% Other setup code goes here. You'll probably want a call to cd here to
% move to the project directory, and perhaps addpath or load as well.
end

SetupGraphicsProject will contain similar contents. By encapsulating this setup code into a function, it means that you can call it from the command line to get going with your project as well. As a lazy typist I tend to use shorter function names for these, or at least have a short alias.

That’s it. You can now update your shortcuts at the click of a button.