Merge pull request #4843 from navneeth/master

This commit is contained in:
Hugo van Kemenade 2020-08-22 10:37:59 +03:00 committed by GitHub
commit 9c6d0bdcb7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 65 additions and 4 deletions

View File

@ -1,6 +1,6 @@
import pytest import pytest
from PIL import Image, ImageOps, features from PIL import Image, ImageDraw, ImageOps, ImageStat, features
from .helper import ( from .helper import (
assert_image_equal, assert_image_equal,
@ -25,7 +25,9 @@ def test_sanity():
ImageOps.autocontrast(hopper("RGB")) ImageOps.autocontrast(hopper("RGB"))
ImageOps.autocontrast(hopper("L"), cutoff=10) ImageOps.autocontrast(hopper("L"), cutoff=10)
ImageOps.autocontrast(hopper("L"), cutoff=(2, 10))
ImageOps.autocontrast(hopper("L"), ignore=[0, 255]) ImageOps.autocontrast(hopper("L"), ignore=[0, 255])
ImageOps.autocontrast(hopper("L"), mask=hopper("L"))
ImageOps.colorize(hopper("L"), (0, 0, 0), (255, 255, 255)) ImageOps.colorize(hopper("L"), (0, 0, 0), (255, 255, 255))
ImageOps.colorize(hopper("L"), "black", "white") ImageOps.colorize(hopper("L"), "black", "white")
@ -312,3 +314,51 @@ def test_autocontrast_cutoff():
assert autocontrast(10) == autocontrast((10, 10)) assert autocontrast(10) == autocontrast((10, 10))
assert autocontrast(10) != autocontrast((1, 10)) assert autocontrast(10) != autocontrast((1, 10))
def test_autocontrast_mask_toy_input():
# Test the mask argument of autocontrast
with Image.open("Tests/images/bw_gradient.png") as img:
rect_mask = Image.new("L", img.size, 0)
draw = ImageDraw.Draw(rect_mask)
x0 = img.size[0] // 4
y0 = img.size[1] // 4
x1 = 3 * img.size[0] // 4
y1 = 3 * img.size[1] // 4
draw.rectangle((x0, y0, x1, y1), fill=255)
result = ImageOps.autocontrast(img, mask=rect_mask)
result_nomask = ImageOps.autocontrast(img)
assert result != result_nomask
assert ImageStat.Stat(result, mask=rect_mask).median == [127]
assert ImageStat.Stat(result_nomask).median == [128]
def test_auto_contrast_mask_real_input():
# Test the autocontrast with a rectangular mask
with Image.open("Tests/images/iptc.jpg") as img:
rect_mask = Image.new("L", img.size, 0)
draw = ImageDraw.Draw(rect_mask)
x0, y0 = img.size[0] // 2, img.size[1] // 2
x1, y1 = img.size[0] - 40, img.size[1]
draw.rectangle((x0, y0, x1, y1), fill=255)
result = ImageOps.autocontrast(img, mask=rect_mask)
result_nomask = ImageOps.autocontrast(img)
assert result_nomask != result
assert_tuple_approx_equal(
ImageStat.Stat(result, mask=rect_mask).median,
[195, 202, 184],
threshold=2,
msg="autocontrast with mask pixel incorrect",
)
assert_tuple_approx_equal(
ImageStat.Stat(result_nomask).median,
[119, 106, 79],
threshold=2,
msg="autocontrast without mask pixel incorrect",
)

View File

@ -50,6 +50,14 @@ Add MIME type to PsdImagePlugin
API Additions API Additions
============= =============
ImageOps.autocontrast: add mask parameter
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
:py:func:`.ImageOps.autocontrast` can now take a ``mask`` parameter:
* Histogram used in contrast operation is computed using pixels within the mask.
If no mask is given the entire image is used for histogram computation.
ImageOps.autocontrast cutoffs ImageOps.autocontrast cutoffs
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -61,10 +61,10 @@ def _lut(image, lut):
# actions # actions
def autocontrast(image, cutoff=0, ignore=None): def autocontrast(image, cutoff=0, ignore=None, mask=None):
""" """
Maximize (normalize) image contrast. This function calculates a Maximize (normalize) image contrast. This function calculates a
histogram of the input image, removes ``cutoff`` percent of the histogram of the input image (or mask region), removes ``cutoff`` percent of the
lightest and darkest pixels from the histogram, and remaps the image lightest and darkest pixels from the histogram, and remaps the image
so that the darkest pixel becomes black (0), and the lightest so that the darkest pixel becomes black (0), and the lightest
becomes white (255). becomes white (255).
@ -74,9 +74,12 @@ def autocontrast(image, cutoff=0, ignore=None):
high ends. Either a tuple of (low, high), or a single high ends. Either a tuple of (low, high), or a single
number for both. number for both.
:param ignore: The background pixel value (use None for no background). :param ignore: The background pixel value (use None for no background).
:param mask: Histogram used in contrast operation is computed using pixels
within the mask. If no mask is given the entire image is used
for histogram computation.
:return: An image. :return: An image.
""" """
histogram = image.histogram() histogram = image.histogram(mask)
lut = [] lut = []
for layer in range(0, len(histogram), 256): for layer in range(0, len(histogram), 256):
h = histogram[layer : layer + 256] h = histogram[layer : layer + 256]