Нарисуйте объект в массиве в соответствии с вектором - PullRequest
0 голосов
/ 03 октября 2018

Цель:

Я пишу код для определения угла между двумя трехмерными векторами (достаточно просто).Однако векторы определяются в соответствии с выравниванием данных, выполненным в отдельной программе.Чтобы быть более точным, программа выравнивания берет объемы и выравнивает их в соответствии с общими характеристиками.Эти элементы представляют собой толстую белую линию с меньшей линией, выходящей из нее на очень шумном изображении в оттенках серого.

Используя маски, я выравниваю толстые и меньшие белые линии отдельно, а затем использую известные повороты, чтобы вернуть их обратно.в положение, в котором они были бы на исходных изображениях, и тогда я могу определить угол между ними (несколько тысяч изображений).

Текущая проблема:

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

Создание трехмерного массива с множеством случайных чисел в оттенках серого легко выполнить с помощью кода:

def RandomNoise():
NoiseArray = np.random.normal(0,1,(100,100,100))

return NoiseArray

Затем нужно каким-то образом вставить толстую белую линию, а затем белую поменьше.линия под случайным углом, идущая от его центра.Думаю, я мог бы добавить толстую белую линию в виде плоскости через все трехмерное пространство, которое остается в той же позиции.Я просто застрял в том, чтобы расположить тонкую белую линию под случайными углами.Я думал об определении его как вектора и применении к нему случайных вращений, записи вращений, а затем рендеринга в массиве в виде цилиндра, но я не знаю, как это сделать.

РЕДАКТИРОВАТЬ: вуточнить, что «толстая» белая линия - это, по сути, просто белая плоскость по всему трехмерному пространству в Z с определенной высотой по x и y (например, 20 пикселей в массиве 100 100 100).«Тонкая» белая линия - это цилиндр определенного радиуса (скажем, 10 пикселей в массиве 100 100 100), который я хочу вывести из белой плоскости под разными углами, поэтому он должен «поворачиваться» на одном конце на более толстой белой линии.

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

Буду признателен за любую помощь.

Спасибо

РЕДАКТИРОВАТЬ: запрошенный эскиз

enter image description here

1 Ответ

0 голосов
/ 03 октября 2018

Исходя из вашего вопроса, я не совсем уверен, как разные линии должны быть выровнены относительно друг друга, но я предоставлю вам следующий небольшой скрипт, который в любом случае должен послужить отправной точкой.Для поворота вы можете использовать rotate из пакета scipy.

import matplotlib.pyplot as plt
import numpy as np
from scipy.ndimage import rotate

np.random.seed(181003)

N = 100  # Number of images.
m, n = 100, 100  # row and column dimension.
test = np.random.uniform(0, 1, (N, m, n))

def create_bars(d):
    """Parameter d indicates thickness of the bar in number of rows"""
    bars = np.zeros((N, m, n), dtype=float)
    bars[:, m//2 - d : m//2 + d, :] = np.random.uniform(0.95, 1.0, (N, 2*d, n))
    for i, angle in enumerate(np.random.uniform(0, 180, N)):  # Angle in degrees.
        bars[i, :, :] = rotate(bars[i], angle, reshape=False)
    return bars

test += create_bars(m // 5)  # Thick bars.
test += create_bars(m // 25)  # Thin bars.

for i in range(3):
    plt.figure()
    plt.imshow(test[i])
plt.show()

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

Example

Редактировать на основе обновленияOP

Мы можем сгенерировать плоскость и цилиндр с помощью соответствующих индексов для трехмерного массива.Мы можем повернуть эти индексы, чтобы получить новые индексы для повернутых фигур (нам нужно отцентрировать индексы перед вращением, а затем снова сдвинуть назад).Вот пример кода:

"""Coordinate system is z, y, x for indexing the 3D array (i.e. test[z, y, x])."""

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def rotate_z(angle):
    return np.array([
        [1, 0, 0],
        [0, np.cos(angle), -np.sin(angle)],
        [0, np.sin(angle), np.cos(angle)],
    ])

def rotate_y(angle):
    return np.array([
        [np.cos(angle), 0, np.sin(angle)],
        [0, 1, 0],
        [-np.sin(angle), 0, np.cos(angle)],
    ])

def rotate_x(angle):
    return np.array([
        [np.cos(angle), -np.sin(angle), 0],
        [np.sin(angle), np.cos(angle), 0],
        [0, 0, 1],
    ])

l = m = n = 40  # Use only small number of points due to plotting.
test = np.random.uniform(0, 0.95, (l, m, n))

d = l // 10  # Thickness of plane.
i_thick = np.array([*np.ndindex(d, m, n)]).T  # Indices for plane.
i_thick[0, :] -= d // 2
i_thick[1, :] -= m // 2
i_thick[2, :] -= n // 2

angle_y = angle_x = 0  # Angles about which the plane is rotated.
i_thick = rotate_y(angle_y) @ i_thick
i_thick = rotate_x(angle_x) @ i_thick
i_thick[0, :] += d // 2 + l // 2
i_thick[1, :] += m // 2
i_thick[2, :] += n // 2
i_thick = np.clip(np.round(i_thick).astype(int), 0, np.array(test.shape)[:, None] - 1)  # Correct rounding errors.

test[i_thick.tolist()] = np.random.uniform(0.95, 1.0, i_thick.shape[1])  # Add the plane.

r = m // 8  # Radius of cylinder.
i_cylinder = np.array([*np.ndindex(l, m, n)])
i_cylinder = i_cylinder[
    (i_cylinder[:, 0] < l // 2)
    & (np.sqrt((i_cylinder[:, 1] - m // 2)**2 + (i_cylinder[:, 2] - n // 2)**2) < r)
].T
i_cylinder[0, :] -= l // 2
i_cylinder[1, :] -= m // 2
i_cylinder[2, :] -= n // 2

# Align cylinder with plane.
i_cylinder = rotate_y(angle_y) @ i_cylinder
i_cylinder = rotate_x(angle_x) @ i_cylinder

angle2_z = angle2_y = angle2_x = 0  # Angles about which the cylinder is rotated.
i_cylinder = rotate_z(angle2_z) @ i_cylinder
i_cylinder = rotate_y(angle2_y) @ i_cylinder
i_cylinder = rotate_x(angle2_x) @ i_cylinder

i_cylinder[0, :] += l // 2
i_cylinder[1, :] += m // 2
i_cylinder[2, :] += n // 2
i_cylinder = np.clip(np.round(i_cylinder).astype(int), 0, np.array(test.shape)[:, None] - 1)

test[i_cylinder.tolist()] = np.random.uniform(0.95, 1.0, i_cylinder.shape[1])

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
test_plot = test.copy()
test_plot = np.moveaxis(test_plot, [0, 1, 2], [-1, 0, 1])  # Reorder axes from `z, y, x` to `y, x, z` in order to be aligned with plt.scatter.
test_plot = np.flip(test_plot, axis=2)  # Flip along `z` in order to plot top-to-bottom rather than bottom-to-top.
ax.scatter(*np.array([*np.ndindex(m, n, l)]).T[:, test_plot.ravel() >= 0.95].tolist(), s=1)
ax.set_xlim([0, test.shape[1] - 1])
ax.set_ylim([0, test.shape[0] - 1])
ax.set_zlim([0, test.shape[2] - 1])
plt.show()

Например, обе фигуры не повернуты:

Example 3D no rotation

Другой пример для плоскости, вращающейся вокруг x на -pi/2 и цилиндр дополнительно вращается вокруг z и x на pi/8:

Example 3D with rotation

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