Wednesday, March 30, 2016

Module 4

This week, we have begun to learn about and work with sound files, including the concepts of sampling, amplitude, and bit depth.  It's an interesting, complex application for Python, which I never before thought I would take on.  Overall, working with a variety of media has been a lot of fun -- and this is coming from someone who does not really consider themselves a creative -- and I think it's been a great medium for studying programming.

I've found the Github tutorial to be exciting, as well as the fact that my team will start pushing and pulling, etc., the code that we share.  It's a great protocol to know for working with a team, so we'll be getting a lot of practice using it and hopefully becoming more and more familiar with it.


Friday, March 25, 2016

Module 3 - Keeping up with my Learning Journal

Pair programming is more difficult for me than coding solo.  I appreciate that the driver is free to focus on tactical maneuvers when the navigator is observing strategy and prospective future issues, but it's difficult for me to 1) concentrate when working in front of others, 2) articulate what I am coding while I'm thinking it through, and 3) always interpret what others are writing, while they're doing so.  There's quite a lot of silent time, but that's OK.  I wonder if others share this perspective, find it a challenge, as well.  Of course, ultimately, it's helpful and worthwhile to have constructive, valuable feedback from the navigator.  Hopefully, with practice I will become more comfortable with this method of writing.

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:






Tuesday, March 15, 2016

Module 2

A funny thing about module two is when you digitally manipulate an image it's digitally manipulated.

Horizontal Mirroring can have an unexpected outcome.

What is that, am I swimming in a very reflective lake? If you turn it sideways it looks kinda like a happy gnome-like creature.

Tuesday, March 8, 2016

Python!

I'm currently finishing a Java data structures class and beginning a Python one, albeit one with Jython lessons, which gives me a nice opportunity to neatly juxtapose the two languages.

Studying JPG, GIF, TIFF, PNG, BMP and learning when to use each one was very useful.  It was interesting to read that JPG is the format of choice on the internet due to its excellent quality even at rather high compression settings.  It seems not to be lossless, or, rather, it is lossy, but it does discard information that the eye is least likely to notice.

Manipulating digitized image's pixels with code on JES was pretty fun.  I had only used software programs to do such in the past.  Thanks to CSUMB, I currently possess an Adobe Creative Cloud Membership, so I also took some time to explore the Photoshop app's tools and features for manipulating images, which was decidedly more difficult than writing similarly behaving code on JES!  I definitely preferred making my own methods!