Lecture 39 (Sherriff) - Images 3

Lecture Date: Monday, April 20

Another day of image algorithms! These are a bit trickier than the last few days…

The algorithms for today are:

  • Edge Detection
  • Image Subtraction

Edge Detection

The edge detection algorithm will show us where the edges of objects are in an image and highlight them. The basic idea is that we can look at every pixel and then see if the pixels next to it are substantially different in intensity. To do this, we will apply a set of convolution matrices called Sobel operators to each pixel. The set consists of two matrices: one that looks for differences on the x axis and one on the y axis.

Masks

The steps of the algorithm are:

  • Convert the original image to grayscale
  • Create an empty image of the same size as the original
  • Then, for each pixel:

  • Convolve the pixel with the x_mask, resulting in an int called gX

  • Convolve the pixel with the y_mask, resulting in an int called yY
  • Compute the square root of the sum of squares of gX and gY called g
  • Based on the value of g, assign the corresponding pixel in the new image to black or white

One example would be if g > 175, make the pixel black and otherwise white.

Edge Algorithm Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public static Picture edges(Picture pict) {
  Picture grayImage = grayscaleImage(pict);
  Picture edgePic = new Picture(pict.getWidth(), pict.getHeight());
  
  int[][] xMask = \{\{-1,-2,-1\},\{0,0,0\},\{1,2,1\}\};
  int[][] yMask = \{\{1,0,-1\},\{2,0,-2\},\{1,0,-1\}\};
  
  for(int row = 1; row < grayImage.getHeight()-1; row++) {
      for(int col = 1; col < grayImage.getWidth()-1; col++) {
          int gx = convolve(grayImage, row, col, xMask);
          int gy = convolve(grayImage, row, col, yMask);
          double g = Math.sqrt(gx*gx + gy*gy);
          
          if(g > 175){
              edgePic.getPixel(col, row).setColor(Color.black);
          } else {
              edgePic.getPixel(col, row).setColor(Color.white);
          }
      }
  }
  
  
  return edgePic;
  
  
}

public static int convolve(Picture pict, int pixelRow, int pixelCol, int[][] kernel) {
  int kernelColBase = pixelCol - 1;
  int kernelRowBase = pixelRow - 1;
  
  int sum = 0;
  
  for(int row = kernelRowBase; row < kernelRowBase+3; row++) {
      for(int col = kernelColBase; col < kernelColBase+3; col++) {
          int kColIndex = col-kernelColBase;
          int kRowIndex = row-kernelRowBase;
          
          Pixel pix = pict.getPixel(col, row);
          int intensity = pix.getRed();
          
          sum = sum + intensity * kernel[kRowIndex][kColIndex];
      }
  }
  
  return sum;
}

Image Subtraction

Image subtraction shows us the difference between two images, highlighting what has changed. The Pixel class provides a method to determine the distance between two colors. We can use this to loop over the images.

Difference Code 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static Picture imageDifference(Picture v1, Picture v2) {
  
  Picture diff = new Picture(v1.getWidth(), v2.getHeight());
  
  for(int j = 0; j < v1.getHeight(); j++) {
      for(int i = 0; i < v1.getWidth(); i++) {
          Pixel p1 = v1.getPixel(i,j);
          Pixel p2 = v2.getPixel(i,j);
          
          if(p1.colorDistance(p2.getColor()) > 20) {
              diff.getPixel(i, j).setColor(Color.black);
          }
      }
  }
  
  
  return diff;
}
Difference Code 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
 * Converts a value between 0 and 1 to a false-color heatmap
 * @param number; 0.0 will be black and 1.0 will be white
 * @return a Color object based on a heatmap white->yellow->red->purple->blue->black
 */
public static Color fromNumber(double number) {
    if (number >= 1) return Color.WHITE;
    else if (number <= 0) return Color.BLACK;
    else if (number > 0.8) return new Color(255, 255, (int)(255*(number-0.8)/0.2));
    else if (number > 0.5) return new Color(255, (int)(255*(number-0.5)/0.3), 0);
    else if (number > 0.2) return new Color((int)(255*(number-0.2)/0.3), 0, (int)(255*(0.5-number)/0.3));
    else return new Color(0, 0, (int)(255*number/0.2));
}

/**
 * Creates an image based on the difference between two other images
 * @param a One image
 * @param b The other image
 * @return An image that it the size of the smaller of the two parameters representing the difference of the two
 */
public static Picture difference(Picture a, Picture b) {
    Picture result = new Picture(Math.min(a.getWidth(), b.getWidth()), Math.min(a.getHeight(),b.getHeight()));
    double maxDifference = 0;
    for(int x = 0; x < result.getWidth(); x += 1) {
        for(int y=0; y < result.getHeight(); y+=1) {
            double diff = a.getPixel(x, y).colorDistance(b.getPixel(x, y).getColor());
            if (diff > maxDifference) maxDifference = diff;
        }
    }
    for(int x = 0; x < result.getWidth(); x += 1) {
        for(int y=0; y < result.getHeight(); y+=1) {
            result.getPixel(x, y).setColor(fromNumber(a.getPixel(x, y).colorDistance(b.getPixel(x, y).getColor())/maxDifference));
        }
    }
    return result;
}