Quantcast
Channel: 懒得折腾
Viewing all articles
Browse latest Browse all 764

Computational Photography Programming Assignment 1

$
0
0

part0.py

import sys
import os
import numpy as np
import random
import cv2
import run

def convolve(image, kernel):
  '''Convolve the given image and kernel

  Inputs:

  image - a single channel (rows, cols) image with dtype uint8

  kernel - a matrix of shape (d, d) and dtype float

  Outputs:

  output - an output array of the same dtype as image, and of shape
  (rows - d + 1, cols - d + 1)
 
  Every element of output should contain the application of the kernel to the
  corresponding location in the image.

  Output elements that result in values that are greater than 255 should be 
  cropped to 255, and output values less than 0 should be set to 0.
  '''
  output = None
  # Insert your code here.----------------------------------------------------
  (rows, cols) = image.shape
  (drows, dcols) = kernel.shape
  d = 0
  if drows != dcols:
    raise ValueError('The kernel must be a square')
  else:
    d = drows
  if (d % 2 != 1):
    raise ValueError('The kernel size must be a odd number')
  k = (d - 1)/2
  output = np.zeros((rows - d + 1, cols - d + 1), dtype = np.uint8)
  for i in range(rows - d + 1):
    for j in range(cols - d + 1):
      result = 0
      for u in range(-k, k + 1):
        for v in range(-k, k + 1):
          result = result + kernel[u + k, v + k] * image[i - u + k, j - v + k]
      if (result < 0):
          result = 0
      if (result > 255):
          result = 255
      output[i, j] = result
  #---------------------------------------------------------------------------
  return output 

def test():
  '''This script will perform a unit test on your function, and provide useful
  output.
  '''
  images = []
  kernels = []
  outputs = []

  x = np.zeros((9,9), dtype = np.uint8)
  x[4,4] = 255 
  images.append(x)

  x = np.zeros((5,5), dtype = np.uint8)
  x[2,2] = 255 
  images.append(x)

  y = np.array(
      [[-0.9,-0.7, 0.5, 0.3, 0.0],
       [-0.7, 0.5, 0.3, 0.0, 0.4],
       [ 0.5, 0.1, 0.0, 0.4, 0.6],
       [ 0.1, 0.0, 0.2, 0.6, 0.8],
       [ 0.0, 0.2, 0.6, 0.8, 1.2]])
  kernels.append(y)

  y = np.array(
      [[0.1, 0.1, 0.1],
       [0.1, 0.2, 0.1],
       [0.1, 0.1, 0.1]])
  kernels.append(y)

  z = np.array(
      [[   0,   0, 127,  76,   0],
       [   0, 127,  76,   0, 102],
       [ 127,  25,   0, 102, 153],
       [  25,   0,  51, 153, 204],
       [   0,  51, 153, 204, 255]], dtype = np.uint8)
  outputs.append(z)

  z = np.array(
      [[ 25,  25,  25],
       [ 25,  51,  25],
       [ 25,  25,  25]], dtype = np.uint8)
  outputs.append(z)

  for image, kernel, output in zip(images, kernels, outputs):
    if __name__ == "__main__":
      print "image:\n{}".format(image)
      print "kernel:\n{}".format(kernel)

    usr_out = convolve(image, kernel)

    if not type(usr_out) == type(output):
      if __name__ == "__main__":
        print "Error- output has type {}. Expected type is {}.".format(
            type(usr_out), type(output))
      return False

    if not usr_out.shape == output.shape:
      if __name__ == "__main__":
        print "Error- output has shape {}. Expected shape is {}.".format(
            usr_out.shape, output.shape)
      return False

    if not usr_out.dtype == output.dtype:
      if __name__ == "__main__":
        print "Error- output has dtype {}. Expected dtype is {}.".format(
            usr_out.dtype, output.dtype)
      return False

    if not np.all(usr_out == output):
      if __name__ == "__main__":
        print "Error- output has value:\n{}\nExpected value:\n{}".format(
            usr_out, output)
      return False
    if __name__ == "__main__":
      print "Passed."

  if __name__ == "__main__":
    print "Success."
  return True

if __name__ == "__main__":
  # Testing code
  print "Performing unit test."
  test()

part1.py

import sys
import os
import numpy as np
from scipy import signal
import math
import random
import cv2
import run

def make_gaussian(k, std):
  '''Create a gaussian kernel.
  
  Input:

  k - the radius of the kernel.
  
  std - the standard deviation of the kernel.
  
  Output:

  output - a numpy array of shape (2k+1, 2k+1) and dtype float.
  
  If gaussian_1d is a gaussian filter of length 2k+1 in one dimension, 
  kernel[i,j] should be filled with the product of gaussian_1d[i] and 
  gaussian_1d[j].
 
  Once all the points are filled, the kernel should be scaled so that the sum
  of all cells is equal to one.'''
  kernel = None
  # Insert your code here.----------------------------------------------------
  kernel = np.zeros((2 * k + 1, 2 * k + 1), dtype = np.float)
  #---------------------------------------------------------------------------
  gaussian_1d = np.zeros((2 * k + 1), dtype = np.float)
  for i in range(-k, k + 1):
    gaussian_1d[i + k] = math.exp(-0.5*i*i/(std*std))
  total = 0
  for u in range(-k, k + 1):
    for v in range(-k, k + 1):
      kernel[u + k, v + k] = gaussian_1d[u + k] * gaussian_1d[v + k]  #math.exp(-(u*u + v*v)/(std*std))/(2*math.pi*std*std)
      total = total + kernel[u + k, v + k]
  for u in range(-k, k + 1):
    for v in range(-k, k + 1):
      kernel[u + k, v + k] = kernel[u + k, v + k]/total
  return kernel

def test():
  '''This script will perform a unit test on your function, and provide useful
  output.
  '''

  np.set_printoptions(precision=3)

  ks =  [1, 2, 1, 2, 1]
  sds = [1, 2, 3, 4, 5]
  outputs = []
  # 1,1
  y = np.array([[ 0.075,  0.124,  0.075],
             [ 0.124,  0.204,  0.124],
             [ 0.075,  0.124,  0.075]])
  outputs.append(y)
  # 2,2
  y = np.array([[ 0.023,  0.034,  0.038,  0.034,  0.023],
             [ 0.034,  0.049,  0.056,  0.049,  0.034],
             [ 0.038,  0.056,  0.063,  0.056,  0.038],
             [ 0.034,  0.049,  0.056,  0.049,  0.034],
             [ 0.023,  0.034,  0.038,  0.034,  0.023]])
  outputs.append(y)
  # 1,3
  y = np.array([[ 0.107,  0.113,  0.107],
             [ 0.113,  0.120,  0.113],
             [ 0.107,  0.113,  0.107]])
  outputs.append(y)
  # 2,4
  y = np.array([[ 0.035,  0.039,  0.04 ,  0.039,  0.035],
             [ 0.039,  0.042,  0.044,  0.042,  0.039],
             [ 0.04 ,  0.044,  0.045,  0.044,  0.04 ],
             [ 0.039,  0.042,  0.044,  0.042,  0.039],
             [ 0.035,  0.039,  0.04 ,  0.039,  0.035]])
  outputs.append(y)
  # 1,5
  y = np.array([[ 0.11 ,  0.112,  0.11 ],
             [ 0.112,  0.114,  0.112],
             [ 0.11 ,  0.112,  0.11 ]])
  outputs.append(y)

  for k, sd, output in zip(ks, sds, outputs):
    if __name__ == "__main__":
      print "k:{}, sd:{}".format(k, sd)

    usr_out = make_gaussian(k, sd)

    if not type(usr_out) == type(output):
      if __name__ == "__main__":
        print "Error- output has type {}. Expected type is {}.".format(
            type(usr_out), type(output))
      return False

    if not usr_out.shape == output.shape:
      if __name__ == "__main__":
        print "Error- output has shape {}. Expected shape is {}.".format(
            usr_out.shape, output.shape)
      return False

    if not usr_out.dtype == output.dtype:
      if __name__ == "__main__":
        print "Error- output has dtype {}. Expected dtype is {}.".format(
            usr_out.dtype, output.dtype)
      return False

    if not np.all(np.abs(usr_out - output) < .005):
      if __name__ == "__main__":
        print "Error- output has value:\n{}\nExpected value:\n{}".format(
            usr_out, output)
      return False

    if __name__ == "__main__":
      print "Passed."

  if __name__ == "__main__":
    print "Success."
  return True

if __name__ == "__main__":
  # Testing code
  print "Performing unit test. Tests will be accepted if they are within .005 \
of the correct answer."
  test()

part2.py

import sys
import os
import numpy as np
from scipy.stats import norm
import math
import random
import cv2
import run

def make_sharp(k, sd):
  '''Create a sharpen kernel.
  
  Input:

  k - the radius of the kernel.
  sd - the standard deviation of the gaussian filter used to make the kernel.
  
  Output:

  output - a numpy array of shape (2k+1, 2k+1) and dtype float.
  
  The sharpen filter is constructed by first taking a filter with a 2 in the
  center and 0's everywhere else, and subtracting from that a gaussian filter.
  
  Note:

  You can use the make_gaussian function from part one by typing:

  import part1
  part1.make_gaussian(k, sd)
  '''
  kernel = None
  # Insert your code here.----------------------------------------------------
  kernel = np.zeros((2 * k + 1, 2 * k + 1), dtype = np.float)
  kernel[k, k] = 2
  import part1
  kernel = kernel - part1.make_gaussian(k, sd)    
  #---------------------------------------------------------------------------
  return kernel

def test():
  '''This script will perform a unit test on your function, and provide useful
  output.
  '''

  np.set_printoptions(precision=3)

  ks =  [1, 2, 1, 2, 1]
  sds = [1, 2, 3, 4, 5]
  outputs = []
  # 1,1
  y = np.array([[-0.075, -0.124, -0.075],
                [-0.124,  1.796, -0.124],
                [-0.075, -0.124, -0.075]])
  outputs.append(y)
  # 2,2
  y = np.array([[-0.023, -0.034, -0.038, -0.034, -0.023],
                [-0.034, -0.049, -0.056, -0.049, -0.034],
                [-0.038, -0.056,  1.937, -0.056, -0.038],
                [-0.034, -0.049, -0.056, -0.049, -0.034],
                [-0.023, -0.034, -0.038, -0.034, -0.023]])
  outputs.append(y)
  # 1,3
  y = np.array([[-0.107, -0.113, -0.107],
                [-0.113,  1.880, -0.113],
                [-0.107, -0.113, -0.107]])
  outputs.append(y)
  # 2,4
  y = np.array([[-0.035, -0.039, -0.04 , -0.039, -0.035],
                [-0.039, -0.042, -0.044, -0.042, -0.039],
                [-0.04 , -0.044,  1.955, -0.044, -0.04 ],
                [-0.039, -0.042, -0.044, -0.042, -0.039],
                [-0.035, -0.039, -0.04 , -0.039, -0.035]])
  outputs.append(y)
  # 1,5
  y = np.array([[-0.11 , -0.112, -0.11 ],
                [-0.112,  1.886, -0.112],
                [-0.11 , -0.112, -0.11 ]])
  outputs.append(y)

  for k, sd, output in zip(ks, sds, outputs):
    if __name__ == "__main__":
      print "k:{}, sd:{}".format(k, sd)

    usr_out = make_sharp(k, sd)

    if not type(usr_out) == type(output):
      if __name__ == "__main__":
        print "Error- output has type {}. Expected type is {}.".format(
            type(usr_out), type(output))
      return False

    if not usr_out.shape == output.shape:
      if __name__ == "__main__":
        print "Error- output has shape {}. Expected shape is {}.".format(
            usr_out.shape, output.shape)
      return False

    if not usr_out.dtype == output.dtype:
      if __name__ == "__main__":
        print "Error- output has dtype {}. Expected dtype is {}.".format(
            usr_out.dtype, output.dtype)
      return False

    if not np.all(np.abs(usr_out - output) < .005):
      if __name__ == "__main__":
        print "Error- output has value:\n{}\nExpected value:\n{}".format(
            usr_out, output)
      return False

    if __name__ == "__main__":
      print "Passed."

  if __name__ == "__main__":
    print "Success."
  return True

if __name__ == "__main__":
  # Testing code
  print "Performing unit test. Answers will be accepted as long as they are \
within .005 of the input."
  test()

import sys
import os
import numpy as np
from scipy.stats import norm
import math
import random
import cv2
import run

def filter_median(image, k):
  '''Filter the image using a median kernel.
  
  Inputs:

  image - a single channel image of shape (rows, cols)

  k - the radius of the neighborhood you should use (positive integer)

  Output:

  output - a numpy array of shape (rows - 2k, cols - 2k) and the same dtype as 
  image.
  
  Each cell in the output image should be filled with the median value of the
  corresponding (2k+1, 2k+1) patch in the image.
  '''
  output = None
  # Insert your code here.----------------------------------------------------
  (rows, cols) = image.shape
  if (k <= 0):
    raise ValueError('The k must be a postive integer') 
  output = np.zeros((rows - 2*k, cols - 2*k), dtype = image.dtype)
  for i in range(rows - 2*k):
    for j in range(cols - 2*k):
      patch = np.zeros((2*k + 1, 2*k + 1), dtype = image.dtype)
      for u in range(2*k + 1):
        for v in range(2*k + 1):
          patch[u, v] = image[i + u, j + v]
      output[i, j] = np.median(patch)
  #---------------------------------------------------------------------------
  return output 

def test():
  '''This script will perform a unit test on your function, and provide useful
  output.
  '''
  images = []
  x = np.array([[   0,   1,   2,   3,   4],
                [   5,   6,   7,   8,   9],
                [  10,  11,  12,  13,  14],
                [  15,  16,  17,  18,  19],
                [  20,  21,  22,  23,  24]], dtype = np.uint8)
  images.append(x)
  images.append(x)

  x = np.array([[ 0,  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]], dtype = np.uint8)
  images.append(x)
  images.append(x)

  ks = [1, 2, 1, 2]
  outputs = []

  z = np.array([[ 6,  7,  8],
                [11, 12, 13],
                [16, 17, 18]], dtype=np.uint8)
  outputs.append(z)

  z = np.array([[12]], dtype=np.uint8)
  outputs.append(z)

  z = np.array([[ 8,  9, 10, 11, 12],
                [15, 16, 17, 18, 19],
                [22, 23, 24, 25, 26],
                [29, 30, 31, 32, 33],
                [36, 37, 38, 39, 40]], dtype=np.uint8)
  outputs.append(z)

  z = np.array([[16, 17, 18],
                [23, 24, 25],
                [30, 31, 32]], dtype=np.uint8)
  outputs.append(z)

  for image, k, output in zip(images, ks, outputs):
    if __name__ == "__main__":
      print "image:\n{}".format(image)
      print "k:\n{}".format(k)

    usr_out = filter_median(image, k)

    if not type(usr_out) == type(output):
      if __name__ == "__main__":
        print "Error- output has type {}. Expected type is {}.".format(
            type(usr_out), type(output))
      return False

    if not usr_out.shape == output.shape:
      if __name__ == "__main__":
        print "Error- output has shape {}. Expected shape is {}.".format(
            usr_out.shape, output.shape)
      return False

    if not usr_out.dtype == output.dtype:
      if __name__ == "__main__":
        print "Error- output has dtype {}. Expected dtype is {}.".format(
            usr_out.dtype, output.dtype)
      return False

    if not np.all(usr_out == output):
      if __name__ == "__main__":
        print "Error- output has value:\n{}\nExpected value:\n{}".format(
            usr_out, output)
      return False

    if __name__ == "__main__":
      print "Passed."

  if __name__ == "__main__":
    print "Success."
  return True

if __name__ == "__main__":
  # Testing code
  print "Performing unit test."
  test()

import sys
import os
import numpy as np
import cv2
from scipy.signal import convolve2d
from scipy.ndimage.filters import gaussian_filter
import math

import part0
import part1
import part2
import part3
import run

def sobel_filter_x():
  '''Return a 3x3 sobel filter in the x direction.
  '''
  return np.array([[-1, 0, 1],
                   [-2, 0, 2],
                   [-1, 0, 1]])

def sobel_filter_y():
  '''Return a 3x3 sobel filter in the y direction.
  '''
  return np.array([[-1,-2,-1],
                   [ 0, 0, 0],
                   [ 1, 2, 1]])

def transform_xy_theta(dx, dy):
  '''Transform from xy gradients to edge direction.
  
  Input:

  dx, dy - the gradient images generated by applying sobel filters to an
  image. They both have shape (rows, cols) and dtype float.

  Output:

  theta - a numpy array of shape (rows, cols) and dtype float.
  
  Each location theta[i,j] should contain the inverse tangent of dy[i,j]/dx[i,j]
  , in the range of [-pi/2, pi/2] radiants.

  Hint: you may find the np.arctan function useful here.
  '''
  
  # To avoid dividing by zero, set dy to a small value in locations where it
  # is zero.
  dx[dx == 0] = 0.001

  theta = None
  
  # Insert your code here -------------------------------------------------------

  #------------------------------------------------------------------------------
  (rowsx, colsx) = dx.shape
  (rowsy, colsy) = dy.shape
  if (rowsx != rowsy or colsx != colsy):
    raise ValueError('dx and dy must have the same size.')
  theta = np.zeros((rowsx, colsx), dtype = np.float)
  for i in range(rowsx):
    for j in range(colsx):
      theta[i, j] = np.arctan(dy[i,j]/dx[i,j])
  return theta

def transform_xy_mag(dx, dy):
  '''Transform from xy gradients to edge direction.
  
  Input:

  dx, dy - the gradient images generated by applying sobel filters to an
  image. They both have shape (rows, cols) and dtype float.

  Output:

  mag - a numpy array of shape (rows, cols) and dtype float.
  
  Each location mag[i,j] should contain the magnitude of the gradient, which
  is sqrt(dx[i,j]^2 + dy[i,j]^2)

  Hint: you may find the np.sqrt and np.square funcitons useful here.
  '''
  
  mag = None
  
  # Insert your code here -------------------------------------------------------

  #------------------------------------------------------------------------------
  (rowsx, colsx) = dx.shape
  (rowsy, colsy) = dy.shape
  if (rowsx != rowsy or colsx != colsy):
    raise ValueError('dx and dy must have the same size.')
  mag = np.zeros((rowsx, colsx), dtype = np.float)
  for i in range(rowsx):
    for j in range(colsx):
      mag[i, j] = math.sqrt(dx[i,j]*dx[i,j] + dy[i,j]*dy[i,j])
  return mag

def get_color(theta, mag):
  '''Return the color for a given edge theta and magnitude.

  Given the local edge orientation and magnitude, return the corresponding
  color. The intensity of the color is given by the magnitude (stronger edges
  are brighter)
  '''

  boundaries = np.array([0.375, 0.125, -0.125, -0.375]) * math.pi

  # crop the magnitude to 0, 255 range.
  if mag < 0:
    mag = 0

  if mag > 255:
    mag = 255

  # (vertical) | yellow
  if theta > boundaries[0] or theta < boundaries[3] :
    return (0, mag, mag)
  
  # \ green
  if theta >= boundaries[3] and theta < boundaries[2] :
    return (0, mag, 0)

  # -- blue
  if theta >= boundaries[2] and theta < boundaries[1] :
    return (mag, 0, 0)
  
  # / red
  if theta >= boundaries[1] and theta < boundaries[0] :
    return (0, 0, mag)

def run_edges(image):
  ''' This function finds and colors all edges in the given image.
  '''

  # Convert image to gray
  if len(image.shape) > 2:
    grayimage = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  else:
    grayimage = image

  # blur so the gradient operation is less noisy.
  # uses a gaussian filter with sigma = 2
  grayimage = gaussian_filter(grayimage, 2).astype(float)
  
  # Filter with x and y sobel filters
  dx = convolve2d(grayimage, sobel_filter_x())
  dy = convolve2d(grayimage, sobel_filter_y())
  
  # Convert to orientation and magnitude images
  theta = transform_xy_theta(dx, dy)
  mag = transform_xy_mag(dx, dy)

  outimg = np.zeros((image.shape[0], image.shape[1], 3), dtype = np.uint8)

  # Fill with corresponding color.
  for r in range(outimg.shape[0]):
    for c in range(outimg.shape[1]):
      outimg[r,c,:] = get_color(theta[r,c], mag[r,c])

  return outimg

def test():
  '''This script will perform a unit test on your function, and provide useful
  output.
  '''

  dxs = []
  dys = []
  thetas = []
  mags = []

  y = np.array([[ 0, 1],
                [-1, 0]], dtype = float)
  dys.append(y)

  x = np.array([[ 1, 0],
                [ 0,-1]], dtype = float)
  dxs.append(x)
  
  theta = np.array([[ 0.  ,  math.pi/2],
                    [-math.pi/2,  0.  ]], dtype = float)
  thetas.append(theta)

  mag = np.array([[ 1, 1],
                  [ 1, 1]], dtype = float)
  mags.append(mag)

  y = np.array([[ 0, 0, 0],
                [ 1, 1, 1],
                [-1,-1,-1]], dtype = float)
  dys.append(y)

  x = np.array([[ 0, 1,-1],
                [ 0, 1,-1],
                [ 0, 1,-1]], dtype = float)
  dxs.append(x)
  
  theta = np.array([[         0,          0,          0],
                    [ math.pi/2,  math.pi/4, -math.pi/4],
                    [-math.pi/2, -math.pi/4,  math.pi/4]], dtype = float)
  thetas.append(theta)

  mag= np.array([[ 0,     1,     1],
                 [ 1, 1.414, 1.414],
                 [ 1, 1.414, 1.414]], dtype = float)
  mags.append(mag)

  for dx, dy, theta, mag in zip(dxs, dys, thetas, mags):
    if __name__ == "__main__":
      print "dx:\n{}\n, dy:\n{}\n".format(dx, dy)

    usr_theta = transform_xy_theta(dx, dy)
    usr_mag = transform_xy_mag(dx, dy)

    for usr_out, true_out, name in zip((usr_theta, usr_mag), (theta, mag), ('theta', 'mag')):
      if not type(usr_out) == type(true_out):
        if __name__ == "__main__":
          print "Error- {} has type {}. Expected type is {}.".format(
              name, type(usr_out), type(true_out))
        return False

      if not usr_out.shape == true_out.shape:
        if __name__ == "__main__":
          print "Error- {} has shape {}. Expected shape is {}.".format(
              name, usr_out.shape, true_out.shape)
        return False

      if not usr_out.dtype == true_out.dtype:
        if __name__ == "__main__":
          print "Error- {} has dtype {}. Expected dtype is {}.".format(
              name, usr_out.dtype, true_out.dtype)
        return False

      if not np.all(np.abs(usr_out - true_out) < .05):
        if __name__ == "__main__":
          print "Error- {} has value:\n{}\nExpected value:\n{}".format(
              name, usr_out, true_out)
        return False

      if __name__ == "__main__":
        print "{} passed.".format(name)

  if __name__ == "__main__":
    print "Success."
  return True

if __name__ == "__main__":
  print "Performing unit tests. Your functions will be accepted if your result is\
within 0.05 of the correct output."
  np.set_printoptions(precision=3)
  if not test():
    print "Unit test failed. Halting"
    sys.exit() 

  sourcefolder = os.path.abspath(os.path.join(os.curdir, 'images', 'source'))
  outfolder = os.path.abspath(os.path.join(os.curdir, 'images', 'filtered'))

  print 'Searching for images in {} folder'.format(sourcefolder)

  # Extensions recognized by opencv
  exts = ['.bmp', '.pbm', '.pgm', '.ppm', '.sr', '.ras', '.jpeg', '.jpg', 
    '.jpe', '.jp2', '.tiff', '.tif', '.png']

  # For every image in the source directory
  for dirname, dirnames, filenames in os.walk(sourcefolder):
    for filename in filenames:
      name, ext = os.path.splitext(filename)
      if ext in exts:
        print "Reading image {}.".format(filename)
        img = cv2.imread(os.path.join(dirname, filename))

        print "Applying edges."
        outimg = run_edges(img)
        outpath = os.path.join(outfolder, name + 'edges' + ext)

        print "Writing image {}.".format(outpath)
        cv2.imwrite(outpath, outimg)



Viewing all articles
Browse latest Browse all 764

Trending Articles