In this document, we will blur out the face of Teddy Roosevelt in an image of Mt. Rushmore (sorry, Teddy). This example is taken from Matloff - The Art of R Programming.

We will need the pixmap package.

install.packages("pixmap")
library(pixmap)

Download the file mtrush1.pgm from the course website and move it to your working directory. Then load it as follows:

mtrush1 <- read.pnm("mtrush1.pgm")
str(mtrush1)
## Formal class 'pixmapGrey' [package "pixmap"] with 6 slots
##   ..@ grey    : num [1:194, 1:259] 0.278 0.263 0.239 0.212 0.192 ...
##   ..@ channels: chr "grey"
##   ..@ size    : int [1:2] 194 259
##   ..@ cellres : num [1:2] 1 1
##   ..@ bbox    : num [1:4] 0 0 259 194
##   ..@ bbcent  : logi FALSE

The str function gives the “structure” of mtrush1. We see that mtrush1@grey is a \(194\times 259\) numeric matrix.

is.matrix(mtrush1@grey)
## [1] TRUE
dim(mtrush1@grey)
## [1] 194 259

This matrix encodes a picture of Mt. Rushmore, which can be seen by plotting the mtrush1 object:

plot(mtrush1)

The top left \(5\times 5\) corner of the matrix is given below:

mtrush1@grey[1:5, 1:5]
##           [,1]      [,2]      [,3]      [,4]      [,5]
## [1,] 0.2784314 0.2588235 0.2431373 0.2549020 0.2784314
## [2,] 0.2627451 0.2470588 0.2352941 0.2431373 0.2627451
## [3,] 0.2392157 0.2274510 0.2196078 0.2274510 0.2392157
## [4,] 0.2117647 0.2117647 0.2078431 0.2117647 0.2156863
## [5,] 0.1921569 0.2000000 0.2039216 0.2039216 0.2000000

Note that all the values are between 0 and 1. A value of 0 indicates a black pixel and 1 indicates a white pixel. Hence this greyscale image is represented by a matrix of values between 0 and 1.

Censor Teddy

We can blur out the face of the 26th U.S. president as follows. First, create a copy of the object called mtrush_blur.

mtrush_blur <- mtrush1

The coordinates of Teddy’s face range from 84 to 163 on the \(y\)-axis and 135 to 177 on the \(x\)-axis. Let’s set up these coordinates in code.

y <- 84:163
x <- 135:177
y_len <- length(y)
x_len <- length(x)

Now we will generate a matrix of random noise. Remember that runif(n) generates a vector of \(n\) random values between 0 and 1. We want y_len * x_len random values in total, to cover up Teddy’s face.

noise <- runif(y_len * x_len) # generate the noise
noise_mx <-  matrix(noise, nrow=y_len, ncol=x_len) # form a noise matrix
mtrush_blur@grey[y, x] <- noise_mx
plot(mtrush_blur)

And he’s gone!

Actually blurring him our

The above perhaps blurs him too much. We can control the amount of noise to add to the image by adjusting the weight of the noise.

We will continue to use noise_mx but this time take a weighted average between the noise and the true pixel value:

mtrush_blur@grey[y, x] <- mtrush1@grey[y, x] * 0.55 + noise_mx * 0.45
plot(mtrush_blur)

Now the image is only partially blurred; noise is added but you can still discern his face. By adjusting the numbers \(0.55\) and \(1-0.55 = 0.45\), you can control how much to blur the image.