diff --git a/ResizeDemo.py b/ResizeDemo.py index fa4032c..6ccab64 100644 --- a/ResizeDemo.py +++ b/ResizeDemo.py @@ -18,30 +18,30 @@ sc = SeamCarverLib.SeamCarver(pic) print "print vertical seam 1" -print sc.width(), sc.height() +print sc._width, sc._height #SeamCarverUtilities.printVerticalSeamEnergy(sc) -SeamCarverUtilities.printVerticalSeam(sc) +SeamCarverUtilities.printSeam(sc, direction="vertical") #SeamCarverUtilities.distToArray(sc) print "remove vertical seam" -s = sc.findVerticalSeam() +s = sc.findSeam(direction="vertical") sc.removeVerticalSeam(s) -print sc.width(), sc.height() +print sc._width, sc._height print "find vertical seam" -SeamCarverUtilities.printVerticalSeam(sc) +SeamCarverUtilities.printSeam(sc, direction="vertical") print "print horizontal seam" -SeamCarverUtilities.printHorizontalSeam(sc) +SeamCarverUtilities.printSeam(sc, direction="horizontal") #SeamCarverUtilities.distToArray(sc) #SeamCarverUtilities.printHorizontalSeamEnergy(sc) print "remove horizontal seam" -s = sc.findHorizontalSeam() +s = sc.findSeam(direction="horizontal") sc.removeHorizontalSeam(s) -print sc.width(), sc.height() +print sc._width, sc._height #SeamCarverUtilities.printHorizontalSeamEnergy(sc) print "find horizontal seam" -SeamCarverUtilities.printHorizontalSeam(sc) +SeamCarverUtilities.printSeam(sc, direction="horizontal") #SeamCarverUtilities.distToArray(sc) @@ -49,11 +49,11 @@ # sc.removeVerticalSeam(s) # # print "print vertical seam 2" -# print sc.width(), sc.height() +# print sc._width, sc._height # SeamCarverUtilities.printVerticalSeam(sc) # #SeamCarverUtilities.printVerticalSeamEnergy(sc) # # s = sc.findVerticalSeam() -# # for i in range(sc.height()): +# # for i in range(sc._height): # # print s[i] # # # print sc._edgeTo # # # print sc._distTo @@ -62,27 +62,27 @@ # s = sc.findVerticalSeam() # sc.removeVerticalSeam(s) -# print sc.width(), sc.height() +# print sc._width, sc._height # # print "print vertical seam 3" -# # print sc.width(), sc.height() +# # print sc._width, sc._height # SeamCarverUtilities.printVerticalSeam(sc) # SeamCarverUtilities.distToArray(sc) # #SeamCarverUtilities.printVerticalSeamEnergy(sc) # # s = sc.findVerticalSeam() -# # for i in range(sc.height()): +# # for i in range(sc._height): # # print s[i] # s = sc.findVerticalSeam() # sc.removeVerticalSeam(s) -# print sc.width(), sc.height() +# print sc._width, sc._height # # print "print vertical seam 4" -# # print sc.width(), sc.height() +# # print sc._width, sc._height # SeamCarverUtilities.printVerticalSeam(sc) #SeamCarverUtilities.printVerticalSeamEnergy(sc) # s = sc.findVerticalSeam() -# for i in range(sc.height()): +# for i in range(sc._height): # print s[i] # print "print vertical seam 2" @@ -90,14 +90,14 @@ # # print sc._distTo # s = sc.findVerticalSeam() # sc.removeVerticalSeam(s) -# print sc.height(), sc.width() +# print sc._height, sc._width #SeamCarverUtilities.printVerticalSeam(sc) # print # print "print vertical seam 3" # s = sc.findVerticalSeam() # sc.removeVerticalSeam(s) -# print sc.height(), sc.width() +# print sc._height, sc._width # # print sc._edgeTo # # print sc._distTo # #pdb.set_trace() @@ -107,7 +107,7 @@ # print "remove vertical seam 4" # s = sc.findVerticalSeam() # sc.removeVerticalSeam(s) -# print sc.height(), sc.width() +# print sc._height, sc._width # # print sc._edgeTo # # print sc._distTo # SeamCarverUtilities.printVerticalSeam(sc) @@ -115,7 +115,7 @@ # print "remove vertical seam 5" # s = sc.findVerticalSeam() # sc.removeVerticalSeam(s) -# print sc.height(), sc.width() +# print sc._height, sc._width # SeamCarverUtilities.printVerticalSeam(sc) diff --git a/SeamCarverLib.py b/SeamCarverLib.py index 2b265c4..493f300 100644 --- a/SeamCarverLib.py +++ b/SeamCarverLib.py @@ -6,7 +6,7 @@ import pdb class SeamCarver(object): - "removes seams from an image" + """removes seams from an image""" def __init__(self, picture): self._img = picture.imageArray self._height = picture.num_rows @@ -25,24 +25,21 @@ def __init__(self, picture): self._edgeTo = [] self._distTo = [] - - def width(self): - return self._width - - def height(self): - return self._height - def energy(self, col, row): - "return energy of pixel in (col, row)" + """return energy of pixel in (col, row)""" if self._isValid(col, row): return self._energy[self._toLinear(col, row)] + else: + print "invalid coordinates to energy: %s %s" % (col, row) - def findVerticalSeam(self, transposed=False): - "return vertical seam in image" + def findSeam(self, direction): + """return vertical seam in image""" # vertical seam = sequence of cols; seam[0] is col of row 0 - # row-indexed seam - seam = [-1 for _ in range(self._height)] - self._buildGraph(transposed) + # - row-indexed seam + # horizontal seam = sequence of rows; seam[0] is row of col 0 + # - col-indexed seam + seam = [-1] * self._height + self._buildGraph(direction) row = self._height - 1 v = self._edgeTo[self._sink] while (v != self._source): @@ -53,21 +50,8 @@ def findVerticalSeam(self, transposed=False): #self._distTo = [] return seam - def findHorizontalSeam(self, transposed=True): - "return horizontal seam in image" - # tranpose dimensions - self._exchDims() - - # horizontal seam = sequence of rows; seam[0] is row of col 0 - # col-indexed seam - seam = self.findVerticalSeam(transposed) - self._exchDims() - #self._edgeTo = [] - #self._distTo = [] - return seam - def _shiftImgUp(self, (col, row)): - "remove horizontal seam in img and energy array by shifting up each col" + """remove horizontal seam in img and energy array by shifting up each col""" for r in range(row, self._height - 1): i = self._width * r + col rchan_index = i*3 @@ -77,7 +61,7 @@ def _shiftImgUp(self, (col, row)): self._energy[i] = self._energy[i + self._width] def _removeSeam(self, seam): - "remove seam of pixels from image" + """remove seam of pixels from image""" # remove horizontal seam if(len(seam)) != self._width or self._width < 2: raise ValueError @@ -91,7 +75,7 @@ def _removeSeam(self, seam): def removeVerticalSeam(self, seam): - "remove vertical seam of pixels from image" + """remove vertical seam of pixels from image""" if (len(seam) != self._height or self._height == 0 or self._width == 2): raise ValueError indexes_to_remove = map(lambda (r, col): self._width * r + col, enumerate(seam)) @@ -128,7 +112,7 @@ def removeVerticalSeam(self, seam): self._sink = self._source + 1 def removeHorizontalSeam(self, seam): - "remove horizontal seam of pixels" + """remove horizontal seam of pixels""" self._removeSeam(seam) # update energy @@ -147,13 +131,13 @@ def removeHorizontalSeam(self, seam): def _onEdge(self, col, row): - "True if pixel is on left, top, or right edge" + """True if pixel is on left, top, or right edge""" return col == 0 or col == self._width - 1 or row == 0 def _updateEnergy(self, R_chan, resized_width): - '''re-calculate energy values for pixels on either side of seam + """re-calculate energy values for pixels on either side of seam - R_chan is a list of R channels''' + R_chan is a list of R channels""" for R in R_chan: # index = index of seam pixel wrt original image index = R / self._num_channels @@ -199,9 +183,9 @@ def _updateEnergy(self, R_chan, resized_width): self._energyGrad(resized_index - 1, resized_width) def _energyGrad(self, index, width): - '''Calculate energy of pixel in resized image. Update self._energy + """Calculate energy of pixel in resized image. Update self._energy - uses resized_index and resized_width''' + uses resized_index and resized_width""" left = (index - 1) * self._num_channels right = (index + 1) * self._num_channels @@ -230,19 +214,13 @@ def _energyGrad(self, index, width): def _diff_squared(self, x, y): return (x - y)**2 - def _exchDims(self): - "exchange self._width and self._height" - swap = self._width - self._width = self._height - self._height = swap - def _toLinear(self, col, row): - "converts pixel from (col, row) to single index" + """converts pixel from (col, row) to single index""" if self._isValid(col, row): return row * self._width + col def _toGrid(self, num): - "converts pixel from single index to (col, row)" + """converts pixel from single index to (col, row)""" if self._isValid(num): row = num / self._width col = num % self._width @@ -260,8 +238,8 @@ def _isValid(self, col, row=None): else: return True - def _buildGraph(self, transposed): - "pixels are nodes; edges define precedence constraints in a seam" + def _buildGraph(self, direction): + """pixels are nodes; edges define precedence constraints in a seam""" # graph data structures self._edgeTo = [_SENTINEL for _ in range(self._num_pixels + 2)] # add 2 for source, sink pixels self._distTo = [_INF for _ in range(self._num_pixels + 2)] @@ -276,14 +254,23 @@ def _buildGraph(self, transposed): # for each vertex (pixel), calculate edgeTo[], distTo[] # start at row 1 for v in range(self._width, self._num_pixels): - if (v % self._width == 0): - # pixel is on left edge - self._edgeTodistTo(v, transposed, edgeL=True) - elif (v % self._width == self._width - 1): - # pixel is on right edge - self._edgeTodistTo(v, transposed, edgeR=True) - else: - self._edgeTodistTo(v, transposed) + edges = [] + if v % self._width == 0: + edges.append('left') + if v % self._width == self._width - 1: + edges.append("right") + if v / self._width == 0: + edges.append("top") + if v / self._width == self._height - 1: + edges.append("bottom") + + if direction == "vertical" and "top" in edges: + continue + if direction == "horizontal" and "left" in edges: + continue + + self._edgeTodistTo(v, direction, edges) + # edgeTo[sink] is vertex in last row with min energy index, min_energy = min(enumerate(self._distTo[self._num_pixels - self._width:self._num_pixels]), key=lambda (x, y): y) self._distTo[self._sink] = min_energy @@ -291,44 +278,36 @@ def _buildGraph(self, transposed): - def _edgeTodistTo(self, v, transposed, edgeL=False, edgeR=False): + def _edgeTodistTo(self, pixel, direction, edges): # returns pixel connected to v with min energy - if edgeL: - # left edge - vC = v - self._width - vRD = v - self._width + 1 - vLU = vC - elif edgeR: - # right edge - vLU = v - self._width - 1 - vC = v - self._width - vRD = vC - else: - # pixels connect to v - vLU = v - self._width - 1 - vC = v - self._width - vRD = v - self._width + 1 - - # energy of pixels connected to v - if transposed: - (colU, rowU) = self._toGrid(vLU) - (colC, rowC) = self._toGrid(vC) - (colD, rowD) = self._toGrid(vRD) - # read energy - eLU = self._energy[self._height * colU + rowU] - eC = self._energy[self._height * colC + rowC] - eRD = self._energy[self._height * colD + rowD] - else: - # read energy directly from energy array - eLU = self._energy[vLU] - eC = self._energy[vC] - eRD = self._energy[vRD] - #print (eLU, vLU), (eC, vC), (eRD, vRD) + + if direction == "vertical": + ancestor_one = pixel - self._width - 1 + ancestor_two = pixel - self._width + ancestor_three = pixel - self._width + 1 + if 'left' in edges: + ancestor_one = ancestor_two + elif 'right' in edges: + ancestor_three = ancestor_two + + else: #horizontal + ancestor_one = pixel + self._width - 1 + ancestor_two = pixel - 1 + ancestor_three = pixel - self._width - 1 + if 'top' in edges: + ancestor_three = ancestor_two + elif 'bottom' in edges: + ancestor_one = ancestor_two + + eLU = self._energy[ancestor_one] + eC = self._energy[ancestor_two] + eRD = self._energy[ancestor_three] + #print (eLU, ancestor_one), (eC, ancestor_two), (eRD, ancestor_three) # find min distance and its associated vertex - dist, from_vertex = min((self._distTo[vLU] + eLU, vLU), (self._distTo[vC] + eC, vC), (self._distTo[vRD] + eRD, vRD)) - #e, vertex = min([(eC, vC), (eLU, vLU), (eRD, vRD)]) - self._edgeTo[v] = from_vertex - self._distTo[v] = dist + dist, from_vertex = min((self._distTo[ancestor_one] + eLU, ancestor_one), (self._distTo[ancestor_two] + eC, ancestor_two), (self._distTo[ancestor_three] + eRD, ancestor_three)) + #e, vertex = min([(eC, ancestor_two), (eLU, ancestor_one), (eRD, ancestor_three)]) + self._edgeTo[pixel] = from_vertex + self._distTo[pixel] = dist diff --git a/SeamCarverUtilities.py b/SeamCarverUtilities.py index a6c85f7..9837274 100644 --- a/SeamCarverUtilities.py +++ b/SeamCarverUtilities.py @@ -1,42 +1,27 @@ -def printVerticalSeam(sc): - "vertical seam is a list of cols" - seam = sc.findVerticalSeam() - totalSeamEnergy = 0 - for row in range(sc.height()): - for col in range(sc.width()): - lmarker = ' ' - rmarker = ' ' - if col == seam[row]: - lmarker = '[' - rmarker = ']' - totalSeamEnergy += sc.energy(col, row) +def printSeam(sc, direction): + """vertical seam is a list of cols""" + seam = sc.findSeam(direction) + + for row in range(sc._height): + for col in range(sc._width): + if direction == "vertical": + is_on_seam = col == seam[row] + else: + is_on_seam = row == seam[col] + lmarker, rmarker = ('[', ']') if is_on_seam else (' ',' ') print '{:s}{:>6d}{:s}'.format(lmarker, sc.energy(col, row), rmarker), print - print "\nTotal seam energy: {:d}".format(totalSeamEnergy) + totalSeamEnergy = calculateSeamEnergy(sc, direction) + print "\nTotal seam energy: {:d}".format(totalSeamEnergy) -def printHorizontalSeam(sc): - "horizontal seam is a list of rows" - seam = sc.findHorizontalSeam() - totalSeamEnergy = 0 - for row in range(sc.height()): - for col in range(sc.width()): - lmarker = ' ' - rmarker = ' ' - if row == seam[col]: - lmarker = '[' - rmarker = ']' - totalSeamEnergy += sc.energy(col, row) - print '{:s}{:>6d}{:s}'.format(lmarker, sc.energy(col, row), rmarker), - print - print "\nTotal seam energy: {:d}".format(totalSeamEnergy) +def calculateSeamEnergy(sc, direction): + seam = sc.findSeam(direction) -def printVerticalSeamEnergy(sc): - "vertical seam is a list of cols" - seam = sc.findVerticalSeam() - totalSeamEnergy = 0 - for row in range(sc.height()): - for col in range(sc.width()): - if col == seam[row]: - totalSeamEnergy += sc.energy(col, row) - print "\nTotal seam energy: {:d}".format(totalSeamEnergy) \ No newline at end of file + if direction == "vertical": + seam_indices = zip(seam, range(sc._height)) + else: + seam_indices = zip(range(sc._width), seam) + totalSeamEnergy = sum(sc.energy(col, row) for col, row in seam_indices) + print "\nTotal seam energy: {:d}".format(totalSeamEnergy) + return totalSeamEnergy diff --git a/readPNG_2.py b/readPNG_2.py index d2dd381..26daabe 100644 --- a/readPNG_2.py +++ b/readPNG_2.py @@ -2,13 +2,13 @@ class Picture(object): - "reads a png image from a filename" + """reads a png image from a filename""" #BORDER_ENERGY = 195075 BORDER_ENERGY = 195705 def __init__(self, pngfilename): - "reads in a .png image" + """reads in a .png image""" _CH = 3 # number of channels (R,G,B = 3; R,G,B,A = 4) _r = png.Reader(filename=pngfilename) res = _r.read() @@ -44,7 +44,7 @@ def __init__(self, pngfilename): # for images with more than 2 rows for _row_next in res[2]: - "build image array and energy array" + #build image array and energy array # add _row_next to image array self.imageArray.extend(_row_next)