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)