openISP学习12-EE — Edge Enhancement(边缘增强)

这里的边缘检测算子采用的类拉普拉斯算子的变种, 关于拉普拉斯算子,我们再前面数字图像处理中已经有介绍过了.它的原理就是判单当前像素和周围像素(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_filter3×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])
  • 核心代码
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.测试代码

    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+原图
    叠加后能看到边缘加强
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值