In python numpy array, how to know which object is nearer to one point in one image?

238 views Asked by At

I have a numpy array, which respresents an image. The image has 3 colors: orange (background), blue (object1) and green (object2). I use 3 values (0, 1 and 2) to indicate the 3 colors in numpy array. Two objects are not overlapped.

My question is: How do know which object is nearer to the center (red point) of the image? (Here, nearer means the nearest distance from the object to the center of the image of one object is smaller than the nearest distance from the object to the center of the image of the otehr object)

My code is like this:

import numpy as np
from scipy import spatial
import time

sub_image1 = np.ones((30, 30, 30))
sub_image2 = np.ones((20, 10, 15))

# pad the two sub_images to same shape (1200, 1200, 1200) to simulate my 3D medical data
img_1 = np.pad(sub_image1, ((1100, 70), (1100, 70), (1100, 70)))
img_2 = np.pad(sub_image1, ((1100, 80), (1130, 60), (1170, 15)))

def nerest_dis_to_center(img):
    position = np.where(img > 0)
    coordinates = np.transpose(np.array(position))  # get the coordinates where the voxels is not 0
    cposition = np.array(img.shape) / 2  # center point position/coordinate
    distance, index = spatial.KDTree(coordinates).query(cposition)
    return distance

t1 = time.time()
d1 = nerest_dis_to_center(img_1)
d2 = nerest_dis_to_center(img_2)

if d1 > d2:
    print("img2 object is nearer")
elif d2 > d1:
    print("img1 object is nearer")
else:
    print("They are the same far")
t2 = time.time()
print("used time: ", t2-t1)
# 30 seconds

The above code works, but slowly and it requires very big memory (about 30 GB). If you want to reproduce my code in your PC, you can use a smaller shape instead of (3200, 1200, 1200). Is there any more efficient way to achieve my goal?

Note: Actually my image is a 3D CT medical image, it is too big to be uploaded. The objects in the image is random, may be convex or not. That is why my implimentation is far slowly. Here in order to clarify my question, I use the 2D image to explain my method.

Figure

2

There are 2 answers

0
Jingnan Jia On BEST ANSWER

I solved this issue.

Because the two 3D arrays are too big. So at first I down sample them to a smaller size with nearest neighbor method. then continue:

import numpy as np
from scipy import spatial
import time

sub_image1 = np.ones((30, 30, 30))
sub_image2 = np.ones((20, 10, 15))

# pad the two sub_images to same shape (1200, 1200, 1200) to simulate my 3D medical data
img_1 = np.pad(sub_image1, ((1100, 70), (1100, 70), (1100, 70)))
img_2 = np.pad(sub_image1, ((1100, 80), (1130, 60), (1170, 15)))

ori_sz = np.array(img_1.shape)
trgt_sz = ori_sz / 4
zoom_seq = np.array(trgt_sz, dtype='float') / np.array(ori_sz, dtype='float')
img_1 = ndimage.interpolation.zoom(img_1, zoom_seq, order=0, prefilter=0)
img_2 = ndimage.interpolation.zoom(img_2, zoom_seq, order=0, prefilter=0)
print("it cost this secons to downsample the nearer image" + str(time.time() - t0))  # 0.8 seconds


def nerest_dis_to_center(img):
    position = np.where(img > 0)
    coordinates = np.transpose(np.array(position))  # get the coordinates where the voxels is not 0
    cposition = np.array(img.shape) / 2  # center point position/coordinate
    distance, index = spatial.KDTree(coordinates).query(cposition)
    return distance

t1 = time.time()
d1 = nerest_dis_to_center(img_1)
d2 = nerest_dis_to_center(img_2)

if d1 > d2:
    print("img2 object is nearer")
elif d2 > d1:
    print("img1 object is nearer")
else:
    print("They are the same far")
t2 = time.time()
print("used time: ", t2-t1)
# 1.1 seconds

3
sai On

This might not be the final solution or the most optimal w.r.t time, have to test it with the actual data. To get my idea through I have chosen smaller matrix sizes and only 2D case

import numpy as np
import matplotlib.pyplot as plt


sub_image1 = np.ones((30, 30))  # 1st object
sub_image2 = np.ones((20, 10)) * 2  # 2nd object

# pad the two sub_images to same shape (120, 120)
img_1 = np.pad(sub_image1, ((110, 60), (60, 110)))
img_2 = np.pad(sub_image2, ((100, 80), (130, 60)))

final_image = img_1 + img_2  # creating final image with both objects in a background of zeros

image_center = (np.array([final_image.shape[0], final_image.shape[1]]) / 2).astype(np.int)

# mark the center
final_image[image_center[0], image_center[1]] = 10

# find the coordinates of where the objects are
first_obj_coords = np.argwhere(final_image == 1)  # could be the most time consuming operation
second_obj_coords = np.argwhere(final_image == 2) # could be the most time consuming 

# find their centers
first_obj_ctr = np.mean(first_obj_coords, axis=0)
second_obj_ctr = np.mean(second_obj_coords, axis=0)

# turn the centers to int for using them to index
first_obj_ctr = np.floor(first_obj_ctr).astype(int)
second_obj_ctr = np.floor(second_obj_ctr).astype(int)

# mark the centers of the objects
final_image[first_obj_ctr[0], first_obj_ctr[1]] = 10
final_image[second_obj_ctr[0], second_obj_ctr[1]] = 10

# calculate the distances from center to the object center
print('Distance to first object: ', np.linalg.norm(image_center - first_obj_ctr))
print('Distance to second object: ', np.linalg.norm(image_center - second_obj_ctr))

plt.imshow(final_image)
plt.show()

Output

Distance to first object:  35.38361202590826
Distance to second object:  35.17101079013795

enter image description here