Skip to content

Commit

Permalink
add bilinear resampling, closes ojii#8
Browse files Browse the repository at this point in the history
  • Loading branch information
craigds committed Jun 7, 2012
1 parent 83da4a3 commit ef86819
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 0 deletions.
46 changes: 46 additions & 0 deletions pymaging/resample.py
Expand Up @@ -49,3 +49,49 @@ def nearest(source, width, height, pixelsize):
lineextend(source.pixels[source_y][source_x_start:source_x_end])
pixelappend(line)
return pixels


def bilinear(source, width, height, pixelsize):
pixels = []

x_ratio = fdiv(source.width, width) # get the x-axis ratio
y_ratio = fdiv(source.height, height) # get the y-axis ratio

if x_ratio < 1 and y_ratio < 1:
if not (width % source.width) and not (height % source.height):
# optimisation: if doing a perfect upscale,
# can just use nearest neighbor (it's much faster)
return nearest(source, width, height, pixelsize)

y_range = range(height) # an iterator over the indices of all lines (y-axis)
x_range = range(width) # an iterator over the indices of all rows (x-axis)
for y in y_range:
src_y = (y + 0.5) * y_ratio - 0.5 # use the center of each pixel
src_y_i = int(src_y)

weight_y0 = 1 - (src_y - src_y_i)

line = array.array('B') # initialize a new line
for x in x_range:
src_x = (x + 0.5) * x_ratio - 0.5
src_x_i = int(src_x)

weight_x0 = 1 - (src_x - src_x_i)

channel_sums = [0.0] * pixelsize
for i, src_pixel in enumerate([
source.get_color(src_y_i, src_x_i),
source.get_color(src_y_i, src_x_i + 1),
source.get_color(src_y_i + 1, src_x_i),
source.get_color(src_y_i + 1, src_x_i + 1),
]):
src_pixel = src_pixel.to_pixel(pixelsize)
weight_x = (1 - weight_x0) if (i % 2) else weight_x0
weight_y = (1 - weight_y0) if (i // 2) else weight_y0
weight = weight_x * weight_y
for channel_index, channel_value in enumerate(src_pixel):
channel_sums[channel_index] += weight * channel_value

line.extend([int(round(s)) for s in channel_sums])
pixels.append(line)
return pixels
37 changes: 37 additions & 0 deletions pymaging/tests/test_resampling.py
Expand Up @@ -42,3 +42,40 @@ def test_resize_nearest_up(self):
[Blue, Blue, Green, Green],
[Blue, Blue, Green, Green],
])


class ResizeBilinearResamplingTests(PymagingBaseTestCase):
def test_resize_bilinear_down_simple(self):
img = image_factory([
[Red, Blue],
[Blue, Green],
])
img = img.resize(1, 1, resample_algorithm=bilinear)
self.assertImage(img, [
# all the colors blended equally
[Color(64, 32, 128, 255)]
])

def test_resize_bilinear_down_proportional(self):
img = image_factory([
[Red, Red, Blue],
[Red, Red, Blue],
[Blue, Blue, Blue],
])
img = img.resize(2, 2, resample_algorithm=bilinear)
self.assertImage(img, [
[Red, Color(64, 0, 191, 255)],
[Color(64, 0, 191, 255), Color(16, 0, 239, 255)],
])

# def test_resize_bilinear_down_transparent(self):
# img = image_factory([
# [Red, Blue],
# [Blue, Color(255, 255, 255, 0)],
# ])
# img = img.resize(1, 1, resample_algorithm=bilinear)
# self.assertImage(img, [
# # 3 colors blended equally,
# # but the transparent one should be ignored
# [Color(85, 0, 170, 255)]
# ])

0 comments on commit ef86819

Please sign in to comment.