Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

numpy 2d array (coordinates) need to assign into 3D array, to some particular bin

I have the following code to compute HOG image with 8 bins and pre-counted Sobel X and Y filtered image:

for y in xrange(0, 480):
    for x in xrange(0, 640):
        base_angle = np.arctan2(sobel_Y[y,x], sobel_X[y,x]) * 180/np.pi
        if base_angle < 0: base_angle += 360
        angle = int(round(base_angle / 45))
        if angle == 8: angle = 0
        hog[y,x,angle] += np.sqrt(sobel_X[y,x]**2 + sobel_Y[y,x]**2)

I was trying to modify it to avoid loops:

base_angle = np.arctan2(sobel_Y, sobel_X) * 180/np.pi
base_angle[base_angle < 0] += 360
angle =(base_angle / 45).round().astype(np.uint8)
angle[angle == bins] = 0
hog[:,:,angle] += np.sqrt(sobel_X**2 + sobel_Y**2)

However, the last expression does not count correctly. What I basically need is to have the magnitude (np.sqrt... expression) being added to hog array according to index from angle array, at every (y,x) point of hog array. Any solutions?

like image 331
loknar Avatar asked Mar 21 '26 00:03

loknar


1 Answers

Use

magnitude = np.sqrt(sobel_X**2 + sobel_Y**2)
Y, X = np.ogrid[0:angle.shape[0], 0:angle.shape[1]]
hog[Y, X, angle] += magnitude

to update hog.


import numpy as np

def using_for_loop(hog, sobel_Y, sobel_X):
    for y in xrange(0, sobel_Y.shape[0]):
        for x in xrange(0, sobel_X.shape[1]):
            base_angle = np.arctan2(sobel_Y[y, x], sobel_X[y, x]) * 180 / np.pi
            if base_angle < 0:
                base_angle += 360
            angle = int(round(base_angle / 45))
            if angle == 8:
                angle = 0
            hog[y, x, angle] += np.sqrt(sobel_X[y, x] ** 2 +
                                        sobel_Y[y, x] ** 2)
    return hog

def using_indexing(hog, sobel_Y, sobel_X):
    base_angle = np.arctan2(sobel_Y, sobel_X) * 180 / np.pi
    base_angle[base_angle < 0] += 360
    angle = (base_angle / 45).round().astype(np.uint8)
    angle[angle == bins] = 0
    magnitude = np.sqrt(sobel_X ** 2 + sobel_Y ** 2)
    Y, X = np.ogrid[0:angle.shape[0], 0:angle.shape[1]]
    hog[Y, X, angle] += magnitude
    return hog

bins = 8
sobel_Y, sobel_X = np.meshgrid([1, 2, 3], [4, 5, 6, 7])
# hog = np.zeros(sobel_X.shape + (bins,))
hog = np.random.random(sobel_X.shape + (bins,))
answer = using_for_loop(hog, sobel_Y, sobel_X)
result = using_indexing(hog, sobel_Y, sobel_X)
assert np.allclose(answer, result)

Note that if

In [62]: angle.shape
Out[62]: (4, 3)

then

In [74]: hog[:,:,angle].shape
Out[74]: (4, 3, 4, 3)

That's not the right shape. Rather, if you define

In [75]: Y, X = np.ogrid[0:angle.shape[0], 0:angle.shape[1]]

then hog[Y, X, angle] has the same shape as magnitude:

In [76]: hog[Y, X, angle].shape
Out[76]: (4, 3)

In [77]: magnitude = np.sqrt(sobel_X ** 2 + sobel_Y ** 2)

In [78]: magnitude.shape
Out[78]: (4, 3)

Of course, that is not a proof that hog[Y, X, angle] is the correct expression, but it is the equivalent of a physicist's dimensionality check which shows we at least could be on the right track.


With NumPy fancy indexing, when Y, X, and angle all have the same shape (or broadcast to the same shape),

hog[Y, X, angle]

will also be of the same shape. The (i,j)th element in hog[Y, X, angle] will equal

hog[Y[i,j], X[i,j], angle[i,j]]

This is why hog[Y, X, angle] += magnitude works.

like image 91
unutbu Avatar answered Mar 22 '26 13:03

unutbu



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!