From 1eed17c70e4a37039e30c78dfb472af7bc47c667 Mon Sep 17 00:00:00 2001 From: tsennott Date: Sun, 8 Jul 2018 20:09:39 -0700 Subject: [PATCH] tightened up colorize(); split tests; moved tuple comparison fcn to helper.py --- Tests/helper.py | 9 ++++ Tests/test_imageops.py | 109 ++++++++++++++++++++++------------------- src/PIL/ImageOps.py | 47 ++++++------------ 3 files changed, 83 insertions(+), 82 deletions(-) diff --git a/Tests/helper.py b/Tests/helper.py index 207f497d2..834589723 100644 --- a/Tests/helper.py +++ b/Tests/helper.py @@ -307,6 +307,15 @@ def hopper(mode=None, cache={}): return im.copy() +def tuple_approx_equal(actual, target, threshold): + """Tests if tuple actual has values within threshold from tuple target""" + + value = True + for i, target in enumerate(target): + value *= (target - threshold <= actual[i] <= target + threshold) + return value + + def command_succeeds(cmd): """ Runs the command, which must be a list of strings. Returns True if the diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index d1be04046..07e4dd343 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -1,4 +1,4 @@ -from helper import unittest, PillowTestCase, hopper +from helper import unittest, PillowTestCase, hopper, tuple_approx_equal from PIL import ImageOps from PIL import Image @@ -95,87 +95,94 @@ class TestImageOps(PillowTestCase): newimg = ImageOps.scale(i, 0.5) self.assertEqual(newimg.size, (25, 25)) - def test_colorize(self): - # Test the colorizing function + def test_colorize_2color(self): + # Test the colorizing function with 2-color functionality # Open test image (256px by 10px, black to white) im = Image.open("Tests/images/bw_gradient.png") im = im.convert("L") # Create image with original 2-color functionality - im_2c = ImageOps.colorize(im, 'red', 'green') - - # Create image with original 2-color functionality with offsets - im_2c_offset = ImageOps.colorize(im, - black='red', - white='green', - blackpoint=50, - whitepoint=200) - - # Create image with new three color functionality with offsets - im_3c_offset = ImageOps.colorize(im, - black='red', - white='green', - mid='blue', - blackpoint=50, - whitepoint=200, - midpoint=100) - - # Define function for approximate equality of tuples - def tuple_approx_equal(actual, target, thresh): - value = True - for i, target in enumerate(target): - value *= (target - thresh <= actual[i] <= target + thresh) - return value + im_test = ImageOps.colorize(im, 'red', 'green') # Test output image (2-color) left = (0, 1) middle = (127, 1) right = (255, 1) - self.assertTrue(tuple_approx_equal(im_2c.getpixel(left), - (255, 0, 0), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(left), + (255, 0, 0), threshold=1), '2-color image black incorrect') - self.assertTrue(tuple_approx_equal(im_2c.getpixel(middle), - (127, 63, 0), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(middle), + (127, 63, 0), threshold=1), '2-color image mid incorrect') - self.assertTrue(tuple_approx_equal(im_2c.getpixel(right), - (0, 127, 0), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(right), + (0, 127, 0), threshold=1), '2-color image white incorrect') + def test_colorize_2color_offset(self): + # Test the colorizing function with 2-color functionality and offset + + # Open test image (256px by 10px, black to white) + im = Image.open("Tests/images/bw_gradient.png") + im = im.convert("L") + + # Create image with original 2-color functionality with offsets + im_test = ImageOps.colorize(im, + black='red', + white='green', + blackpoint=50, + whitepoint=100) + # Test output image (2-color) with offsets left = (25, 1) - middle = (125, 1) - right = (225, 1) - self.assertTrue(tuple_approx_equal(im_2c_offset.getpixel(left), - (255, 0, 0), thresh=1), + middle = (75, 1) + right = (125, 1) + self.assertTrue(tuple_approx_equal(im_test.getpixel(left), + (255, 0, 0), threshold=1), '2-color image (with offset) black incorrect') - self.assertTrue(tuple_approx_equal(im_2c_offset.getpixel(middle), - (127, 63, 0), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(middle), + (127, 63, 0), threshold=1), '2-color image (with offset) mid incorrect') - self.assertTrue(tuple_approx_equal(im_2c_offset.getpixel(right), - (0, 127, 0), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(right), + (0, 127, 0), threshold=1), '2-color image (with offset) white incorrect') + def test_colorize_3color_offset(self): + # Test the colorizing function with 3-color functionality and offset + + # Open test image (256px by 10px, black to white) + im = Image.open("Tests/images/bw_gradient.png") + im = im.convert("L") + + # Create image with new three color functionality with offsets + im_test = ImageOps.colorize(im, + black='red', + white='green', + mid='blue', + blackpoint=50, + whitepoint=200, + midpoint=100) + # Test output image (3-color) with offsets left = (25, 1) left_middle = (75, 1) middle = (100, 1) right_middle = (150, 1) right = (225, 1) - self.assertTrue(tuple_approx_equal(im_3c_offset.getpixel(left), - (255, 0, 0), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(left), + (255, 0, 0), threshold=1), '3-color image (with offset) black incorrect') - self.assertTrue(tuple_approx_equal(im_3c_offset.getpixel(left_middle), - (127, 0, 127), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(left_middle), + (127, 0, 127), threshold=1), '3-color image (with offset) low-mid incorrect') - self.assertTrue(tuple_approx_equal(im_3c_offset.getpixel(middle), - (0, 0, 255), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(middle), + (0, 0, 255), threshold=1), '3-color image (with offset) mid incorrect') - self.assertTrue(tuple_approx_equal(im_3c_offset.getpixel(right_middle), - (0, 63, 127), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(right_middle), + (0, 63, 127), threshold=1), '3-color image (with offset) high-mid incorrect') - self.assertTrue(tuple_approx_equal(im_3c_offset.getpixel(right), - (0, 127, 0), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(right), + (0, 127, 0), threshold=1), '3-color image (with offset) white incorrect') diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index 4e6baf8c9..0ba7ce069 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -162,13 +162,10 @@ def colorize(image, black, white, mid=None, blackpoint=0, # Initial asserts assert image.mode == "L" - assert 0 <= whitepoint <= 255 - assert 0 <= blackpoint <= 255 - assert 0 <= midpoint <= 255 - assert blackpoint <= whitepoint - if mid is not None: - assert blackpoint <= midpoint - assert whitepoint >= midpoint + if mid is None: + assert 0 <= blackpoint <= whitepoint <= 255 + else: + assert 0 <= blackpoint <= midpoint <= whitepoint <= 255 # Define colors from arguments black = _color(black, "RGB") @@ -181,42 +178,28 @@ def colorize(image, black, white, mid=None, blackpoint=0, green = [] blue = [] + # Create the low-end values + for i in range(0, blackpoint): + red.append(black[0]) + green.append(black[1]) + blue.append(black[2]) + # Create the mapping (2-color) if mid is None: - # Define ranges - range_low = range(0, blackpoint) range_map = range(0, whitepoint - blackpoint) - range_high = range(0, 256 - whitepoint) - # Map - for i in range_low: - red.append(black[0]) - green.append(black[1]) - blue.append(black[2]) for i in range_map: red.append(black[0] + i * (white[0] - black[0]) // len(range_map)) green.append(black[1] + i * (white[1] - black[1]) // len(range_map)) blue.append(black[2] + i * (white[2] - black[2]) // len(range_map)) - for i in range_high: - red.append(white[0]) - green.append(white[1]) - blue.append(white[2]) # Create the mapping (3-color) else: - # Define ranges - range_low = range(0, blackpoint) range_map1 = range(0, midpoint - blackpoint) range_map2 = range(0, whitepoint - midpoint) - range_high = range(0, 256 - whitepoint) - # Map - for i in range_low: - red.append(black[0]) - green.append(black[1]) - blue.append(black[2]) for i in range_map1: red.append(black[0] + i * (mid[0] - black[0]) // len(range_map1)) green.append(black[1] + i * (mid[1] - black[1]) // len(range_map1)) @@ -225,10 +208,12 @@ def colorize(image, black, white, mid=None, blackpoint=0, red.append(mid[0] + i * (white[0] - mid[0]) // len(range_map2)) green.append(mid[1] + i * (white[1] - mid[1]) // len(range_map2)) blue.append(mid[2] + i * (white[2] - mid[2]) // len(range_map2)) - for i in range_high: - red.append(white[0]) - green.append(white[1]) - blue.append(white[2]) + + # Create the high-end values + for i in range(0, 256 - whitepoint): + red.append(white[0]) + green.append(white[1]) + blue.append(white[2]) # Return converted image image = image.convert("RGB")