Lecture 39 - Image Manipulation

Lecture Date: Monday, April 25

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:

  1. Convolve the pixel with the x_mask, resulting in an int called gX
  2. Convolve the pixel with the y_mask, resulting in an int called gY
  3. Compute the square root of the sum of squares of gX and gY called g
  4. 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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import cImage
import math

from cImage import *

def convolve(image, pixel_row, pixel_col, kernel):
    k_col_base = pixel_col - 1
    k_row_base = pixel_row - 1

    sum = 0
    for row in range(k_row_base, k_row_base + 3):
        for col in range(k_col_base, k_col_base + 3):
            k_col_index = col - k_col_base
            k_row_index = row - k_row_base

            pixel = image.getPixel(col, row)
            intensity = pixel.getRed()

            sum = sum + intensity * kernel[k_row_index][k_col_index]

    return sum

def grayscale_image(image):
    new_image = EmptyImage(image.width, image.height)

    for row in range(image.height):
        for col in range(image.width):
            old_pixel = image.getPixel(col, row)
            intensity = (old_pixel.getRed() + old_pixel.getGreen() + old_pixel.getBlue()) // 3
            new_pixel = Pixel(intensity, intensity, intensity)
            new_image.setPixel(col, row, new_pixel)

    return new_image

# Open an image
old_image = FileImage('whiteside.gif')

image_window_old = ImageWin("Original", old_image.width, old_image.height)

# Draw the image on the window
old_image.draw(image_window_old)

new_image = EmptyImage(int(old_image.width), int(old_image.height))

image_window_new = ImageWin("Edges", int(old_image.width), int(old_image.height))

new_gray_image = grayscale_image(old_image)

black_pixel = Pixel(0,0,0)
white_pixel = Pixel(256, 256,256)
x_mask = [[-1,-2,-1],[0,0,0],[1,2,1]]
y_mask = [[1,0,-1],[2,0,-2],[1,0,-1]]

for row in range(1,new_gray_image.height -1):
    for col in range(1,new_gray_image.width -1):
        gx = convolve(new_gray_image, row, col, x_mask)
        gy = convolve(new_gray_image, row, col, y_mask)
        g = math.sqrt(gx**2 + gy**2)

        if g > 175:
            new_image.setPixel(col, row, black_pixel)
        else:
            new_image.setPixel(col, row, white_pixel)

new_image.draw(image_window_new)

image_window_new.exitOnClick()
image_window_old.exitOnClick()    

Image Subtraction

Image subtraction shows us the difference between two images, highlighting what has changed. We’ll have to figure out a way to determine the distance between two colors. We can use this to loop over the images.

Version 1

Version 1

Version 2

Version 2

Image Difference
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
import math
from cImage import *

def distance(pixel_1, pixel_2):
    sum = (pixel_1.getRed() - pixel_2.getRed())**2 + (pixel_1.getBlue() - pixel_2.getBlue())**2 + (pixel_1.getGreen() - pixel_2.getGreen())**2
    return math.sqrt(sum)

def image_difference(image_1, image_2):
    diff_image = EmptyImage(image_1.width, image_1.height)

    for row in range(image_1.height):
        for col in range(image_1.width):
            dist = distance(image_1.getPixel(col, row),image_2.getPixel(col, row) )

            if dist > 20:
                black_pixel = Pixel(0,0,0)
                diff_image.setPixel(col, row, black_pixel)
            else:
                white_pixel = Pixel(256,256,256)
                diff_image.setPixel(col, row, white_pixel)
    return diff_image

image_1 = FileImage('version1.jpg')
image_1_window = ImageWin("Image 1", image_1.width, image_1.height)
image_1.draw(image_1_window)

image_2 = FileImage('version2.jpg')
image_2_window = ImageWin("Image 2", image_2.width, image_2.height)
image_2.draw(image_2_window)

image_diff = image_difference(image_1, image_2)
image_diff_window = ImageWin("Image Diff", image_diff.width, image_diff.height)
image_diff.draw(image_diff_window)

image_1_window.exitOnClick()
image_2_window.exitOnClick()
image_diff_window.exitOnClick()
Image Difference w/ Heatmap
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
48
49
50
51
52
53
54
import math
from cImage import *

def distance(pixel_1, pixel_2):
    sum = (pixel_1.getRed() - pixel_2.getRed())**2 + (pixel_1.getBlue() - pixel_2.getBlue())**2 + (pixel_1.getGreen() - pixel_2.getGreen())**2
    return math.sqrt(sum)

def get_pixel_from_distance(dist):
    if dist >= 1:
        return Pixel(255,255,255)
    elif dist <= 0:
        return Pixel(0,0,0)
    elif dist > 0.8:
        return Pixel(255,255,int(255*(dist-0.8)/0.2))
    elif dist > 0.5:
        return Pixel(255, int(255 * (dist - 0.5) / 0.3), 0)
    elif dist > 0.2:
        return Pixel(int(255 * (dist - 0.2) / 0.3), 0, int(255 * (dist - 0.5) / 0.3))

    return Pixel(0, 0, int(255 * dist / 0.2))


def image_difference(image_1, image_2):
    diff_image = EmptyImage(image_1.width, image_1.height)

    # figure out what the biggest change is to determine what's "hottest"
    max_distance = 0
    for row in range(image_1.height):
        for col in range(image_1.width):
            dist = distance(image_1.getPixel(col, row),image_2.getPixel(col, row) )
            if dist > max_distance:
                max_distance = dist

    for row in range(image_1.height):
        for col in range(image_1.width):
            dist = distance(image_1.getPixel(col, row), image_2.getPixel(col, row))
            diff_image.setPixel(col, row, get_pixel_from_distance(dist/max_distance))
    return diff_image

image_1 = FileImage('version1.jpg')
image_1_window = ImageWin("Image 1", image_1.width, image_1.height)
image_1.draw(image_1_window)

image_2 = FileImage('version2.jpg')
image_2_window = ImageWin("Image 2", image_2.width, image_2.height)
image_2.draw(image_2_window)

image_diff = image_difference(image_1, image_2)
image_diff_window = ImageWin("Image Diff", image_diff.width, image_diff.height)
image_diff.draw(image_diff_window)

image_1_window.exitOnClick()
image_2_window.exitOnClick()
image_diff_window.exitOnClick()