RMS
RMS

Reputation: 1430

Difference between cv2.findNonZero and Numpy.NonZero

Silly question here.

I want to find the locations of the pixels from some black and white images and found this two functions from Numpy library and OpenCV.

The example I found on the internet (http://docs.opencv.org/trunk/d1/d32/tutorial_py_contour_properties.html):

    mask = np.zeros(imgray.shape,np.uint8)
    cv2.drawContours(mask,[cnt],0,255,-1)
    pixelpoints = np.transpose(np.nonzero(mask))
    pixelpointsCV2 = cv2.findNonZero(mask)

Which states

Numpy gives coordinates in (row, column) format, while OpenCV gives coordinates in (x,y) format. So basically the answers will be interchanged. Note that, row = x and column = y.

Based on my understanding of english, isn't their explanation wrong? Shouldn't it be:

Numpy gives coordinates in (row, column) format, while OpenCV gives coordinates in (y,x) or (column, row) format.

My questions are:

  1. Does numpy return (row,col)/(x,y) and OpenCV (y,x) where row=x, col=y? Although IMHO it should be row=y, col=x?

  2. Which one is more computation efficient? In terms of time & resources.

Maybe I am not getting this simple thing right due to not being a non-native English speaker.

Upvotes: 8

Views: 15561

Answers (2)

Niels
Niels

Reputation: 1481

After quite some debugging, found an equivalent implementation between cv2 and NumPy:

import numpy as np
import cv2

mask = np.array([[0,1,1],[0,1,1]])

coords = cv2.findNonZero(mask)

coords_numpy = np.argwhere(mask)
coords_numpy[:, [0, 1]] = coords_numpy[:, [1, 0]]
coords_numpy = np.expand_dims(coords_numpy, axis=1)

Upvotes: 0

Miki
Miki

Reputation: 41775

There is an error in the documentation:

Numpy gives coordinates in (row, column) format, while OpenCV gives coordinates in (x,y) format. So basically the answers will be interchanged. Note that, row = x and column = y. Note that, row = y and column = x.

So, regarding your questions:

  1. numpy returns (row,col) = (y,x), and OpenCV returns (x,y) = (col,row)

  2. You need to scan the whole matrix and retrieve some points. I don't think there will be any significant difference in performance (should be tested!).

    Since you're using Python, probably it's better to use Python facilities, e.g. numpy.

Runtime test comparing these two versions -

In [86]: mask = (np.random.rand(128,128)>0.5).astype(np.uint8)

In [87]: %timeit cv2.findNonZero(mask)
10000 loops, best of 3: 97.4 µs per loop

In [88]: %timeit np.nonzero(mask)
1000 loops, best of 3: 297 µs per loop

In [89]: mask = (np.random.rand(512,512)>0.5).astype(np.uint8)

In [90]: %timeit cv2.findNonZero(mask)
1000 loops, best of 3: 1.65 ms per loop

In [91]: %timeit np.nonzero(mask)
100 loops, best of 3: 4.8 ms per loop

In [92]: mask = (np.random.rand(1024,1024)>0.5).astype(np.uint8)

In [93]: %timeit cv2.findNonZero(mask)
100 loops, best of 3: 6.75 ms per loop

In [94]: %timeit np.nonzero(mask)
100 loops, best of 3: 19.4 ms per loop

Thus, it seems using OpenCV results in something around 3x speedup over the NumPy counterpart across varying datasizes.

Upvotes: 15

Related Questions