简而言之:我需要一个快速(预编译)功能,例如来自OpenCV的 filter2d ,带有 double type 输出。不是整数。
详情: 我有numpy数组存储来自OpenCV的单色图像。
我需要为某些方形(例如)内核计算矩阵的平均值,如下所示:
kernel size = (3,3)
输入数组:
[[13 10 10 10]
[12 10 10 8]
[ 9 9 9 9]
[ 9 10 10 9]]
输出数组:
[[ 10.22222222 9.44444444]
[ 9.77777778 9.33333333]]
例如: 10.22222 =(13 + 10 + 10 + 12 + 10 + 10 + 9 + 9 + 9)/ 9
我写这个函数:
def smooth_filt(src,area_x,area_y):
y,x = src.shape
x_lim = int(area_x/2)
y_lim = int(area_y/2)
result = np.zeros((y-2*y_lim,x-2*x_lim), dtype=np.float64)
for x_i in range(x_lim,x-x_lim):
for y_i in range(y_lim,y-y_lim):
result[y_i-y_lim, x_i-x_lim] = np.mean(src[y_i-y_lim:y_i+area_y-y_lim,x_i-x_lim:x_i+area_x-x_lim])
return result
但这还不够快。
请告诉我是否有更快的方法来计算它。
答案: 我检查所有方法。您可以看到代码:http://pastebin.com/y5dEVbzX
并确定模糊是最强大的方法,它几乎与内核大小无关。
答案 0 :(得分:4)
计算块中的平均值只是将图像卷积为
一个恒定的内核。
您可以使用scipy.signal.convolve2d
:
from scipy.signal import convolve2d
kernel = np.ones((3,3)) / 9.
out = convolve2d(img, kernel, mode='valid')
mode='valid'
参数只需要获取您感兴趣的结果部分。
答案 1 :(得分:3)
看看scipy.signal.convolve2d
。这很简单:
import numpy as np
import scipy.signal as ss
data = np.array([[13, 10, 10, 10],
[12, 10, 10, 8],
[ 9, 9, 9, 9],
[ 9, 10, 10, 9]])
kernel = np.ones((3,3))
kernel /= kernel.size
ss.convolve2d(data, kernel, mode='valid')
这给出了
array([[ 10.22222222, 9.44444444],
[ 9.77777778, 9.33333333]])
答案 2 :(得分:3)
如果您对OpenCV解决方案感兴趣:您需要的功能是cv2.blur
。
对于大多数情况,它必须比卷积更快,因为它对标准化内核进行了单独的优化(系数之和等于1)。
blurred = cv2.blur(img,(3,3))
请参阅有关平滑here的精彩教程。
答案 3 :(得分:1)
您可以利用integral function来计算从(0,0)到(i,j)元素的值之和。
使用这些积分图像,您可以在恒定时间内计算图像特定右上角或旋转矩形区域的和,平均值和标准偏差
如果"内核" size是常数M,乘以1/M^2
得到的积分矩阵,以简化平均计算。
要在某个窗口(x1,y1) - (x2,y2)得到总和,只需找到
S((x1,y1)-(x2,y2)) = I(x1,y1) + I(x2,y2) - I(x1,y2) - I(x2,y1)
伪代码:
integral(src, sum)
multvalue = 1/(kernelsize*kernelsize)
sum = sum * multvalue
for every (x = 0..n-kernelsize-1, y = 0..n-kernelsize-1)
mean[x,y] = sum[x, y]
+ sum[x + kernelsize, y + kernelsize]
- sum[x, y + kernelsize]
- sum[x + kernelsize, y]