Load the required R packages. EBImage handles image data, RSNNS contains an RBF function

source("http://bioconductor.org/biocLite.R")
biocLite("EBImage")
## package 'EBImage' successfully unpacked and MD5 sums checked
## 
## The downloaded binary packages are in
##  C:\Users\baris0074\AppData\Local\Temp\RtmpIXrMUQ\downloaded_packages
library("EBImage")

library(RSNNS)

Load the image to reconstruct

# 150x100 brown sheep
filename = "C:/Users/baris0074/Desktop/CS 545/brown_sheep.jpg"

Define image data for the original image. This must be done before any functions are defined since they all reference the length and height of the image.

# display original image
# raster method displays image in RStudio
# browser method (default) displays image in browser
image = readImage(filename)

# imageData() gives pixel values of the image in the form:
# imageData = [R,G,B] where R,G,B represent a matrix of normalized
# pixel values for each color pane
originalImage = imageData(image)

The Original Image

Determine the dimensions of the image

length = dim(image)[1]
height = dim(image)[2]
size = length*height

Artificially damage an image by adding “noise”

createNoiseImage = function(imageData,noiseLevel){
  
  # data from original image
  imageData = imageData(imageData)
  
  # make empty image
  noiseImage = array(dim=c(length,height,3))
  
  # create "noisy" image
  for(i in 1:height){
    # a random number in (-noiseLevel,noiseLevel) will give pixels
    # noise of < (100*noiseLevel)%
    noise = runif(length, min=-noiseLevel, max=noiseLevel)
    

    noiseImage[,i,1] = imageData[,i,1] + noise
    noiseImage[,i,2] = imageData[,i,2] + noise
    noiseImage[,i,3] = imageData[,i,3] + noise

  }
  
  damagedImage = rgbImage(noiseImage[,,1],noiseImage[,,2],noiseImage[,,3])
  display(damagedImage)
  
  return(imageData(damagedImage))
}  

Image damaged by 25% and 75% noise


Artificially damage images by removing random pixels

createMissingPixels = function(imageData,numPixels){
  
  # make empty image
  holesImage = array(dim=c(length,height,3))

  # create "full of holes" image
  for(i in 1:length){
    for(j in 1:height){
      # 
      # if a random number in (0,1) is less than numPixels
      # then (100*numPixels)% of pixels will be blacked out
      if(runif(1) < numPixels){holesImage[i,j,1] = 0;
                        holesImage[i,j,2] = 0;
                        holesImage[i,j,3] = 0}
      else{holesImage[i,j,1] = imageData[i,j,1];
          holesImage[i,j,2] = imageData[i,j,2];
          holesImage[i,j,3] = imageData[i,j,3]}
    }
  }
  
  damagedImage = rgbImage(holesImage[,,1],holesImage[,,2],holesImage[,,3])
  display(damagedImage)
  
  return(imageData(damagedImage))
}

Image damaged by 25% and 75% missing pixels


Radial Basis Function Network

The RBF function takes a single row or column of the damaged image and applies a Radial Basis Function Network to approximate an output. The network can be optimized by adjusting the size of the hidden layer, the number of iterations, etc.

RBF = function(input,output){
  # input is just an index
  inputs = input
  # outputs either row or column of image
  outputs = output
  
  # RBF network
  model = rbf(inputs, outputs, size=10, maxit=1000,
              initFuncParams=c(0, 1, 0, 0.01, 0.01),
              learnFuncParams=c(1e-8, 0, 1e-8, 0, 1), linOut=TRUE)
  
  # predictive model
  return(fitted(model))
}

Interpolation

Perform interpolation of image, first length-wise then height-wise. Then overlay each interpolated image and average.

interpolate = function(imageData){
  
  interpolatedImage_H = matrix(,ncol=length,nrow=height)
  interpolatedImage_L = matrix(,ncol=length,nrow=height)
  
  input_H = as.matrix(seq(1,height,1))
  input_L = as.matrix(seq(1,length,1))
  
  # interpolate in height direction
  for(i in 1:length){
    model = RBF(input_H,imageData[i,])
    interpolatedImage_H[,i] = model
  }
  
  # interpolate in length direction
  for(j in 1:height){
    model = RBF(input_L,imageData[,j])
    interpolatedImage_L[j,] = model
  }
  
  # put them together
  # overlay images interpolated by length and by height
  # and average
  interpolatedImage = t((interpolatedImage_H + interpolatedImage_L)/2)
  
  # return image data of interpolated image
  return(interpolatedImage)
  
}

Use interpolate function on each color pane separately, then combine.

interpolateColors = function(imageData){
  # Red
  interpolateRed = interpolate(imageData[,,1])
  
  # Green
  interpolateGreen = interpolate(imageData[,,2])
  
  # Blue
  interpolateBlue = interpolate(imageData[,,3])
  
  # Combine
  interpolateImage = rgbImage(interpolateRed,interpolateGreen,interpolateBlue)
  display(interpolateImage)
  
  # return image data of interpolated image
  return(imageData(interpolateImage))
}

Error Calculation

Mean Square Error between original image and restored image to measure how well the interpolation performs.

MSE = function(originalImage,restoredImage){
  sumRed = 0
  sumGreen = 0
  sumBlue = 0
  
  for(i in 1:length){
    for(j in 1:height){
      sumRed = sumRed + (originalImage[i,j,1] - restoredImage[i,j,1])^2
      sumGreen = sumGreen + (originalImage[i,j,2] - restoredImage[i,j,2])^2
      sumBlue = sumBlue + (originalImage[i,j,3] - restoredImage[i,j,3])^2
    }
  }
  
  MSERed = sumRed/size
  MSEGreen = sumGreen/size
  MSEBlue = sumBlue/size
  
  avgMSE = (MSERed + MSEGreen + MSEBlue)/3
  
  print('MSE of red pixels:')
  print(MSERed)
  print('------------------')
  print('MSE of green pixels:')
  print(MSEGreen)
  print('--------------------')
  print('MSE of blue pixels:')
  print(MSEBlue)
  print('-------------------')
  print('average MSE:')
  print(avgMSE)
}

Perform Interpolation

Use RBF Networks on to restore each of the damaged images

25% noise

## [1] "MSE of red pixels:"
## [1] 0.0208891
## [1] "------------------"
## [1] "MSE of green pixels:"
## [1] 0.0208891
## [1] "--------------------"
## [1] "MSE of blue pixels:"
## [1] 0.0208891
## [1] "-------------------"
## [1] "average MSE:"
## [1] 0.0208891

## [1] "MSE of red pixels:"
## [1] 0.005829795
## [1] "------------------"
## [1] "MSE of green pixels:"
## [1] 0.006915936
## [1] "--------------------"
## [1] "MSE of blue pixels:"
## [1] 0.003987197
## [1] "-------------------"
## [1] "average MSE:"
## [1] 0.005577643

75% noise

## [1] "MSE of red pixels:"
## [1] 0.1844834
## [1] "------------------"
## [1] "MSE of green pixels:"
## [1] 0.1844834
## [1] "--------------------"
## [1] "MSE of blue pixels:"
## [1] 0.1844834
## [1] "-------------------"
## [1] "average MSE:"
## [1] 0.1844834

## [1] "MSE of red pixels:"
## [1] 0.01396887
## [1] "------------------"
## [1] "MSE of green pixels:"
## [1] 0.01509207
## [1] "--------------------"
## [1] "MSE of blue pixels:"
## [1] 0.01220049
## [1] "-------------------"
## [1] "average MSE:"
## [1] 0.01375381

25% of pixels missing

## [1] "MSE of red pixels:"
## [1] 0.04842484
## [1] "------------------"
## [1] "MSE of green pixels:"
## [1] 0.06622047
## [1] "--------------------"
## [1] "MSE of blue pixels:"
## [1] 0.01701701
## [1] "-------------------"
## [1] "average MSE:"
## [1] 0.04388744

## [1] "MSE of red pixels:"
## [1] 0.01959483
## [1] "------------------"
## [1] "MSE of green pixels:"
## [1] 0.02632066
## [1] "--------------------"
## [1] "MSE of blue pixels:"
## [1] 0.008152145
## [1] "-------------------"
## [1] "average MSE:"
## [1] 0.01802255

75% of pixels missing

## [1] "MSE of red pixels:"
## [1] 0.1432768
## [1] "------------------"
## [1] "MSE of green pixels:"
## [1] 0.1953974
## [1] "--------------------"
## [1] "MSE of blue pixels:"
## [1] 0.05011653
## [1] "-------------------"
## [1] "average MSE:"
## [1] 0.1295969

## [1] "MSE of red pixels:"
## [1] 0.1128522
## [1] "------------------"
## [1] "MSE of green pixels:"
## [1] 0.1537243
## [1] "--------------------"
## [1] "MSE of blue pixels:"
## [1] 0.04008002
## [1] "-------------------"
## [1] "average MSE:"
## [1] 0.1022188