Как создать сферу внутри ndarray питона? - PullRequest
0 голосов
/ 15 ноября 2018

У меня размер ndarray 32x32x32.Я хочу создать сферу внутри массива с центром в (х, у) и радиусом 4 пикселя.Значение сферы равно 1, а значение массива равно 0. Как я могу сделать это в Python?Большое спасибо

Это код для генерации массива

import numpy as np
A = np.zeros((32,32,32))
print (A)

Ответы [ 4 ]

0 голосов
/ 09 мая 2019

Ничто из вышеперечисленного не сработало для меня, поэтому есть моя попытка:

def create_bin_sphere(arr_size, center, r):
    coords = np.ogrid[:arr_size[0], :arr_size[1], :arr_size[2]]
    distance = np.sqrt((coords[0] - center[0])**2 + (coords[1]-center[1])**2 + (coords[2]-center[2])**2) 
    return 1*(distance <= r)

, где:

  • arr_size - это кортеж с формой массива
  • центркортеж с координатами центра сферы
  • r - радиус сферы

Пример:

arr_size = (30,30,30)
sphere_center = (15,15,15)
r=10
sphere = create_bin_sphere(arr_size,sphere_center, r)

#Plot the result
fig =plt.figure(figsize=(6,6))
ax = fig.gca(projection='3d')
ax.voxels(sphere, facecolors=colors, edgecolor='k')
plt.show()

Результат визуализации

0 голосов
/ 16 ноября 2018

Поскольку индексы массива имеют только определенный уровень специфичности (т. Е. Вы можете разделить только до ширины, в данном случае 32), не существует единого идеального способа представления сферы в массиве.Вместо этого мы можем рассматривать каждый индекс массива как пространство кубической области, где индексы [x][y][z] индекса представляют координаты центра кубической области.Чтобы создать сферу, мы оцениваем, соответствует ли присутствие сферы в этой области пространства определенным критериям.

Начнем с уравнения для сферы.От Википедия :

В аналитической геометрии сфера с центром ( x0 , y0 , z0 ) и радиус r - это местоположение всех точек ( x , y , z ), таких что

( x - x0 ) ^ 2 + ( y - y0 ) ^ 2 + ( z - z0 ) ^ 2 <= <em>r ^ 2.

Для массива измерений N центр будет иметь координату (N - 1) / 2 длявсе размеры.(поскольку для измерения с четным номером центр должен находиться между двумя центральными точками, а для измерения с нечетным номером центр должен быть целым числом.) Величина радиуса может варьироваться в зависимости от того, где вы определяете границысфера относительно нашего воображаемого представления кубического массива;перечитывая вопрос, я замечаю, что вы уже дали желаемый радиус: 4.

Есть два критерия оценки, о которых я могу думать:

Простой подход

В этом подходе, мы просто воспользуемся проверкой того, находится ли центр кубической области индекса массива в уравнении окружности.

Вы можете увидеть ответ Сиддхарта Сатпати для некоторого кода, использующего этот подход.

Сложный подход

В идеале для меня уравнение решит, находится ли индекс в сфере, путем оценки, превышает ли доля сферы для этой кубической области более 50%.Тем не менее, этот подход, к сожалению, выходит за рамки моих текущих рабочих математических знаний.


Что касается обсуждения, которое я провел в комментариях, ни один подход не лучше, чем другой, поскольку они представляют разные точки зрения: я лично представляюмассив фактически представляет кубическую область для каждого индекса, тогда как другие могут представить, что индексы являются центральными точками этих кубических областей.

0 голосов
/ 16 ноября 2018

Используя комбинацию индексации, вычисления расстояния и маскирования (все с numpy):

import numpy as np
center = (31/2, 31/2, 31/2)  # if it is centered
size = (32, 32, 32)
max_dist = 4
distance = np.linalg.norm(np.subtract(np.indices(size).T, np.asarray(center)), axis=2)
#print(distance)
mask = np.ones(size) * (distance < max_dist)
print(mask)

np.indices создает индекс в виде [[[(i, j, k)]]], np.substract вычисляет векторную разницук вашему центру, и np.linalg.norm вычисляет векторную норму.Остальное - просто использование операции маски на массиве расстояний.

Это работает?

РЕДАКТИРОВАТЬ: пример с (3,3,3) для ясности

center = (1, 1, 1)
size = (3, 3, 3)
distance = np.linalg.norm(np.subtract(np.indices(size).T,np.asarray(center)), axis=len(center))
mask = np.ones(size) * (distance<=1)
print(mask)

>>[[[0. 0. 0.]
  [0. 1. 0.]
  [0. 0. 0.]]

 [[0. 1. 0.]
  [1. 1. 1.]
  [0. 1. 0.]]

 [[0. 0. 0.]
  [0. 1. 0.]
  [0. 0. 0.]]]
0 голосов
/ 16 ноября 2018

Очень хороший вопрос. Вы можете попробовать следующий код. В приведенном ниже коде AA это матрица, которую вы хотите. =) * * Тысяча два

import numpy as np
from copy import deepcopy

''' size : size of original 3D numpy matrix A.
    radius : radius of circle inside A which will be filled with ones. 
'''
size, radius = 5, 2

''' A : numpy.ndarray of shape size*size*size. '''
A = np.zeros((size,size, size)) 

''' AA : copy of A (you don't want the original copy of A to be overwritten.) '''
AA = deepcopy(A) 

''' (x0, y0, z0) : coordinates of center of circle inside A. '''
x0, y0, z0 = int(np.floor(A.shape[0]/2)), \
        int(np.floor(A.shape[1]/2)), int(np.floor(A.shape[2]/2))


for x in range(x0-radius, x0+radius+1):
    for y in range(y0-radius, y0+radius+1):
        for z in range(z0-radius, z0+radius+1):
            ''' deb: measures how far a coordinate in A is far from the center. 
                    deb>=0: inside the sphere.
                    deb<0: outside the sphere.'''   
            deb = radius - abs(x0-x) - abs(y0-y) - abs(z0-z) 
            if (deb)>=0: AA[x,y,z] = 1

Ниже приведен пример вывода для size=5 и radius=2 (сфера с радиусом 2 пикселей внутри массива фигуры 5*5*5):

[[[0. 0. 0. 0. 0.]
  [0. 0. 0. 0. 0.]
  [0. 0. 1. 0. 0.]
  [0. 0. 0. 0. 0.]
  [0. 0. 0. 0. 0.]]

 [[0. 0. 0. 0. 0.]
  [0. 0. 1. 0. 0.]
  [0. 1. 1. 1. 0.]
  [0. 0. 1. 0. 0.]
  [0. 0. 0. 0. 0.]]

 [[0. 0. 1. 0. 0.]
  [0. 1. 1. 1. 0.]
  [1. 1. 1. 1. 1.]
  [0. 1. 1. 1. 0.]
  [0. 0. 1. 0. 0.]]

 [[0. 0. 0. 0. 0.]
  [0. 0. 1. 0. 0.]
  [0. 1. 1. 1. 0.]
  [0. 0. 1. 0. 0.]
  [0. 0. 0. 0. 0.]]

 [[0. 0. 0. 0. 0.]
  [0. 0. 0. 0. 0.]
  [0. 0. 1. 0. 0.]
  [0. 0. 0. 0. 0.]
  [0. 0. 0. 0. 0.]]]

Я не напечатал вывод для размера и радиуса, которые вы просили (size=32 и radius=4), так как вывод будет очень длинным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...