opencv - Fast method to retrieve contour mask from a binary mask in Python -
i want make realtime application, involves finding edges of binary mask. need fast, without gpu if possible, runs below 0.0005 secs per image, size (1000,1000). using following example of binary image ,with size (1000,1000).
(code replicate:)
import numpy np im=np.zeros((1000,1000),dtype=np.uint8) im[400:600,400:600]=255
the first logical way things fast use opencv library:
import cv2 timeit.timeit(lambda:cv2.laplacian(im,cv2.cv_8u),number=100)/100 0.0011617112159729003
which expected resulted in: laplacian
i found way time consuming. after tried 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
which gave same result above. better, still not like. moved on usage of numpy, approximate laplacian using gradient, last resort, although knew worse:
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
so, has further idea on how can accelerate algorithm? emphasize want algorithm used binary images, guess there must better implementation.
i picked fastest 1 cv2.findcontours
speed up. in it, replace expensive transpose
, converting tuple parts simple 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
runtime test -
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
so, there's marginal improvement there proposed method, seems negligible compared contour-finding itself.
i looked scikit-image's version
, ran quick test , seems it's slower opencv version.
Comments
Post a Comment