Date

Lecture Date: Monday, November 28

More image manipulation algorithms today!

Our main algorithms for the day will be:

  • Grayscale
  • Resizing
  • Green Screen
  • Edge Detection
  • Image Differences (if time)

Grayscale

The basic idea here to get the overall intensity of the color by adding up the red, green, and blue values and then taking the average. Remember that for a pixel to be gray (or black or white), all three RGB values have to be the same.

# Here we define a method that will take a pixel
# and return a pixel that is the right intensity of gray
def negative_pixel(old_pixel):
    intensity = (old_pixel.getRed() + old_pixel.getGreen() + old_pixel.getBlue()) // 3
    new_pixel = Pixel(intensity, intensity, intensity)
    return new_pixel

Resizing

With resizing, we will either be taking a fraction of the pixels (to make the image smaller) or duplicating pixels (to make the image bigger). We begin by creating a new image at the new size. Then, as we adjust the looping through our original image based on the scaling factor - we either skip pixels to make a smaller image or grab the same pixel multiple times to enlarge it.

from cImage import *

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

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

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

scale = float(input("Scale?: "))

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

image_window_new = ImageWin("Scaled", int(old_image.width* scale), int(old_image.height* scale))

for row in range(int(old_image.height*scale)):
    for col in range(int(old_image.width*scale)):
        old_pixel = old_image.getPixel(int(col/scale), int(row/scale))
        new_image.setPixel(col, row, old_pixel)

new_image.draw(image_window_new)

image_window_new.exitOnClick()
image_window_old.exitOnClick()

Green Screen

Take two pictures, one in which the background is completely one solid color that you wouldn't normally find in a "typical" picture. (This is one reason TV weathermen don't wear green...) Then, as you loop through both pictures, pick the pixels from the background image if the matching pixel from the foreground image is green. Otherwise, take the pixel from the foreground image. Here are two images we can work with:

Code:

from cImage import *

def isGreen(greenPixel):
    if greenPixel.getGreen() > greenPixel.getRed() + greenPixel.getBlue():
        return True
    return False

green_image = FileImage('ninja.gif')
background_image = FileImage('mtn.gif')
image_window = ImageWin("Green Screen", green_image.width * 3, green_image.height)
green_image.draw(image_window)
background_image.setPosition(green_image.width + 1, 0)
background_image.draw(image_window)

combined_image = EmptyImage(green_image.width, green_image.height)

for row in range(green_image.height):
    for col in range(green_image.width):
        if isGreen(green_image.getPixel(col, row)):
            new_pixel = background_image.getPixel(col, row)
            combined_image.setPixel(col, row, new_pixel)
        else:
            new_pixel = green_image.getPixel(col, row)
            combined_image.setPixel(col, row, new_pixel)

combined_image.setPosition(background_image.width + green_image.width + 1, 0)
combined_image.draw(image_window)

image_window.exitOnClick()

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.

/images/mask_s.jpg

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.

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 > 50:
            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 Difference

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.