然而,我的边缘检测函数使用Sobel算子(维基百科描述)比其他函数慢得多,尽管它确实起作用。以下是代码:
def sobel(img):
xKernel = np.array([[-1,0,1],[-2,0,2],[-1,0,1]])
yKernel = np.array([[-1,-2,-1],[0,0,0],[1,2,1]])
sobelled = np.zeros((img.shape[0]-2, img.shape[1]-2, 3), dtype="uint8")
for y in range(1, img.shape[0]-1):
for x in range(1, img.shape[1]-1):
gx = np.sum(np.multiply(img[y-1:y+2, x-1:x+2], xKernel))
gy = np.sum(np.multiply(img[y-1:y+2, x-1:x+2], yKernel))
g = abs(gx) + abs(gy) #math.sqrt(gx ** 2 + gy ** 2) (Slower)
g = g if g > 0 and g < 255 else (0 if g < 0 else 255)
sobelled[y-1][x-2] = g
return sobelled
并使用这张猫的灰度图像运行它: 我得到了这个看起来正确的回复: 该库的应用,尤其是这个功能,是在一个下棋机器人上,其中边缘检测将有助于识别棋子的位置。问题在于它需要超过15秒才能运行,这是一个重大问题,因为它会显著增加机器人下棋所需的时间。
我的问题是:如何加速它?
到目前为止,我已经尝试了一些方法:
- 而不是对
gx
和gy
值进行平方、相加,然后开方得到总梯度,我只需要对绝对值进行求和。这样可以显著提高速度。 - 使用来自
rpi
摄像头的较低分辨率图像。这显然是一种简单的方法,可以使这些操作运行得更快,但它并不是非常可行,因为即使在最小可用分辨率480x360
下,速度仍然大大降低,远低于相机的最大分辨率3280x2464
。 - 编写嵌套的for循环来执行矩阵卷积,以代替
np.sum(np.multiply(...))
。这最终略微变慢,这让我感到惊讶,因为由于np.multiply
返回一个新的数组,我认为使用循环
应该更快。不过我认为这可能是因为numpy
主要是用C
编写的,或者新数组实际上没有被存储,所以不需要太长时间,但我不太确定。
OpenCV
实现了整个棋子检测,但我正在尝试用 Python 从头开始编写它。2D 卷积非常广泛,我以为我已经实现了它... - Joe Iddon