CSC 370

MATLAB Image Representations

[Due Wednesday, September 23]

This assignment will introduce you to more of Matlab's features, and also let you play around with some images. You will learn to read and write images, change image resolution, interpolate points, and resample images. Matlab has extensive mathematical abilities, including both scalar and matrix multiplication, that will come in handy.

Working with Images

Let's start by loading in an image and performing some simple operations on it. We'll use an image that comes with Matlab.

>> img1 = imread('boy.png');
>> img2 = img1(1:2:end,1:2:end);
>> img3 = img1(1:end/2,1:end/2);
>> imshow(img1)
>> imshow(img2)
>> imshow(img3)
>> imwrite(img3,'halfboy.png');

The operation of the various functions used above should be clear. If they are not, remember that you can always use the help command. (Even if you think you know what a command does, it's often worth reading the help file because you may learn about additional abilities and related functions. In general, Matlab functions are more versatile than functions in many other languages, and can be called in multiple different ways to achieve slightly different effects. One important note: when initially read into Matlab, image pixel values are stored using a single-byte representation called uint8 (for unsigned 8-bit integer). If you are planning on doing any sort of math using the pixel values, however, you will need to convert them to Matlab's standard internal format for numbers, using double. It's also wise to change the range of values when you do this: by convention, uint8 values are integers from 0 to 255, while image double values are decimals from 0 to 1. We'll see an example of this in a moment.

Interpolation

The interp2 function is used to interpolate data on a 2D grid. This can be used to increase the spatial resolution of an image (although details finer than those present in the original image cannot be recaptured) or simply to resample the data on a different grid of points. For example, image processing programs like Photoshop use interpolation when you resize or rotate an image. You will also need to learn about meshgrid in order to make use of interp2.

>> [nrow,ncol] = size(img1);
>> [xgrid,ygrid] = meshgrid(1:ncol,1:nrow);
>> [xgrid2,ygrid2] = meshgrid(linspace(1,ncol,1.2*ncol),linspace(1,nrow,1.2*nrow));
>> img4 = interp2(xgrid,ygrid,double(img1)/255,xgrid2,ygrid2);  % note use of double
>> imshow(img4)
>> size(img4)
ans =
    76    76
>> size(img1)
ans =
    64    64

In the example above, the spatial resolution of the image was increased by 20%. You can also use interp2 to resample an image in other ways, for example rotated by some angle. (Note that points outside the original image grid cannot be interpolated.) The secret is to create the right values in xgrid2 and ygrid2. For this, we'll need to do some math. The example below demonstrates some of Matlab's matrix mathematics, specifically, scalar multiplication and matrix addition. Basic trigonometry tells us that to rotate a point (x,y) by angle theta, one applies the following formulae:

We want to do this for every point in xgrid and ygrid. Fortunately, Matlab makes it easy. The following example shows how to carry out the above formulae for every element of the grid matrices. The result is an image rotated by 30 degrees around its upper left corner.

>> xgrid3 = cos(pi/6)*xgrid-sin(pi/6)*ygrid;
>> ygrid3 = sin(pi/6)*xgrid+cos(pi/6)*ygrid;
>> img5 = interp2(xgrid,ygrid,double(img1)/255,xgrid3,ygrid3);
>> imshow(img5)

Just for fun, we can use Matlab's plot function to plot the locations of the grid points used above. The following will print the original pixel grid (black points) with the rotated grid superimposed (magenta points). You may have to enlarge the window to see all the detail. Can you figure out how to add the higher resolution points stored in xgrid2 and ygrid2 as cyan dots?

>> plot(xgrid(:),ygrid(:),'k.')
>> hold on
>> plot(xgrid3(:),ygrid3(:),'m.')

Different Color Spaces

Color can be represented in many different ways. The image we've been using so far is a grayscale image, represented as a rectangular matrix of either uint8 or double. Actually, Matlab treats grayscale images as a special case of indexed image, where the color palette used happens to match the range of grays exactly. The example below changes the color palette to a few other possibilities.

>> imshow(img1)
>> colormap jet
>> colormap winter
>> colormap hot
>> colormap flag
>> colormap gray

True color images in Matlab are 3-dimensional arrays of either uint8 (scaled from 0 to 255) or double, MxNx3 (scaled from 0.0 to 1.0). Typically these are viewed as three 2-d matrices stacked on top of each other, with each 2-d matrix holding one of the color channels. The most common set of color channels is R-G-B, and all the functions that display images assume this is the case. You can transform images to other color spaces such as HSV, but they will look funny if you try to display them without converting back to RGB first.

>> img = imread('barn.jpg');
>> imshow(img)
>> hsv = rgb2hsv(img);
>> imshow(hsv)
>> imshow(hsv2rgb(hsv));

Once you have an image in Matlab, you can manipulate it by manipulating the numbers in its component matrices. Keep in mind that they must stay within the range between 0 and 1, but any transformation that preserves this will result in a valid image. Shifting the numbers toward zero will make an image darker; towards 1 brighter. Shifting one color component but not others will change the relative amount of that color. Some examples appear below.

>> img1 = double(img)/255;  % start with doubles between 0 and 1
>> img2 = img1/2;           % darken the image
>> imshow(img2)
>> img3 = img1/2+0.5;       % lighten the image
>> imshow(img3)
>> img4 = img1.^0.5;        % another way to lighten
>> imshow(img4)
>> img5 = img1.^2;          % another way to darken
>> imshow(img5)
>> img6 = img1;             % more red and less blue
>> img6(:,:,1) = img6(:,:,1).^0.5;
>> img6(:,:,3) = img6(:,:,3).^2;
>> imshow(img6)
>> img7 = 1-img1;           % negative image
>> imshow(img7)
>> img8 = rgb2hsv(img1);
>> img8(:,:,2) = img8(:,:,2)/2;  % desaturated image
>> imshow(hsv2rgb(img8))
>> img9 = rgb2hsv(img1);
>> img9(:,:,2) = img9(:,:,2).^0.5;  % supersaturated image
>> imshow(hsv2rgb(img9))

One note about the above: the .^ operator means that every element of an array gets raised to the specified power. Now, feel free to play around a bit and try out your own transformations.

Exercises

Part One. Find your picture. Crop it down to a 384x256 window centered around the face (use colon notation to extract the part of the image you want. Play with the limits until you have the right size and location.) Now use colon notation to decrease the spatial resolution by taking every third pixel in each direction. (This should give you a 129x86 image.) Finally, use interpolation to create a new 384x256 pixel image from the smaller one. How does it look compared with the original cropped image? (Make sure that you are viewing the image at full resolution, not scaled down.) Turn in your answer with a transcript of the commands you used to do this.

Part Two. Older color photographs used inks that were not permanent, so they lost color with time. This accounts for the washed-out look of some historical color photographs. You can simulate color bleeding by converting an image into HSV color space, decreasing the saturation (the second HSV color component) and then converting back to RGB color space. Try this on the barn image, then write an M-file called ColorFade that will do the same for any color image, returning a color-faded version. Turn in this M-file.