mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-01 05:42:05 +08:00
Fix handling of border pixels and update tests
This commit is contained in:
@@ -55,9 +55,10 @@ def equalize_adapthist(image, ntiles_x=8, ntiles_y=8, clip_limit=0.01,
|
||||
- The CLAHE algorithm is run on the V (Value) channel
|
||||
- The image is converted back to RGB space and returned
|
||||
* For RGBA images, the original alpha channel is removed.
|
||||
* The CLAHE algorithm relies on image blocks of equal size. This results
|
||||
in extra border pixels that are not handled. Extra blocks are created
|
||||
around the border to handle these pixels.
|
||||
* The CLAHE algorithm relies on image blocks of equal size. This may
|
||||
result in extra border pixels that would not be handled. In that case,
|
||||
we pad the image with a repeat of the border pixels, apply the
|
||||
algorithm, and then trim the image to original size.
|
||||
|
||||
References
|
||||
----------
|
||||
@@ -120,19 +121,36 @@ def _clahe(image, ntiles_x, ntiles_y, clip_limit, nbins=128):
|
||||
if clip_limit == 1.0:
|
||||
return image # is OK, immediately returns original image.
|
||||
|
||||
map_array = np.zeros((ntiles_y, ntiles_x, nbins), dtype=int)
|
||||
|
||||
y_res = image.shape[0] - image.shape[0] % ntiles_y
|
||||
x_res = image.shape[1] - image.shape[1] % ntiles_x
|
||||
|
||||
# make the tile size divisible by 2
|
||||
while y_res % (2 * ntiles_y):
|
||||
y_res -= 1
|
||||
while x_res % (2 * ntiles_x):
|
||||
x_res -= 1
|
||||
image = image[: y_res, : x_res]
|
||||
|
||||
x_size = image.shape[1] // ntiles_x # Actual size of contextual regions
|
||||
y_size = image.shape[0] // ntiles_y
|
||||
orig_shape = image.shape
|
||||
x_size = x_res // ntiles_x # Actual size of contextual regions
|
||||
y_size = y_res // ntiles_y
|
||||
|
||||
if y_res != image.shape[0]:
|
||||
ntiles_y += 1
|
||||
if x_res != image.shape[1]:
|
||||
ntiles_x += 1
|
||||
if y_res != image.shape[1] or x_res != image.shape[0]:
|
||||
hgt = y_size * ntiles_y - image.shape[0]
|
||||
wid = x_size * ntiles_x - image.shape[1]
|
||||
image = np.vstack((image, image[-hgt:, :]))
|
||||
image = np.hstack((image, image[:, -wid:]))
|
||||
y_res, x_res = image.shape
|
||||
|
||||
bin_size = 1 + NR_OF_GREY / nbins
|
||||
aLUT = np.arange(NR_OF_GREY)
|
||||
aLUT //= bin_size
|
||||
img_blocks = view_as_blocks(image, (y_size, x_size))
|
||||
|
||||
map_array = np.zeros((ntiles_y, ntiles_x, nbins), dtype=int)
|
||||
n_pixels = x_size * y_size
|
||||
|
||||
if clip_limit > 0.0: # Calculate actual cliplimit
|
||||
@@ -142,11 +160,6 @@ def _clahe(image, ntiles_x, ntiles_y, clip_limit, nbins=128):
|
||||
else:
|
||||
clip_limit = NR_OF_GREY # Large value, do not clip (AHE)
|
||||
|
||||
bin_size = 1 + NR_OF_GREY / nbins
|
||||
aLUT = np.arange(NR_OF_GREY)
|
||||
aLUT //= bin_size
|
||||
img_blocks = view_as_blocks(image, (y_size, x_size))
|
||||
|
||||
# Calculate greylevel mappings for each contextual region
|
||||
for y in range(ntiles_y):
|
||||
for x in range(ntiles_x):
|
||||
@@ -203,6 +216,9 @@ def _clahe(image, ntiles_x, ntiles_y, clip_limit, nbins=128):
|
||||
|
||||
ystart += ystep
|
||||
|
||||
if image.shape != orig_shape:
|
||||
image = image[:orig_shape[0], :orig_shape[1]]
|
||||
|
||||
return image
|
||||
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ import matplotlib.pyplot as plt
|
||||
# Test histogram equalization
|
||||
# ===========================
|
||||
|
||||
np.random.seed(0)
|
||||
|
||||
# squeeze image intensities to lower image contrast
|
||||
test_img = skimage.img_as_float(data.camera())
|
||||
test_img = exposure.rescale_intensity(test_img / 5. + 100)
|
||||
@@ -170,8 +172,8 @@ def test_adapthist_grayscale():
|
||||
nbins=128)
|
||||
assert_almost_equal = np.testing.assert_almost_equal
|
||||
assert img.shape == adapted.shape
|
||||
assert_almost_equal(peak_snr(img, adapted), 105.669, 3)
|
||||
assert_almost_equal(norm_brightness_err(img, adapted), 0.02470, 3)
|
||||
assert_almost_equal(peak_snr(img, adapted), 104.3168, 3)
|
||||
assert_almost_equal(norm_brightness_err(img, adapted), 0.0265, 3)
|
||||
return data, adapted
|
||||
|
||||
|
||||
@@ -212,59 +214,6 @@ def test_adapthist_alpha():
|
||||
assert_almost_equal(norm_brightness_err(full_scale, adapted), 0.0544, 3)
|
||||
|
||||
|
||||
def test_adapthist_modes_scalar():
|
||||
'''Test adaptist `mode` parameter values for ndim==2 image.
|
||||
'''
|
||||
img = skimage.img_as_float(data.moon())
|
||||
full_scale = skimage.exposure.rescale_intensity(skimage.img_as_uint(img))
|
||||
ignore = exposure.equalize_adapthist(img.copy(), ntiles_x=9, ntiles_y=9)
|
||||
zero = exposure.equalize_adapthist(img.copy(), ntiles_x=9, ntiles_y=9,
|
||||
mode='zero')
|
||||
crop = exposure.equalize_adapthist(img.copy(), ntiles_x=9, ntiles_y=9,
|
||||
mode='crop')
|
||||
assert ignore.shape == zero.shape
|
||||
assert ignore.shape != crop.shape
|
||||
assert_array_equal(zero[crop.shape[0]:, :], 0)
|
||||
assert_array_equal(zero[:, crop.shape[1]:], 0)
|
||||
|
||||
assert_almost_equal = np.testing.assert_almost_equal
|
||||
full_cropped = full_scale[:crop.shape[0], :crop.shape[1]]
|
||||
zero_cropped = zero[:crop.shape[0], :crop.shape[1]]
|
||||
ignore_cropped = ignore[:crop.shape[0], :crop.shape[1]]
|
||||
|
||||
for crop_img in [ignore_cropped, zero_cropped, crop]:
|
||||
assert_almost_equal(peak_snr(full_cropped, crop_img), 120.456, 3)
|
||||
assert_almost_equal(norm_brightness_err(full_cropped, crop_img),
|
||||
0.4398, 3)
|
||||
|
||||
|
||||
def test_adapthist_modes_rgb():
|
||||
'''Test adaptist `mode` parameter values for rgb image.
|
||||
'''
|
||||
img = skimage.img_as_float(data.lena())
|
||||
full_scale = skimage.exposure.rescale_intensity(skimage.img_as_uint(img))
|
||||
ignore = exposure.equalize_adapthist(img.copy(), ntiles_x=9, ntiles_y=10)
|
||||
zero = exposure.equalize_adapthist(img.copy(), ntiles_x=9, ntiles_y=10,
|
||||
mode='zero')
|
||||
crop = exposure.equalize_adapthist(img.copy(), ntiles_x=9, ntiles_y=10,
|
||||
mode='crop')
|
||||
assert ignore.shape == zero.shape
|
||||
assert ignore.shape != crop.shape
|
||||
|
||||
assert_array_equal(zero[crop.shape[0]:, :, :], 0)
|
||||
assert_array_equal(zero[:, crop.shape[1]:, :], 0)
|
||||
|
||||
assert_almost_equal = np.testing.assert_almost_equal
|
||||
full_cropped = full_scale[:crop.shape[0], :crop.shape[1], :]
|
||||
zero_cropped = zero[:crop.shape[0], :crop.shape[1], :]
|
||||
ignore_cropped = ignore[:crop.shape[0], :crop.shape[1], :]
|
||||
|
||||
for crop_img in [ignore_cropped, zero_cropped, crop]:
|
||||
assert np.floor(peak_snr(full_cropped, crop_img)) == 106
|
||||
assert_almost_equal(norm_brightness_err(full_cropped, crop_img),
|
||||
0.0517, 3)
|
||||
|
||||
|
||||
def peak_snr(img1, img2):
|
||||
'''Peak signal to noise ratio of two images
|
||||
|
||||
|
||||
Reference in New Issue
Block a user