Sunday, March 20, 2016

Module 3 - Image Manipulation Portfolio


Image Manipulation Portfolio

Over the last couple of weeks, we've explored Python multimedia programming through the Jython Environment for Students (JES). The functions below require arguments be passed in when called, and when that's a picture or image, it necessitates our having first created and stored appropriate variables via the command line (pickAFile() and makePicture()).

1.  Rose Colored Glasses
Reading over some of my colleagues' code, I have learned that this function needn't be so complicated as my approach below.  It's enough to loop through an image's pixels and alter/set each RGB value by a percentage relative to red.  Nevertheless, here I used the same approach a lot of filters use, firstly converting the image to BnW by invoking a BnW function, looping through that image's pixels,  and setting the red and blue to varying degrees dependent on the level of shade, mid-tone or highlight.

def roseColoredGlasses(pic):
  """problem 3 takes picture and repaints it so that images appears a rosy pink"""
  grayscale = betterBnW(pic)    # convert image to grayscale by calling betterBnW()
  pixels = getPixels(grayscale)
  for pix in pixels:
    r = getRed(pix)
    b = getBlue(pix)
    #tint shadows
    if r < 63:
      r *= 1.1
      b *= 0.9
    #tint midtones
    elif r >= 63 and r < 192:
      r *= 1.75
      b *= 0.85
    #tint highlights
    elif r >=192 and r <= 255:
      r *= 2.48
      b *= 0.93
    else:
      r = 255
      b *= 0.93
    setRed(pix, r)
    setBlue(pix, b)
  rose_colored = grayscale
  repaint(rose_colored)
  writePictureTo(rose_colored, '/Users/lisabenson/Documents/CST205/Module3/rose_colored_glasses.jpg')
  return rose_colored

Calla lilies, before and after:



_______________________________________________________________________________
2.  Negative
This function loops through an image's pixels and sets each RGB scale value for each to an opposite value.  The opposite value of 0 is to be 255, the opposite of 1 is to be 254, and the opposite of 127 to be 128.

def makeNegative(pic):
  """creates the negative of original picture"""
  pixels = getPixels(pic)
  for pix in pixels:
    r = getRed(pix)
    g = getGreen(pix)
    b = getBlue(pix)
    new_r = 255 - r
    new_g = 255 - g
    new_b = 255 - b
    setRed(pix, new_r)
    setGreen(pix, new_g)
    setBlue(pix, new_b)
  repaint(pic)
  #writePictureTo(pic, '/Users/lisabenson/Documents/CST205/Module2_Lab3/negative_pic.jpg')
  return pic

CSUMB campus artwork, before and after:



_________________________________________________________________________________
3.  Better Black and White
This function simulates a black and white image by converting the color image to grayscale. Each RGB value in a pixel must be the same, e.g. 0, 0, 0 or 1, 1, 1. One way to do this would be to take the average of the RGB values of a pixel and reassign it to each one, but a better formula is for luminance at R*0.299 + G*0.587 + B*0.114, which will similarly be the new value of each RGB value of each pixel looped through in the function.

def betterBnW(pic):
  """makes an image grayscale with luminance formula R*0.299 + G*0.587 + B*0.114"""
  pixels = getPixels(pic)
  for pix in pixels:
    r = getRed(pix)
    g = getGreen(pix)
    b = getBlue(pix)
    luminance = r*0.299 + g*0.587 + b*0.114
    setRed(pix, luminance)
    setGreen(pix, luminance)
    setBlue(pix, luminance)
  repaint(pic)
  return pic  # if function was called as a helper function, comment out repaint(pic) and use return pic

Monterey Bay sand dunes, before and after:



_________________________________________________________________________________
4.  Bottom-to-top
This function mirrors the bottom part of the image, so that the top part is its reflection.  It loops through the image to be copied and sets the pixel to the opposite location.

def bottomToTop(pic):
  width = getWidth(pic)
  half_height = getHeight(pic)/2
  height = getHeight(pic)
  for x in range(0, width):
    for y in range(half_height, height):
      px = getPixel(pic, x, y)
      opp_px = getPixel(pic, x, height - 1 - y)
      c = getColor(px)
      setColor(opp_px, c)
  repaint(pic)
  writePictureTo(pic, '/Users/lisabenson/Documents/CST205/Module2_Lab4_Voss/bottom-to-top.jpg')

Bicycles parked outside the CSUMB STEM building, before and after:




_________________________________________________________________________________
5.  Shrink
This function shrinks a picture.  Firstly, we create a new, shrunk, empty picture with reduced width and height.  Then, we loop through the width and height of the original image in increments of the reduction, so to get half the size we'll loop by increments of two.  We then reconstitute the new image by setting the old pixel values to the shrunk images value that meanwhile have incremented by only one.

def shrink(picture):
  """make a copy of a picture that is half as big as the original"""
  width = getWidth(picture)
  height = getHeight(picture)
  shrunk_pic = makeEmptyPicture(width / 2, height / 2)
  a = 0
  for x in range(0, width, 2):
    b = 0
    for y in range(0, height, 2):
      px = getPixel(picture, x, y)
      shrunk_px = getPixel(shrunk_pic, a, b)
      c = getColor(px)
      setColor(shrunk_px, c)
      b += 1
    a += 1
  repaint(shrunk_pic)
  writePictureTo(shrunk_pic, '/Users/lisabenson/Documents/CST205/Module2_Lab4/shrunk_pic.jpg')
  return shrunk_pic

Photograph of the letter "t" from the cover of Sunset Magazine (March 2016), before and after:





_________________________________________________________________________________
6.  Make A Collage
This function copies manipulated images onto a target image at specified x,y locations.



def makeCollage():
  target = makePicture(pickAFile()) # 2550, 3500  # 637 and 875
  show(target)
  pyCopy(makeNegative(), target, 0, 0)
  pyCopy(rotatePic(), target, 800, 0)
  pyCopy(artify(), target, 1600, 0)
  pyCopy(quadrupleMirror(), target, 1600, 800)
  pyCopy(bottomToTop(), target, 800, 800)
  pyCopy(halfHalfBlue(), target, 0, 1600)
  pyCopy(lightenUp(), target, 800, 1600)
  pyCopy(betterBnW(), target, 1600, 1600)
  pyCopy(sepia(), target, 800, 2400)
  pyCopy(redEye(), target, 0, 2400)

#-------------------------------------------

def pyCopy(source, target, targetX, targetY):
  """function creates a new, bigger blank picture and copy the picture to the middle of it"""
  width = getWidth(source)
  height = getHeight(source)
  # target = makeEmptyPicture(width + targetX, height + targetY)  # Optional to invoke with empty target picture of any size, which will be rewritten
  for x in range(0, width):
    for y in range(0, height):
      old_pixel = getPixel(source, x, y)
      color = getColor(old_pixel)
      new_pixel = getPixel(target, (targetX + x), (targetY + y))
      setColor(new_pixel, color)
  show(target)
  writePictureTo(target, '/Users/lisabenson/Documents/CST205/Module2_Lab5/mycollage_Voss.jpg')   return target

#-------------------------------------------

def makeNegative():
  """creates the negative of original picture"""
  filename = pickAFile()
  pic = makePicture(filename)
  pixels = getPixels(pic)
  for pix in pixels:
    r = getRed(pix)
    g = getGreen(pix)
    b = getBlue(pix)
    new_r = 255 - r
    new_g = 255 - g
    new_b = 255 - b
    setRed(pix, new_r)
    setGreen(pix, new_g)
    setBlue(pix, new_b)
  return pic

#-------------------------------------------

def rotatePic():
  filename = pickAFile()
  picture = makePicture(filename)
  width = getWidth(picture)
  height = getHeight(picture)
  rotated_pic = makeEmptyPicture(height, width)
  for x in range(0, width):
    for y in range(0, height):
      px = getPixel(picture, x, y)
      rotated_px = getPixel(rotated_pic, y, x)
      c = getColor(px)
      setColor(rotated_px, c)
  return rotated_pic

#-------------------------------------------

def verticalMirror(picture):
  width = getWidth(picture)
  half_width = getWidth(picture)/2
  height = getHeight(picture)
  for x in range(0, half_width):
    for y in range(0, height):
      px = getPixel(picture, x, y)
      opp_px = getPixel(picture, width - 1 - x, y)
      c = getColor(px)
      setColor(opp_px, c)
  return picture

#-------------------------------------------

def horizontalMirror(picture):
  width = getWidth(picture)
  half_height = getHeight(picture)/2
  height = getHeight(picture)
  for x in range(0, width):
    for y in range(0, half_height):
      px = getPixel(picture, x, y)
      opp_px = getPixel(picture, x, height - 1 - y)
      c = getColor(px)
      setColor(opp_px, c)
  return picture    


#-------------------------------------------

def quadrupleMirror():
  filename = pickAFile()
  picture = makePicture(filename)
  vertical_pic = verticalMirror(picture)
  quadruple = horizontalMirror(vertical_pic)
  return quadruple

#-------------------------------------------


def bottomToTop():
  filename = pickAFile()
  pic = makePicture(filename)
  width = getWidth(pic)
  half_height = getHeight(pic)/2
  height = getHeight(pic)
  for x in range(0, width):
    for y in range(half_height, height):
      px = getPixel(pic, x, y)
      opp_px = getPixel(pic, x, height - 1 - y)
      c = getColor(px)
      setColor(opp_px, c)
  return pic

#-------------------------------------------

def halfHalfBlue():
  filename = pickAFile()
  picture = makePicture(filename)
  for x in range(0, (getWidth(picture)/2)):
    for y in range(0, (getHeight(picture)/2)):
      px = getPixel(picture, x, y)
      b = getBlue(px)
      setBlue(px, b * .25)
  return picture

#-------------------------------------------

def lightenUp():
  filename = pickAFile()
  pic = makePicture(filename)
  pixels = getPixels(pic)
  for pix in pixels:
    old_color = getColor(pix)
    new_color = makeLighter(old_color)
    setColor(pix, new_color)
  return pic

#-------------------------------------------

def betterBnW():
  filename = pickAFile()
  pic = makePicture(filename)
  pixels = getPixels(pic)
  for pix in pixels:
    r = getRed(pix)
    g = getGreen(pix)
    b = getBlue(pix)
    luminance = r*0.299 + g*0.587 + b*0.114
    setRed(pix, luminance)
    setGreen(pix, luminance)
    setBlue(pix, luminance)
  return pic

#-------------------------------------------

# Sepia
def lum(color):
  # lum = R*0.299 + G*0.587 + B*0.114

  c = .229 * color.getRed() + .587 * color.getGreen() +  .114 * color.getBlue()
  return c

def sepiaInternal(color):
  r = b = g = lum(color)

  if r < 63:
    r *= 1.1
    b *= .9
  elif r < 192:
    r *= 1.15
    b *= .85
  else:
    r *= 1.08
    b *= .93
  color.setRGB(min(int(r), 255),int(g),int(b))

def sepia():
  filename = pickAFile()
  pic = makePicture(filename)
  height = getHeight(pic)
  width = getWidth(pic)
  for y in xrange(0, height):
    for x in xrange(0, width):
      # lum
      p = getPixelAt(pic, x, y)
      c = getColor(p)
      sepiaInternal(c)
      setColor(p, c)
  return pic

#-------------------------------------------

def redEye():
  filename = pickAFile()
  picture = makePicture(filename)
  for x in range(198, 274):
    for y in range(367, 450):
      current_pixel = getPixel(picture ,x, y)
      if (distance(red,getColor(current_pixel)) < 165):
        setColor(current_pixel, black)
  return picture

#-------------------------------------------
# Shawn's Artify
def artify():
  filename = pickAFile()
  pic = makePicture(filename)
  height = getHeight(pic)
  width = getWidth(pic)
  rlist = [31, 95, 159, 223]
  glist = [4, 17, 36, 73]
  blist = [22, 33, 180, 200]
  for y in xrange(0, height):
    for x in xrange(0, width):
      p = getPixelAt(pic, x, y)
      c = getColor(p)
      r = rlist[c.getRed() / 64]
      g = glist[c.getGreen() / 64]
      b = blist[c.getBlue() / 64]
      setColor(p, makeColor(r, g, b))
  return pic

                                         
_________________________________________________________________________________
7. Red-eye Reduction
For this function, if the red color sampled is within distance to a pre-specified level, the color will be replaced.  Targeting the locations in which to take samples limits smudging in areas away from the eyes.  I chose a bright green below to highlight the change.

def redEye(picture, replacementColor):
  for x in range(142, 194):   # targeted x,y locations limits smudging
    for y in range(263, 313):
      current_pixel = getPixel(picture ,x,y)
      if (distance(red,getColor(current_pixel)) < 165):
        setColor(current_pixel, replacementColor)
  repaint(picture)
  return picture

Cottontail rabbit, before and after:


_________________________________________________________________________________
8. Artify
This was a part of a pair programming assignment, so Shawn drove and wrote the function, and deserves credit here.  He firstly creates lists with random (0-256) red, green and blue numeric values, then loops through the image's pixels over a range of the height and width values of the image.  New RGB values are set when the to zero through four achieved by dividing 256 by each of the old RBG values yields the index of the list.

# Shawn's Artify
def artify(pic):
  height = getHeight(pic)
  width = getWidth(pic)
  rlist = [31, 95, 159, 223]
  glist = [4, 17, 36, 73]
  blist = [22, 33, 180, 200]
  for y in xrange(0, height):
    for x in xrange(0, width):
      p = getPixelAt(pic, x, y)
      c = getColor(p)
      r = rlist[c.getRed() / 64]
      g = glist[c.getGreen() / 64]
      b = blist[c.getBlue() / 64]
      setColor(p, makeColor(r, g, b))
  return pic



 
_________________________________________________________________________________
9. Green-screen
I used Adobe Photoshop to hastily lasso and cut a selfie and affix it to a green layer background.  Using explore() in JES, I sampled the RGB values of the green background to find a representative one, made it a color to be passed into my function, along with the background image and the distance from it, to which a color must range to avoid having its pixels gotten and re-set.  This was a part of a pair programming assignment, so Cian drove and wrote the function, and deserves credit here.  He wrote the function to work for pictures of different sizes.

# Cian's Chromakey
def chromakey(backg, foreg, dist, col):   # greenback = makeColor(56, 152, 24)
  if getWidth(backg) >= getWidth(foreg):
    for x in range(0, getWidth(foreg)):
      if getHeight(backg) >= getHeight(foreg):
        for y in range(0, getHeight(foreg)):
          if distance(getColor(getPixel(foreg, x, y)), col) < dist:
            p = getPixel(foreg, x, y)
            setColor(p, getColor(getPixel(backg, x, y)))
      elif getWidth(backg) <= getWidth(foreg):
        for y in range(0, getHeight(backg)):
          if distance(getColor(getPixel(foreg, x, y)), col) < dist:
            p = getPixel(foreg, x, y)
            setColor(p, getColor(getPixel(backg, x, y)))
  elif getWidth(backg) <= getWidth(foreg):
    for x in range(0, getWidth(backg)):
      if getHeight(backg) >= getHeight(foreg):
        for y in range(0, getHeight(foreg)):
          if distance(getColor(getPixel(foreg, x, y)), col) < dist:
            p = getPixel(foreg, x, y)
            setColor(p, getColor(getPixel(backg, x, y)))
      elif getWidth(backg) <= getWidth(foreg):
        for y in range(0, getHeight(backg)):
          if distance(getColor(getPixel(foreg, x, y)), col) < dist:
            p = getPixel(foreg, x, y)
            setColor(p, getColor(getPixel(backg, x, y)))
  show(foreg)
  return foreg





_________________________________________________________________________________
10. Home-made St. Patrick's Day Card

def stPatCard(background, image1, image2):
  background = rotatePic(background)
  new_image = addText(background)
  rainbow_image = addRainbow(new_image)
  pic_with_added_image1 = addImage(image1, rainbow_image, 20, 10)
  artify(image2)
  pic_with_added_image2 = addImage(image2, pic_with_added_image1,145, 550)
  show(pic_with_added_image2)
  writePictureTo(pic_with_added_image2, '/Users/lisabenson/Documents/CST205/Module3_Lab7/st-pat_card.jpg')

def rotatePic(background):
  width = getWidth(background)
  height = getHeight(background)
  if width > height:
    rotated_pic = makeEmptyPicture(height, width)
    for x in range(0, width):
      for y in range(0, height):
        px = getPixel(background, x, y)
        rotated_px = getPixel(rotated_pic, y, x)
        c = getColor(px)
        setColor(rotated_px, c)
    return rotated_pic
  else:
    return background

def addText(pic):
  gold = makeColor(204, 204, 0)
  style = makeStyle(mono, bold, 30)
  text = "Happy St. Patrick's Day!"
  addTextWithStyle(pic, 70, 390, text, style, gold)
  return pic

def addRainbow(pic):
  #Adds RGB rainbow to card
  purple = makeColor(153, 0, 255)
  addArcFilled(pic, 145, 500, 300, 100, 0, 180, purple)
  addArcFilled(pic, 145, 480, 300, 100, 0, 180, blue)
  addArcFilled(pic, 145, 460, 300, 100, 0, 180, green)
  addArcFilled(pic, 145, 440, 300, 100, 0, 180, yellow)
  addArcFilled(pic, 145, 420, 300, 100, 0, 180, orange)
  addArcFilled(pic, 145, 400, 300, 100, 0, 180, red)
  return pic

def artify(pic):
  height = getHeight(pic)
  width = getWidth(pic)
  rlist = [31, 95, 159, 223]
  glist = [4, 17, 36, 73]
  blist = [22, 33, 180, 200]
  for y in xrange(0, height):
    for x in xrange(0, width):
      # lum
      p = getPixelAt(pic, x, y)
      c = getColor(p)
      r = rlist[c.getRed() / 64]
      g = glist[c.getGreen() / 64]
      b = blist[c.getBlue() / 64]
      setColor(p, makeColor(r, g, b))
  return pic

def addImage(source, target, targetX, targetY):
  """function creates a new, bigger blank picture and copy the picture to the middle of it"""
  width = getWidth(source)
  height = getHeight(source)
  # target = makeEmptyPicture(width + targetX, height + targetY)  # Optional to invoke with empty target picture of any size, which will be rewritten
  for x in range(0, width):
    for y in range(0, height):
      old_pixel = getPixel(source, x, y)
      color = getColor(old_pixel)
      new_pixel = getPixel(target, (targetX + x), (targetY + y))
      setColor(new_pixel, color)
  return target

Here's the funny little St. Patrick's Day Card I made using addText(), addArcFilled() and others:



_________________________________________________________________________________
11. Advanced Image Processing Technique
This function changes a pixel according to the difference between it and the colors of the pixels to its right and the below.  Without limiting the range to one pixel less than the height and width, the loop would exceed their range when we search for the pixels to the right and below later in the function.   The absolute value of the difference ensures we work with a positive number.  For the images below, I chose to pass in a distance range value of 10 because anything higher resulted in a mostly white-washed result.

def imageProcessor(pic, dist_val):
  pic = betterBnW(pic)  # take a color picture and convert it to black and white
  for x in range(0, getWidth(pic) - 1):
    for y in range(0, getHeight(pic) - 1):
      pix = getPixel(pic, x, y)
      pix_below = getPixel(pic, x, (y + 1))
      pix_right = getPixel(pic, (x + 1), y)
      if abs(distance(getColor(pix), getColor(pix_below))) > dist_val and abs(distance(getColor(pix), getColor(pix_right))) > dist_val:
        setColor(pix, black)
      else:
        setColor(pix, white)
  repaint(pic)
  writePictureTo(pic, '/Users/lisabenson/Documents/CST205/Module3_Lab7/img_process.jpg')
  return pic

def betterBnW(pic):
  """makes an image grayscale with luminance formula R*0.299 + G*0.587 + B*0.114"""
  pixels = getPixels(pic)
  for pix in pixels:
    r = getRed(pix)
    g = getGreen(pix)
    b = getBlue(pix)
    luminance = r*0.299 + g*0.587 + b*0.114
    setRed(pix, luminance)
    setGreen(pix, luminance)
    setBlue(pix, luminance)
  return pic

Portrait taken on favorite holiday in Mürren, CHE, before and after:






No comments:

Post a Comment