我想做一个实时应用程序,其中涉及查找二进制掩码的边缘。我需要一些快速的东西,如果可能的话,没有 GPU,希望每张图像的运行速度低于 0.0005 秒,大小为 (1000,1000)。我将使用以下二进制图像示例,大小为 (1000,1000)。

(要复制的代码:)

import numpy as np
im=np.zeros((1000,1000),dtype=np.uint8)
im[400:600,400:600]=255

Image

快速做事的第一个合乎逻辑的方法是使用 OpenCV 库:
import cv2
timeit.timeit(lambda:cv2.Laplacian(im,cv2.CV_8U),number=100)/100
0.0011617112159729003

正如预期的那样,结果是:
laplacian

我发现这种方式非常耗时。在此之后,我尝试了 findContours:
 def usingcontours(im):
    points=np.transpose(cv2.findContours(im,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)[1][0])
    tmp=np.zeros_like(im)
    tmp[tuple(points)]=255
    return tmp
timeit.timeit(lambda:usingcontours(im),number=100)/100
0.0009052801132202148

这给出了与上面相同的结果。
这更好,但仍然没有我想要的那么好。作为最后的手段,我继续使用 numpy,使用梯度近似拉普拉斯算子,尽管我知道这会更糟:
def usinggradient(im):
    tmp=np.gradient(im)
    return ((tmp[0]+tmp[1])>0).astype(np.uint8)
timeit.timeit(lambda:usinggradient(im),number=100)/100
0.018681130409240722

那么,有没有人对我如何加速我的算法有任何进一步的想法?我强调我希望这个算法用于二进制图像,所以我想肯定有更好的实现。

最佳答案

我选择了最快的 cv2.findContours 来加快速度。在其中,我们可以用简单的 transpose 替换那些昂贵的 slicing 并转换为元组部分,就像这样 -

idx = cv2.findContours(im,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)[1][0]
out = np.zeros_like(im)
out[idx[:,0,0],idx[:,0,1]] = 255

运行时测试 -
In [114]: # Inputs
     ...: im=np.zeros((1000,1000),dtype=np.uint8)
     ...: im[400:600,400:600]=255
     ...: idx = cv2.findContours(im,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)[1][0]
     ...:

In [115]: def original_app(im, idx):
     ...:     points=np.transpose(idx)
     ...:     tmp=np.zeros_like(im)
     ...:     tmp[tuple(points)]=255
     ...:     return tmp
     ...:
     ...: def proposed_app(im, idx):
     ...:     out = np.zeros_like(im)
     ...:     out[idx[:,0,0],idx[:,0,1]] = 255
     ...:     return out
     ...:

In [120]: %timeit original_app(im, idx)
10000 loops, best of 3: 108 µs per loop

In [121]: %timeit proposed_app(im, idx)
10000 loops, best of 3: 101 µs per loop

In [122]: %timeit cv2.findContours(im,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
1000 loops, best of 3: 1.55 ms per loop

因此,所提出的方法有一些边际改进,但与轮廓查找本身相比,这似乎可以忽略不计。

我查看了 scikit-image's version 并进行了快速测试,似乎它比 OpenCV 版本慢得多。

关于python - 从 Python 中的二进制掩码中检索轮廓掩码的快速方法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40441910/

10-12 16:34