用opencv-python实现能线性调整的模糊、锐化
现在的手机图库中,模糊和锐化是必不可少的两个功能。
然而,各位应该都有注意到:在opencv中,锐化和模糊的主要参数都是卷积核半径,且必须为奇数;但是在使用图库软件时,大部分时候只需要拖动一个滑动条。或许“滑动条”的说法不够明显,更直观的说法是:图库软件的模糊和锐化只需要一个浮点数做参数。
显然,图库软件的开发者不可能重复造轮子,他们用的模糊和锐化,底层必然和opencv相似。本文讲的就是如何在opencv中实现这样一个以浮点数控制操作力度的锐化或模糊。本文的思路也适用于其他卷积操作,如USM。
连续与不连续
卷积核半径是不连续的,而操作力度是连续的。
也就是说,虽然我们可以建立这样一个映射,但是非整数的操作力度并不直接对应任意一个卷积核卷积的结果。
操作力度 | 卷积核半径 |
---|---|
1 | 3 |
2 | 5 |
3 | 7 |
我想到的解决方法是:线性混合。按比例混合两个卷积核卷积的结果,就能表示小数的操作力度。
实现
首先将线性混合封装成函数
def gen_kparams(degree):
# 根据参数“degree”生成两个内核半径和它们的混合比例
assert degree>0
deg_head = math.ceil(degree)
deg_tail = degree+1-deg_head
ksize_large = deg_head*2+1
ksize_small = ksize_large-2
large_ratio = deg_tail
small_ratio = 1-large_ratio
return ksize_large, large_ratio, ksize_small, small_ratio
def get_filtered(img, filter_func, degree):
# 根据生成的参数处理图片并混合
ksize_large, large_ratio, ksize_small, small_ratio = gen_kparams(degree)
large = filter_func(img, ksize_large)
small = filter_func(img, ksize_small)
ret = cv2.addWeighted(large, large_ratio, small, small_ratio, 0)
return ret
然后加入具体的操作
gaussian_filter = lambda img, ksize: cv2.GaussianBlur(img, (ksize, ksize), 0)
laplacian_filter = lambda img, ksize: cv2.Laplacian(img, -1, ksize=ksize)
def blur(img, degree=1):
ret = get_filtered(img, gaussian_filter, degree)
return ret
def sharpen(img, degree=1):
ret = cv2.subtract(img, get_filtered(img, laplacian_filter, degree))
return ret