Unverified Commit ce10425d authored by LXXXXR's avatar LXXXXR Committed by GitHub
Browse files

[Feature] Add adjust sharpness (#864)

* add adjust sharpness

* revised according to commnts

* fix bug

* fix docstring

* revise according to comments

* fix blank lines

* revised according to comments
parent 27e9ede5
...@@ -8,9 +8,9 @@ from .geometric import (imcrop, imflip, imflip_, impad, impad_to_multiple, ...@@ -8,9 +8,9 @@ from .geometric import (imcrop, imflip, imflip_, impad, impad_to_multiple,
from .io import imfrombytes, imread, imwrite, supported_backends, use_backend from .io import imfrombytes, imread, imwrite, supported_backends, use_backend
from .misc import tensor2imgs from .misc import tensor2imgs
from .photometric import (adjust_brightness, adjust_color, adjust_contrast, from .photometric import (adjust_brightness, adjust_color, adjust_contrast,
clahe, imdenormalize, imequalize, iminvert, adjust_sharpness, clahe, imdenormalize, imequalize,
imnormalize, imnormalize_, lut_transform, posterize, iminvert, imnormalize, imnormalize_, lut_transform,
solarize) posterize, solarize)
__all__ = [ __all__ = [
'bgr2gray', 'bgr2hls', 'bgr2hsv', 'bgr2rgb', 'gray2bgr', 'gray2rgb', 'bgr2gray', 'bgr2hls', 'bgr2hsv', 'bgr2rgb', 'gray2bgr', 'gray2rgb',
...@@ -21,5 +21,6 @@ __all__ = [ ...@@ -21,5 +21,6 @@ __all__ = [
'imnormalize', 'imnormalize_', 'iminvert', 'posterize', 'solarize', 'imnormalize', 'imnormalize_', 'iminvert', 'posterize', 'solarize',
'rgb2ycbcr', 'bgr2ycbcr', 'ycbcr2rgb', 'ycbcr2bgr', 'tensor2imgs', 'rgb2ycbcr', 'bgr2ycbcr', 'ycbcr2rgb', 'ycbcr2bgr', 'tensor2imgs',
'imshear', 'imtranslate', 'adjust_color', 'imequalize', 'imshear', 'imtranslate', 'adjust_color', 'imequalize',
'adjust_brightness', 'adjust_contrast', 'lut_transform', 'clahe' 'adjust_brightness', 'adjust_contrast', 'lut_transform', 'clahe',
'adjust_sharpness'
] ]
...@@ -97,9 +97,10 @@ def posterize(img, bits): ...@@ -97,9 +97,10 @@ def posterize(img, bits):
def adjust_color(img, alpha=1, beta=None, gamma=0): def adjust_color(img, alpha=1, beta=None, gamma=0):
"""It blends the source image and its gray image: r"""It blends the source image and its gray image:
``output = img * alpha + gray_img * beta + gamma`` .. math::
output = img * alpha + gray\_img * beta + gamma
Args: Args:
img (ndarray): The input source image. img (ndarray): The input source image.
...@@ -166,7 +167,7 @@ def imequalize(img): ...@@ -166,7 +167,7 @@ def imequalize(img):
s2 = _scale_channel(img, 1) s2 = _scale_channel(img, 1)
s3 = _scale_channel(img, 2) s3 = _scale_channel(img, 2)
equalized_img = np.stack([s1, s2, s3], axis=-1) equalized_img = np.stack([s1, s2, s3], axis=-1)
return equalized_img.astype((img.dtype)) return equalized_img.astype(img.dtype)
def adjust_brightness(img, factor=1.): def adjust_brightness(img, factor=1.):
...@@ -177,7 +178,8 @@ def adjust_brightness(img, factor=1.): ...@@ -177,7 +178,8 @@ def adjust_brightness(img, factor=1.):
A factor of 1.0 gives the original image. This function A factor of 1.0 gives the original image. This function
blends the source image and the degenerated black image: blends the source image and the degenerated black image:
``output = img * factor + degenerated * (1 - factor)`` .. math::
output = img * factor + degenerated * (1 - factor)
Args: Args:
img (ndarray): Image to be brightened. img (ndarray): Image to be brightened.
...@@ -208,7 +210,8 @@ def adjust_contrast(img, factor=1.): ...@@ -208,7 +210,8 @@ def adjust_contrast(img, factor=1.):
image. A factor of 1.0 gives the original image. It image. A factor of 1.0 gives the original image. It
blends the source image and the degenerated mean image: blends the source image and the degenerated mean image:
``output = img * factor + degenerated * (1 - factor)`` .. math::
output = img * factor + degenerated * (1 - factor)
Args: Args:
img (ndarray): Image to be contrasted. BGR order. img (ndarray): Image to be contrasted. BGR order.
...@@ -229,6 +232,50 @@ def adjust_contrast(img, factor=1.): ...@@ -229,6 +232,50 @@ def adjust_contrast(img, factor=1.):
return contrasted_img.astype(img.dtype) return contrasted_img.astype(img.dtype)
def adjust_sharpness(img, factor=1., kernel=None):
"""Adjust image sharpness.
This function controls the sharpness of an image. An
enhancement factor of 0.0 gives a blurred image. A
factor of 1.0 gives the original image. And a factor
of 2.0 gives a sharpened image. It blends the source
image and the degenerated mean image:
.. math::
output = img * factor + degenerated * (1 - factor)
Args:
img (ndarray): Image to be sharpened. BGR order.
factor (float): Same as :func:`mmcv.adjust_brightness`.
kernel (np.ndarray, optional): Filter kernel to be applied on the img
to obtain the degenerated img. Defaults to None.
Notes:
No value sanity check is enforced on the kernel set by users. So with
an inappropriate kernel, the `adjust_sharpness` may fail to perform
the function its name indicates but end up performing whatever
transform determined by the kernel.
Returns:
ndarray: The sharpened image.
"""
if kernel is None:
# adopted from PIL.ImageFilter.SMOOTH
kernel = np.array([[1., 1., 1.], [1., 5., 1.], [1., 1., 1.]]) / 13
assert isinstance(kernel, np.ndarray), \
f'kernel must be of type np.ndarrray, but got {type(kernel)} instead.'
assert kernel.ndim == 2, \
f'kernel must have a dimention of 2, but got {kernel.ndim} instead.'
degenerated = cv2.filter2D(img, -1, kernel)
sharpened_img = cv2.addWeighted(
img.astype(np.float32), factor, degenerated.astype(np.float32),
1 - factor, 0)
sharpened_img = np.clip(sharpened_img, 0, 255)
return sharpened_img.astype(img.dtype)
def lut_transform(img, lut_table): def lut_transform(img, lut_table):
"""Transform array by look-up table. """Transform array by look-up table.
......
...@@ -202,6 +202,51 @@ class TestPhotometric: ...@@ -202,6 +202,51 @@ class TestPhotometric:
rtol=0, rtol=0,
atol=1) atol=1)
def test_adjust_sharpness(self, nb_rand_test=100):
def _adjust_sharpness(img, factor):
# adjust the sharpness of image using
# PIL.ImageEnhance.Sharpness
from PIL.ImageEnhance import Sharpness
from PIL import Image
img = Image.fromarray(img)
sharpened_img = Sharpness(img).enhance(factor)
return np.asarray(sharpened_img)
img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]],
dtype=np.uint8)
img = np.stack([img, img, img], axis=-1)
# test case with invalid type of kernel
with pytest.raises(AssertionError):
mmcv.adjust_sharpness(img, 1., kernel=1.)
# test case with invalid shape of kernel
kernel = np.ones((3, 3, 3))
with pytest.raises(AssertionError):
mmcv.adjust_sharpness(img, 1., kernel=kernel)
# test case with all-zero kernel, factor 0.0
kernel = np.zeros((3, 3))
assert_array_equal(
mmcv.adjust_sharpness(img, 0., kernel=kernel), np.zeros_like(img))
# test case with factor 1.0
assert_array_equal(mmcv.adjust_sharpness(img, 1.), img)
# test adjust_sharpness with randomly sampled images and factors.
for _ in range(nb_rand_test):
img = np.clip(
np.random.uniform(0, 1, (1000, 1200, 3)) * 260, 0,
255).astype(np.uint8)
factor = np.random.uniform()
# Note the gap between PIL.ImageEnhance.Sharpness and
# mmcv.adjust_sharpness mainly comes from the difference ways of
# handling img edges when applying filters
np.testing.assert_allclose(
mmcv.adjust_sharpness(img, factor).astype(np.int32)[1:-1,
1:-1],
_adjust_sharpness(img, factor).astype(np.int32)[1:-1, 1:-1],
rtol=0,
atol=1)
def test_lut_transform(self): def test_lut_transform(self):
lut_table = np.array(list(range(256))) lut_table = np.array(list(range(256)))
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment