Skip to content

Commit bbfcbfa

Browse files
committed
added findHorizontalSeam() to SeamCarverLib.py
1 parent c38fe50 commit bbfcbfa

File tree

3 files changed

+167
-23
lines changed

3 files changed

+167
-23
lines changed

ResizeDemo.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import argparse, png, array
2+
from readPNG_2 import Picture
3+
from SeamCarverLib import SeamCarver
4+
import SeamCarverUtilities
5+
6+
parser = argparse.ArgumentParser()
7+
parser.add_argument("filename", help="filename of image", type=str)
8+
parser.add_argument("rowsToRemove", help="number of rows to remove from image", type=int)
9+
parser.add_argument("colsToRemove", help="number of cols to remove from image", type=int)
10+
args = parser.parse_args()
11+
12+
print "build energy array for {}".format(args.filename)
13+
pic = Picture(args.filename)
14+
15+
print "build graph of pixels from energy array"
16+
sc = SeamCarver(pic)
17+
18+
#print pic.energyArray, '\nlen = ', len(pic.energyArray)
19+
20+
print "print vertical seam\n"
21+
SeamCarverUtilities.printVerticalSeam(sc)
22+
print "print horizontal seam\n"
23+
SeamCarverUtilities.printHorizontalSeam(sc)
24+
25+
26+
#print "remove {} rows".format(args.rowsToRemove)
27+
#print "remove {} cols".format(args.colsToRemove)
28+

SeamCarverLib.py

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,27 @@ def findVerticalSeam(self):
4848

4949
def findHorizontalSeam(self):
5050
"return horizontal seam in image"
51-
pass
51+
# tranpose dimensions
52+
self._exchDims()
53+
54+
# horizontal seam = sequence of rows; seam[0] is row of col 0
55+
# col-indexed seam
56+
seam = [-1 for _ in range(self._height)]
57+
self._buildGraph(transposed=True)
58+
row = self._height - 1
59+
v = self._edgeTo[self._sink]
60+
while (v != self._source):
61+
seam[row] = v % self._width # seam[row] = col
62+
v = self._edgeTo[v]
63+
row -= 1
64+
self._exchDims()
65+
return seam
66+
67+
def _exchDims(self):
68+
"exchange self._width and self._height"
69+
swap = self._width
70+
self._width = self._height
71+
self._height = swap
5272

5373
def _toLinear(self, col, row):
5474
"converts pixel from (col, row) to single index"
@@ -64,7 +84,7 @@ def _toGrid(self, num):
6484

6585
def _isValid(self, col, row=None):
6686
if row is None:
67-
if (col < 0) or (col > self._width * self._height):
87+
if (col < 0) or (col > self._width * self._height - 1):
6888
return False
6989
else:
7090
return True
@@ -74,7 +94,7 @@ def _isValid(self, col, row=None):
7494
else:
7595
return True
7696

77-
def _buildGraph(self):
97+
def _buildGraph(self, transposed=False):
7898
"pixels are nodes; edges define precedence constraints in a seam"
7999

80100
# for row 0 pixels: distTo[] is 0; edgeTo[] is _source vertex
@@ -89,45 +109,58 @@ def _buildGraph(self):
89109
for v in range(self._width, self._num_pixels):
90110
if (v % self._width == 0):
91111
# pixel is on left edge
92-
self._edgeTodistTo(v, edgeL=True)
112+
self._edgeTodistTo(v, transposed=transposed, edgeL=True)
93113
elif (v % self._width == self._width - 1):
94114
# pixel is on right edge
95-
self._edgeTodistTo(v, edgeR=True)
115+
self._edgeTodistTo(v, transposed=transposed, edgeR=True)
96116
else:
97-
self._edgeTodistTo(v)
117+
self._edgeTodistTo(v, transposed=transposed)
98118
# for sink vertex
99119
index, min_energy = min(enumerate(self._distTo[self._num_pixels - self._width:self._num_pixels]), key=lambda (x, y): y)
100120
self._distTo[self._sink] = min_energy
101-
self._edgeTo[self._sink] = (self._height-1) * self._width + index
121+
self._edgeTo[self._sink] = (self._height - 1) * self._width + index
102122

103123

104-
def _edgeTodistTo(self, v, edgeL=False, edgeR=False):
124+
def _edgeTodistTo(self, v, edgeL=False, edgeR=False, transposed=False):
105125
# returns pixel connected to v with min energy
126+
106127
if edgeL:
107128
# left edge
108129
vC = v - self._width
109-
vR = v - self._width + 1
110-
vL = vC
130+
vRD = v - self._width + 1
131+
vLU = vC
111132
elif edgeR:
112133
# right edge
113-
vL = v - self._width - 1
134+
vLU = v - self._width - 1
114135
vC = v - self._width
115-
vR = vC
136+
vRD = vC
116137
else:
117138
# pixels connect to v
118-
vL = v - self._width - 1
139+
vLU = v - self._width - 1
119140
vC = v - self._width
120-
vR = v - self._width + 1
141+
vRD = v - self._width + 1
121142
# energy of pixels connected to v
122-
eL = self._energy[vL]
123-
eC = self._energy[vC]
124-
eR = self._energy[vR]
125-
if eL <= min(eC, eR):
126-
self._edgeTo[v] = vL
127-
self._distTo[v] = self._distTo[vL] + eL
128-
elif eR <= min(eL, eC):
129-
self._edgeTo[v] = vR
130-
self._distTo[v] = self._distTo[vR] + eR
143+
if transposed:
144+
(colU, rowU) = self._toGrid(vLU)
145+
(colC, rowC) = self._toGrid(vC)
146+
(colD, rowD) = self._toGrid(vRD)
147+
# read energy
148+
eLU = self._energy[self._height * colU + rowU]
149+
eC = self._energy[self._height * colC + rowC]
150+
eRD = self._energy[self._height * colD + rowD]
151+
152+
else:
153+
# read energy directly from energy array
154+
eLU = self._energy[vLU]
155+
eC = self._energy[vC]
156+
eRD = self._energy[vRD]
157+
158+
if eLU <= min(eC, eRD):
159+
self._edgeTo[v] = vLU
160+
self._distTo[v] = self._distTo[vLU] + eLU
161+
elif eRD <= min(eLU, eC):
162+
self._edgeTo[v] = vRD
163+
self._distTo[v] = self._distTo[vRD] + eRD
131164
else:
132165
self._edgeTo[v] = vC
133166
self._distTo[v] = self._distTo[vC] + eC

readPNG_2.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import png, array
2+
3+
class Picture(object):
4+
"reads a png image from a filename"
5+
#_BORDER_ENERGY = 195075
6+
7+
def __init__(self, pngfilename):
8+
"reads in a .png image"
9+
_BORDER_ENERGY = 195075
10+
_CH = 3 # number of channels (R,G,B = 3; R,G,B,A = 4)
11+
_r = png.Reader(filename=pngfilename)
12+
res = _r.read()
13+
# res = (width, height, iterator-over-pixels,
14+
# {'alpha': False, 'bitdepth': 8, greyscale': True,
15+
# 'interlace': 0, 'planes': 1, size':(255, 1)})
16+
17+
self.num_cols = res[0]
18+
self.num_rows = res[1]
19+
20+
if res[3]['alpha']:
21+
_CH = 4
22+
23+
self.num_channels = _CH
24+
25+
self.energyArray = array.array("L")
26+
self.imageArray = array.array("B")
27+
28+
# row 0 of image
29+
_row_prev = res[2].next()
30+
self.energyArray.extend([_BORDER_ENERGY] * self.num_cols)
31+
self.imageArray.extend(_row_prev)
32+
33+
if (self.num_rows == 1):
34+
return
35+
36+
# row 1 of image
37+
_row_curr = res[2].next()
38+
self.imageArray.extend(_row_curr)
39+
if (self.num_rows == 2):
40+
self.energyArray.extend([_BORDER_ENERGY] * self.num_cols)
41+
return
42+
43+
# for images with more than 2 rows
44+
for _row_next in res[2]:
45+
"build image array and energy array"
46+
47+
# add _row_next to image array
48+
self.imageArray.extend(_row_next)
49+
50+
# calculate gradient of current row
51+
_gradRv = map(self._diff_squared, _row_prev[0::_CH], _row_next[0::_CH])
52+
_gradGv = map(self._diff_squared, _row_prev[1::_CH], _row_next[1::_CH])
53+
_gradBv = map(self._diff_squared, _row_prev[2::_CH], _row_next[2::_CH])
54+
n = self.num_cols * _CH
55+
_gradRh = map(self._diff_squared, _row_curr[0:(n - 2*_CH):_CH], _row_curr[2*_CH:(n - _CH)+1:_CH])
56+
_gradGh = map(self._diff_squared, _row_curr[1:(n - 2*_CH):_CH], _row_curr[2*_CH+1:(n - _CH)+2:_CH])
57+
_gradBh = map(self._diff_squared, _row_curr[2:(n - 2*_CH):_CH], _row_curr[2*_CH+2:(n - _CH)+3:_CH])
58+
59+
_gradR = map(int.__add__, _gradRv[1:-1], _gradRh)
60+
_gradG = map(int.__add__, _gradGv[1:-1], _gradGh)
61+
_gradB = map(int.__add__, _gradBv[1:-1], _gradBh)
62+
63+
# calculate energy of current row
64+
_energy = map(sum, zip(_gradR, _gradG, _gradB))
65+
66+
# left border pixel energy
67+
self.energyArray.append(_BORDER_ENERGY)
68+
# non-border pixel energy
69+
self.energyArray.extend(_energy)
70+
# right border pixel energy
71+
self.energyArray.append(_BORDER_ENERGY)
72+
73+
_row_prev = _row_curr
74+
_row_curr = _row_next
75+
76+
# bottom row of energy array
77+
print 'i am in Picture'
78+
self.energyArray.extend([_BORDER_ENERGY] * self.num_cols)
79+
80+
81+
def _diff_squared(self, x, y):
82+
return (x-y)**2
83+

0 commit comments

Comments
 (0)