Fast component labeling in python and opencv

I implement a component labeling algorithm, as in this article , using python and opencv. This requires checking the input image by pixels and executing the so-called contour trace routine to assign a label to the blocks of the binary image.

I managed to run it, but it seems very slow. Code profiling shows what seems like a bottleneck for a cycle to access pixels. It takes about 200 ms for a 256px * 256px image. Here is roughly what I am doing:

for i in image.height: for j in image.width: p = image[i, j] pa = image[i - 1, j] pb = image[i + 1, j] # etc... 

where the "image" is the opencv binary image.

I wonder if there is a faster way to do this so that it is useful for video applications. I am aiming for something like a 40-50 ms time for the same problem size to get 20-25 frames per second. 10-15fps is likely to be acceptable (runtime 66-100 ms).

Any tips, ideas that I can do are greatly appreciated.

+4
source share
2 answers

The latest OpenCV bindings for Python return numpy data types, which means you have the full numpy arsenal at your disposal. Looping over a two-dimensional array in numpy (with indexes) is usually done using ndenumerate , which should offer at least a slight acceleration (since it is one loop optimized for ND arrays). You can look at numpy vectorize , which would give even greater speedup, but if you need array indexes, then ndenumerate be what you need.

Other than that, recording bottlenecks in C. might be a better option.

Update

If this helps, I believe that scipy.ndimage.label does exactly what you are trying to do, and can even use the same algorithm.

+1
source

Many of the posts I've seen complain about the lack of OpenCV labeling.

As @ malloc47 said, scipy.ndimage.label will work. I used it, but I was not happy with its performance, while I was looking for the largest frame in the image. I don't need labeling, so I used cv2.findContours and cv2.contourArea to highlight the largest:

 # The [0] is because I didn't care about the hierarchy, which is the second # return value of cv2.findContours. contours = cv2.findContours(numpy_array, mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_SIMPLE )[0] areas = [cv2.contourArea(ctr) for ctr in contours] max_contour = [contours[areas.index(max(areas))]] 

This turned out to be much faster for me than scipy.ndimage.label for very similar results. As I said, this is not an exact marking, but you can probably use the contour finder to give a good enough marking.

+1
source

Source: https://habr.com/ru/post/1397215/


All Articles