SHARPENING (HIGHPASS) SPATIAL FILTERS

上一部分介绍的blur能够将图片模糊化, 这部分介绍的是突出图片的边缘的细节.

什么是边缘呢? 往往是像素点跳跃特别大的点, 这部分和梯度的概念是类似的, 可以如下定义图片的一阶导数而二阶导数:

fx=f(x+1)f(x),2fx2=f(x+1)+f(x1)2f(x).

注: 或许用差分来表述更为贴切.

如上图实例所示, 描述了密度值沿着x的变化, 一阶导数似乎能划分区域, 而二阶导数能够更好的“识别"边缘.

Laplacian

著名的laplacian算子:

Δf=2fx2+2fy2,

在digital image这里:

Δf=f(x+1y)+f(x1,y)+f(x,y+1)+f(x,y1)4f(x,y).

这个算子用kernel表示是下面的(a), 但是在实际中也有(b, c, d)的用法, (b, d)额外用到了对角的信息, 注意到这些kernels都满足

ijwij=0.

最后

g(x,y)=f(x,y)+c[2f(x,y)],

c=1, 如果a, b, c=1如果c, d.

kernel = -np.ones((3, 3))
kernel[1, 1] = 8
laps = cv2.filter2D(img, -1, kernel)
laps = (laps - laps.min()) / (laps.max() - laps.min()) * 255
img_pos = img + laps
img_neg = img - laps
fig, axes = plt.subplots(1, 4)
axes[0].imshow(img, cmap='gray')
axes[1].imshow(laps, cmap='gray')
axes[2].imshow(img_pos, cmap='gray')
axes[3].imshow(img_neg, cmap='gray')
plt.tight_layout()
plt.show()

kernel = np.ones((3, 3))
kernel[0, 0] = 0
kernel[0, 2] = 0
kernel[1, 1] = -4
kernel[2, 0] = 0
kernel[2, 2] = 0
laps = cv2.filter2D(img, -1, kernel)
laps = (laps - laps.min()) / (laps.max() - laps.min()) * 255
img_pos = img + laps
img_neg = img - laps
fig, axes = plt.subplots(1, 4)
axes[0].imshow(img, cmap='gray')
axes[1].imshow(laps, cmap='gray')
axes[2].imshow(img_pos, cmap='gray')
axes[3].imshow(img_neg, cmap='gray')
plt.tight_layout()
plt.show()

有点奇怪... 注意到我上面对laps进行标准化处理了, 如果没这个处理其实感觉是差不多的c=1,1.

UNSHARP MASKING AND HIGHBOOST FILTERING

注意到, 之前的box kernel,

wbox(s,t)=1mn,

考虑3×3的kernel size下:

wlap=9(Ewbox),

这里

E(s,t)=0,s2,t2.

故假设

gmask(x,y)=f(x,y)f¯(x,y),

其中f¯是通过box filter 模糊的图像, 则

Δf=9gmask.

gmask也反应了细节边缘信息.

进一步定义

g(x,y)=f(x,y)+kgmask(x,y).

kernel = np.ones((3, 3)) / 9
img_mask = (img - cv2.filter2D(img, -1, kernel)) * 9
img_mask = (img_mask - img_mask.mean()) / (img_mask.max() - img_mask.min())
fig, ax = plt.subplots(1, 1)
ax.imshow(img_mask, cmap='gray')
plt.show()

First-Order Derivatives

最后再说说如何用一阶导数提取细节.

定义

M(x,y)=f=(fx)2+(fy)2.

注: 也常常用M(x,y)=|fx|+|fy|代替.

Roberts cross-gradient

把目标区域按照图(a)区分, Roberts cross-gradient采用如下方式定义:

fx=z9z5,fy=z8z6,

即右下角的对角之差. 所以相应的kernel变如图(b, c)所示(其余部分为0, 3×3).

注: 计算M需要两个kernel做两次卷积.

Sobel operators

Sobel operators 则是

fx=(z7+2z8+z9)(z1+2z2+z3)fy=(z3+2z6+z9)(z1+2z4+z7),

即如图(d, e)所示.

kernel = np.zeros((3, 3))
kernel[1, 1] = -1
kernel[2, 2] = 1
part1 = cv2.filter2D(img, -1, kernel)
kernel = np.zeros((3, 3))
kernel[1, 2] = -1
kernel[2, 1] = 1
part2 = cv2.filter2D(img, -1, kernel)
img_roberts = np.sqrt(part1 ** 2 + part2 ** 2)
part1 = cv2.Sobel(img, -1, dx=1, dy=0, ksize=3)
part2 = cv2.Sobel(img, -1, dx=0, dy=1, ksize=3)
img_sobel = np.sqrt(part1 ** 2 + part2 ** 2)
fig, axes = plt.subplots(1, 2)
axes[0].imshow(img_roberts, cmap='gray')
axes[1].imshow(img_sobel, cmap='gray')

posted @   馒头and花卷  阅读(111)  评论(0编辑  收藏  举报
编辑推荐:
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
阅读排行:
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· 分享4款.NET开源、免费、实用的商城系统
· 解决跨域问题的这6种方案,真香!
· 一套基于 Material Design 规范实现的 Blazor 和 Razor 通用组件库
· 5. Nginx 负载均衡配置案例(附有详细截图说明++)
历史上的今天:
2020-06-16 Generating Adversarial Examples with Adversarial Networks
点击右上角即可分享
微信分享提示