Efficient way to calculate angles of normals between to tensors

I have two images of normals. The target and the prediction (size: 3 x 224 x 224). An image is 224 * 224 pixels and each pixels has a x-, y- and z-component.

Now I want to compute the angle between each normal of the prediction and the target. So I go through the image pixel by pixel and calculate the angle between the normals at each pixel.

First I convert the image 3x224x224 -> 3 x 50176, so that I have a row of normals

Here’s my code:

for j in range(target.size()[1]):
   	angle = math.fabs(angle_between(prediction[:, j].data, target[:, j].data))

def angle_between(v1, v2):
    return np.arccos((v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]) / 
                 (math.sqrt(v1[0]*v1[0] + v1[1]*v1[1] + v1[2]*v1[2]) * 
                  math.sqrt(v2[0]*v2[0] + v2[1]*v2[1] + v2[2]*v2[2])))

This code works fine but is very slow. I heard that for-loops are quite slow in python.

I couldn’t find a solution so far to get rid of the for loop.

Do you have an idea how to increase the performance here? At the moment each image takes 13 sec. Which means for my 142200 images it would take ~21 days.

suppose variable a and b both with shape n * 3. then:

inner_product = (a * b).sum(dim=1)
a_norm = a.pow(2).sum(dim=1).pow(0.5)
b_norm = b.pow(2).sum(dim=1).pow(0.5)
cos = inner_product / (2 * a_norm * b_norm)
angle = torch.acos(cos)

Is it what you want ?

3 Likes

Thanks. That’s what I needed.

Use F.cosine_similarity and specify the axis where you have your normals. Will return 1 for similar, 0 different, -1 opposite

1 Like