文章目录
这里的边缘检测算子采用的类拉普拉斯算子的变种, 关于拉普拉斯算子,我们再前面数字图像处理中已经有介绍过了.它的原理就是判单当前像素和周围像素(3x3)加权就和的平均值.下面详细介绍一下
1.算法原理
边缘增强通过提取图像中的边缘响应,并将其叠加到原始图像上,使边缘更加清晰锐利。我们主要从下面几点来说一下.
处理流程
原图 → 边缘滤波器 → 边缘图(edgemap) → 非线性增益 → 叠加到原图
边缘滤波器
使用 3×5 的滤波器(可配置),默认为类拉普拉斯算子,根据这个算子,可求出当前像素和3x5邻域内像素的加权平均值,正常非边缘地带,得到的是0,而当像素剧烈变化时(这个剧烈到何种程度我们可以自定义阈值),即边缘地带, 加权求和平均值不为0,
edge_filter = [[-1, 0, -1, 0, -1],
[-1, 0, 8, 0, -1],
[-1, 0, -1, 0, -1]]
edgemap[y,x] = Σ(img × edge_filter) / 8
非线性增益函数(emlut)
使用双阈值非线性映射,抑制弱噪声,增强强边缘, 需要结合后面的测试代码一起理解一下.
这里用户判断当前的map值是否在自定义的阈值范围(即差值在一定范围认为是边缘,否则为0).如果是边缘的话,会对边缘乘一个系数,以加强边缘.
val < -thres[1] → gain[1] × val (强负边缘,大增益)
-thres[1] ≤ val ≤ -thres[0] → 0 (弱负响应,抑制)
-thres[0] < val < thres[0] → gain[0] × val (微弱,小增益)
thres[0] ≤ val ≤ thres[1] → 0 (弱正响应,抑制)
val > thres[1] → gain[1] × val (强正边缘,大增益)
2.算法核心算法
- 关键参数
这个在下面测试代码中,默认定义的有参数.
| 参数 | 说明 | 典型值 |
|---|---|---|
edge_filter |
3×5 边缘提取核 | 类拉普拉斯 |
gain[0] |
弱边缘增益(/256) | 32 |
gain[1] |
强边缘增益(/256) | 128 |
thres[0] |
弱边缘阈值 | 32 |
thres[1] |
强边缘阈值 | 64 |
emclip |
增益量 clip 范围 | -64, 64 |
-
最终输出
原图加上边缘的信息,能够在图像中看到边缘信息.ee_output[y,x] = original[y,x] + emlut(edgemap[y,x])
-
核心代码
python
class EE:
'Edge Enhancement'
def __init__(self, img, edge_filter, gain, thres, emclip):
self.img = img
self.edge_filter = edge_filter
self.gain = gain
self.thres = thres
self.emclip = emclip
# 为了方便后续卷积,对图像进行填边操作
def padding(self):
img_pad = np.pad(self.img, ((1, 1), (2, 2)), 'reflect')
return img_pad
# 放置图像像素溢出,像素在(0,255)之间
def clipping(self):
np.clip(self.img, 0, 255, out=self.img)
return self.img
def emlut(self, val, thres, gain, clip):
lut = 0
if val < -thres[1]: # 根据拉普拉斯算子看,此种情况是当前像素值比周围像素暗
lut = gain[1] * val
elif val < -thres[0] and val > -thres[1]:
lut = 0
elif val < thres[0] and val > -thres[1]:
lut = gain[0] * val
# 根据拉普拉斯算子看,此种情况是当前像素值比周围像素亮,但不多
elif val > thres[0] and val < thres[1]:
lut = 0
# 根据拉普拉斯算子看,此种情况是当前像素值比周围像素亮很多
elif val > thres[1]:
lut = gain[1] * val
# np.clip(lut, clip[0], clip[1], out=lut)
lut = max(clip[0], min(lut / 256, clip[1]))
return lut
def execute(self):
img_pad = self.padding()
img_h = self.img.shape[0]
img_w = self.img.shape[1]
ee_img = np.empty((img_h, img_w), np.int16)
em_img = np.empty((img_h, img_w), np.int16)
for y in range(img_pad.shape[0] - 2):
for x in range(img_pad.shape[1] - 4):
#对当前像素做卷积,求和,平均
em_img[y,x] = np.sum(np.multiply(img_pad[y:y+3, x:x+5], self.edge_filter[:, :])) / 8
# 原图+边缘信息,即边缘加强后的图像
ee_img[y,x] = img_pad[y+1,x+2] + self.emlut(em_img[y,x], self.thres, self.gain, self.emclip)
self.img = ee_img
return self.clipping(), em_img
3.测试代码
python
def _default_params(self):
edge_filter = np.array([
[-1, 0, -1, 0, -1],
[-1, 0, 8, 0, -1],
[-1, 0, -1, 0, -1],
], dtype=float)
gain = [32, 128]
thres = [32, 64] # 在这个范围内的<-64,以及>64都认为是边缘上的点
emclip = [-64, 64]
return edge_filter, gain, thres, emclip
def test_step_edge_nonzero_response(self):
"""
包含阶跃边缘的图像(左半 20,右半 100),
边界附近的 edgemap 应有非零响应。
"""
# 生成一个16x20的的图像,左边10列为深灰色,右边10列为灰色
img = np.zeros((16, 20), dtype=np.int16)
img[:, :10] = 20
img[:, 10:] = 100
edge_filter, gain, thres, emclip = self._default_params()
ee = EE(img.copy(), edge_filter, gain, thres, emclip)
ee_out, em_out = ee.execute()
show_gray_images(img, em_out,"left", "right-edgemap")
show_gray_images(img, ee_out,"left", "right-edgemap+img")
print(f"em_out2:{em_out}")
-
degeMap显示效果
显示degeMap效果,这里中间能看到有一个不一样的带装图像

实际的边缘map信息edegeMap矩阵如下所示[[ 0 0 0 0 0 0 0 0 -30 -30 30 30 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 -30 -30 30 30 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 -30 -30 30 30 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 -30 -30 30 30 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 -30 -30 30 30 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 -30 -30 30 30 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 -30 -30 30 30 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 -30 -30 30 30 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 -30 -30 30 30 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 -30 -30 30 30 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 -30 -30 30 30 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 -30 -30 30 30 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 -30 -30 30 30 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 -30 -30 30 30 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 -30 -30 30 30 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 -30 -30 30 30 0 0 0 0 0 0 0 0]] -
edgeMap+原图
叠加后能看到边缘加强
