Alexandru Dinu
Alexandru Dinu

Reputation: 1267

Vectorizing python code to numpy

I have the following code snippet (for Hough circle transform):

for r in range(1, 11):
    for t in range(0, 360):
        trad = np.deg2rad(t)

        b = x - r * np.cos(trad)
        a = y - r * np.sin(trad)

        b = np.floor(b).astype('int')
        a = np.floor(a).astype('int')

        A[a, b, r-1] += 1

Where A is a 3D array of shape (height, width, 10), and height and width represent the size of a given image. My goal is to convert the snippet exclusively to numpy code.

My attempt is this:

arr_r = np.arange(1, 11)
arr_t = np.deg2rad(np.arange(0, 360))

arr_cos_t = np.cos(arr_t)
arr_sin_t = np.sin(arr_t)

arr_rcos = arr_r[..., np.newaxis] * arr_cos_t[np.newaxis, ...]
arr_rsin = arr_r[..., np.newaxis] * arr_sin_t[np.newaxis, ...]

arr_a = (y - arr_rsin).flatten().astype('int')
arr_b = (x - arr_rcos).flatten().astype('int')

Where x and y are two scalar values.

I am having trouble at converting the increment part: A[a,b,r] += 1. I thought of this: A[a,b,r] counts the number of occurrences of the pair (a,b,r), so a clue was to use a Cartesian product (but the arrays are too large).

Any tips or tricks I can use?

Thank you very much!

Edit: after filling A, I need (a,b,r) as argmax(A). The tuple (a,b,r) identifies a circle and its value in A represents the confidence value. So I want that tuple with the highest value in A. This is part of the voting algorithm from Hough circle transform: find circle parameter with unknown radius.

Upvotes: 2

Views: 124

Answers (2)

Thomas
Thomas

Reputation: 1066

np.add(np.array ([arr_a, arr_b, 10]), 1)

Upvotes: 2

Divakar
Divakar

Reputation: 221504

Method #1

Here's one way leveraging broadcasting to get the counts and update A (this assumes the a and b values computed in the intermediate steps are positive ones) -

d0,d1,d2 = A.shape    
arr_r = np.arange(1, 11)
arr_t = np.deg2rad(np.arange(0, 360))

arr_b = np.floor(x - arr_r[:,None] * np.cos(arr_t)).astype('int')
arr_a = np.floor(y - arr_r[:,None] * np.sin(arr_t)).astype('int')

idx = (arr_a*d1*d2) + (arr_b * d2) + (arr_r-1)[:,None]

A.flat[:idx.max()+1] += np.bincount(idx.ravel())
# OR A.flat += np.bincount(idx.ravel(), minlength=A.size)

Method #2

Alternatively, we could avoid bincount to replace the last step in approach #1, like so -

idx.ravel().sort()
idx.shape = (-1)
grp_idx = np.flatnonzero(np.concatenate(([True], idx[1:]!=idx[:-1],[True])))
A.flat[idx[grp_idx[:-1]]] += np.diff(grp_idx)

Improvement with numexpr

We could also leverage numexpr module for faster sine, cosine computations, like so -

import numexpr as ne

arr_r2D = arr_r[:,None]
arr_b = ne.evaluate('floor(x - arr_r2D * cos(arr_t))').astype(int)
arr_a = ne.evaluate('floor(y - arr_r2D * sin(arr_t))').astype(int)

Upvotes: 3

Related Questions