This past week, I was using MATLAB and Image Processing Toolbox functions to make a thumbnail image of a lake. I thought this would make a good example of putting a variety of image processing operations to good use.
The Task
The task is to create a $128\times 128$ two-color lake thumbnail, shown above, starting from this GIS (geographic information system) map image.
lake = imread("nh-lake.png");
imshow(lake)
I got the original image above from the New Hampshire Department of Environmental Service’s Lake Information Mapper. It shows roads, topographical features, and lake depths.
imshow(lake)
xlim([318 1180])
ylim([413 1621])
The task is to show just one color for the lake, another color for outside the lake, remove the islands, make the result be $128\times 128$ square. The solution shown here uses the image type conversion function, rgb2ind
, and some morphological image processing functions, including imopen
, imclose
, imrecontruct
, imfill
, imresize
, and strel
.
Convert the Image to Indexed with Two Colors
Since the image is already close to being just two colors, one way to start is to convert the image to an indexed image with two colors. I’ll use rgb2ind
with the "nodither"
.
num_colors = 2;
[X,map] = rgb2ind(lake,num_colors,"nodither");
imshow(X,map)
Remove Street Names Using Opening by Reconstruction
The output of rgb2ind
is close, but there is more work to be done. Zooming in shows that some of the street names have the same color as the lake.
imshow(X,map)
xlim([1073 1494])
ylim([92 682])
Use binary image processing for the next few steps.
bw = ~logical(X);
imshow(bw)
imshow(bw)
xlim([1073 1494])
ylim([92 682])
I’ll erode the image to get rid of the small objects, such as the letters in the road signs. Then, I’ll use morphological reconstruction to restore the full shape of the lake. This is called opening by reconstruction. See my 14-Jul-2008 MATLAB Central blog post about opening by reconstruction.
bw2 = imerode(bw,strel("disk",5));
bw3 = imreconstruct(bw2,bw);
imshow(bw3)
title("Opening by reconstruction")
Remove Islands by Filling Holes
Use imfill
to get rid of the islands.
bw4 = imfill(bw3,"holes");
imshow(bw4)
title("Islands removed")
Remove the Stream
There is still a small stream showing at the southern end of the lake.
imshow(bw4)
xlim([549 1094])
ylim([1813 2229])
An small opening followed by a closing gets of the stream, while having only a small effect on the outline of the lake.
bw5 = imclose(imopen(bw4,ones(3,3)),ones(3,3));
imshow(bw5)
title("Stream removed")
Make the Image Square
[M,N] = size(bw5)
M = 2228
N = 1588
M - N
ans = 640
Np = ans/2
Np = 320
bw6 = [zeros(M,Np) bw5 zeros(M,Np)];
imshow(bw6)
title("Square image")
Tweak the Colors
Now let’s put this processed image back together with the colors produced by rgb2ind
.
X2 = uint8(~bw6);
imshow(X2,map)
I’d like to have more contrast and saturation. After some experimentation, I chose these colors:
map2 = [0 24 168 ; 172 220 220]/255
map2 = 2x3
0 0.0941 0.6588
0.6745 0.8627 0.8627
imshow(X2,map2)
title("New colors")
Resize the Image
Use imresize
to get a $128\times 128$ result, specifying some options that are specific to resizing indexed images. I want the same colormap, and I don’t want dithering.
[X3,map3] = imresize(X2,map2,[128 128],"bicubic",...
Colormap = "original", Dither = false);
imshow(X3,map3,InitialMagnification = 100)
Save the Image
Write the result as a PNG file.
imwrite(X3,map3,"nh-lake-2-color-128x128.png")