Partly due to a lack of complete functionality with the Obama Poster Generator, I decided to turn it into a much more generic and useful script for taking an image, smoothing/filtering it, and then changing the palette of the result. Most often this is used to generate things like President Obama’s campaign posters, any t-shirt graphic that has 2 to 4 colors and very smooth lines–at least, the ones based on existing images of people and things, and I think it could be used, in principle, to create the effect of some of the cel-shaded video games, in the style of Jet Grind Radio, or even to create an animation style similar to that of A Scanner Darkly or the Charles Schwab commercials. Why? A normal image contains 8 bits of data per color channel, if it is a truecolor image. If one were to take a picture of a “solid” color, then the lower order bits will be integral in the “texture” of the image, created by variations in the color strength. However, if we chop off these lower order bits and then repaint the whole image in a specific subset of the 24-bit truecolor image, but still using 24-bits to get very precise colors, the textures of things disappear, and the only variations that are visible correspond mostly to edges of things and differences in lighting. I’ve included an example of what our President would look like as a video game character, for effect, but the results aren’t the best because it would take a very long time to determine the correct palette for the effect that we want, and I simply generated a uniform palette that discards the lowest bits when converting, but the similarity is still apparent.
In practice, generating high quality animated-style images based on real photographs will require hours of tweaking the palette’s colors, and while I was able to get away with only a few bits of resolution (I used 2 bits), to have something that looks high quality or has a large number of colors, a larger resolution will be necessary. Interestingly enough, for resolutions above 4 bits, the image looks basically the same, but weird in subtle ways that humans have trouble pin pointing. A resolution like this with a very restricted palette (say, the 3 bit one, properly expanded to provide information for all of the combinations) could provide very fine-grained control of the animated styled.
Without further ado, a re-post of the original picture, a much more accurate campaign-style poster, and a video game/commercial version of a portrait of president Obama, along with the palette files that I used for each of them:

Original portrait of President Obama

A Campaign Poster-style Version of the original portrait

A more cartoony, Jet Grind Radio-style version of the Portrait
Palettes:
For the campaign poster (this will need modification on a per-image basis, but the colors should be the same): click here.
For the cartoon-y image (I would recommend making one that is more appropriate for how you want the image to be transformed, this was just a rough starting point): click here.
And, the code. My first contribution to the open source movement, incidentally.
% *************************************************************************
% Image Poster Generator, v2.0
% This filters, decreases the resolution, and then repaints and image with
% values from a specified palette.
%
% Copyright (C) 2009 Greg Malysa
% *************************************************************************
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see < http://www.gnu.org/licenses/ >.
% *************************************************************************
% Specify the names of the palette image, the input, and the output
paletteName = 'palette2bit.png';
inputName = 'obama.jpg';
outputName = 'obama_filt_out.png';
outputType = 'png';
% The darken factor divides all of the pixel values in the image by the
% amount given here in order to change the brightness or darkness of the
% image as a whole.
darken = 1.35;
% Amount of smoothing to apply, between 1 and any integer. Large values
% will make things become far too smooth though, so be careful. 1 does no
% smoothing.
smooth = 4;
% The new target resolution (in bits), which also determines the palette
% size. This must be >= 1 or nothing particularly interesting happens.
% Higher resolutions require larger palettes and allow for more colors.
% With resolution = 8, nothing happens, as all of these images are 8-bits
% per channel anyway (24-bit truecolor images).
targetBits = 2;
paletteSize = 2^targetBits;
divideFactor = 256 / paletteSize;
% The palette itself is a column of bits number of bits by bits blocks,
% where the block number indicates the red channel index, the x offset
% within a block indicates the green channel index, and the y offset
% indicates the blue channel index. For some reason, MATLAB specifies y
% first and x second when accessing an image.
paletteBase = cast(imread(paletteName), 'uint8');
palette = zeros([paletteSize paletteSize paletteSize 3]);
for block = 1:paletteSize
blockBase = (block-1)*paletteSize;
for green = 1:paletteSize %x
for blue = 1:paletteSize %y
palette(block, green, blue, :) = paletteBase(blue, blockBase+green, :);
end
end
end
% Format is columns by lines by channels (y, x, 3)
image = imread(inputName)/darken;
% Create a filter coefficient matrix based on the order of smoothness
% requested (this is like a 2-D averager, which is a form of low-pass
% filter). This can be changed to create an edge-detector, for instance.
B = ones(smooth)/(smooth*smooth);
% Apply to each channel separately
imagenew(:,:,1) = filter2(B, image(:,:,1));
imagenew(:,:,2) = filter2(B, image(:,:,2));
imagenew(:,:,3) = filter2(B, image(:,:,3));
% Decrease the resolution based on the bit number requested above, dealing
% with some inconsistencies between MATLAB's casting and traditional
% conventions, and MATLAB's array access mechanisms.
imagenew = cast(imagenew, 'double');
image = cast(floor(imagenew/divideFactor), 'uint8')+1;
% Channel 1 is red, channel 2 is green, and channel 3 is blue
for n = 1:length(image(:,1,1))
for k = 1:length(image(1,:,1))
image(n, k, :) = palette(image(n, k, 1), image(n, k, 2), image(n, k, 3), :);
end
end
% Write out the final image
imwrite(cast(image, 'uint8'), outputName, outputType);