在计算机视觉领域,对比度增强是提升图像质量、改善模型性能的关键步骤。对比度,简而言之,是指图像中不同区域之间可观察到的差异。这种差异在像素层面表现为明显的不同。对比度增强不是简单地对所有像素进行统一的亮度调整,而是根据像素之间的相对差异进行调整,使得暗像素在整个图像中更加均匀地分布。
对比度增强在天文学中尤为常见,例如,可以比较两张同一时间拍摄的月亮图像:左侧的图像对比度较低,而右侧的图像对比度较高。对比度的提高不仅使图像看起来更悦目,而且对于神经网络来说也更容易理解。回想一下计算机视觉中的一个基本原则,无论是分类、目标检测还是分割,边缘检测都是核心任务。通过对比度预处理,边缘变得更加清晰,因为邻近像素之间的差异被放大。
对比度预处理与数据增强有所不同:预处理意味着对训练集、验证集和测试集中的所有图像都应用相同的转换。而数据增强仅适用于训练集。通常,如果问题中存在对比度较低的图像,或者部分图像的对比度过于饱和,通过预处理平滑图像的对比度是有益的。处理扫描文档时,对比度通常低于理想值。在低对比度的情况下,对于光学字符识别(OCR)来说,识别微弱的字母可能具有挑战性。创建字母与背景之间的更大对比度可以产生更清晰的边缘。需要注意的是,对比度的变化不仅仅是使整个图像变暗:白色背景几乎是相等的色调。
在OCR中添加对比度是一个常见的预处理步骤。对比度预处理可以在许多开源框架中实现,例如TensorFlow中的图像对比度、PyTorch中的图像对比度预处理、FastAI中的图像对比度调整,以及scikit-image中的直方图均衡化对比度。注意:如果在单一框架中进行对比度处理,将来尝试迁移到另一个框架时可能会遇到问题,因为并非所有实现都是相同的。
在scikit-image中,文档提供了一个关于图像对比度如何影响图像属性的很好的例子。通过scikit-image文档中的直方图均衡化。对比度调整(自适应直方图均衡化,AHE)主要是将暗像素更均匀地分布在整个图像中。这个例子还引入了一个提高对比度的基本概念:局部均衡化。像自适应均衡化这样的对比度调整会考虑图像的局部部分,以防止出现中间中间图像的结果,而是将对比度变化更均匀地分布在整个图像中。
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from skimage import data
from skimage.util.dtype import dtype_range
from skimage.util import img_as_ubyte
from skimage import exposure
from skimage.morphology import disk
from skimage.filters import rank
matplotlib.rcParams['font.size'] = 9
def plot_img_and_hist(image, axes, bins=256):
"""Plot an image along with its histogram and cumulative histogram.
"""
ax_img, ax_hist = axes
ax_cdf = ax_hist.twinx()
# Display image
ax_img.imshow(image, cmap=plt.cm.gray)
ax_img.set_axis_off()
# Display histogram
ax_hist.hist(image.ravel(), bins=bins)
ax_hist.ticklabel_format(axis='y', style='scientific', scilimits=(0, 0))
ax_hist.set_xlabel('Pixel intensity')
xmin, xmax = dtype_range[image.dtype.type]
ax_hist.set_xlim(xmin, xmax)
# Display cumulative distribution
img_cdf, bins = exposure.cumulative_distribution(image, bins)
ax_cdf.plot(bins, img_cdf, 'r')
return ax_img, ax_hist, ax_cdf
# Load an example image
img = img_as_ubyte(data.moon())
# Global equalize
img_rescale = exposure.equalize_hist(img)
# Equalization
selem = disk(30)
img_eq = rank.equalize(img, selem=selem)
# Display results
fig = plt.figure(figsize=(8, 5))
axes = np.zeros((2, 3), dtype=np.object)
axes[0, 0] = plt.subplot(2, 3, 1)
axes[0, 1] = plt.subplot(2, 3, 2, sharex=axes[0, 0], sharey=axes[0, 0])
axes[0, 2] = plt.subplot(2, 3, 3, sharex=axes[0, 0], sharey=axes[0, 0])
axes[1, 0] = plt.subplot(2, 3, 4)
axes[1, 1] = plt.subplot(2, 3, 5)
axes[1, 2] = plt.subplot(2, 3, 6)
ax_img, ax_hist, ax_cdf = plot_img_and_hist(img, axes[:, 0])
ax_img.set_title('Low contrast image')
ax_hist.set_ylabel('Number of pixels')
ax_img, ax_hist, ax_cdf = plot_img_and_hist(img_rescale, axes[:, 1])
ax_img.set_title('Global equalise')
ax_img, ax_hist, ax_cdf = plot_img_and_hist(img_eq, axes[:, 2])
ax_img.set_title('Local equalize')
ax_cdf.set_ylabel('Fraction of total intensity')
# prevent overlap of y-axis labels
fig.tight_layout()
plt.show()