1

I am trying to generate a 3D matrix with a tube structure running through it. I can make the tube straight by copying a 2D numpy array with a circle centered at (x,y) inside, and I can make the tube slanted by adding an int to either the x or y axis for each slice I generate. My question is, how can I move the (x,y) coordinates so that they can form a curve? I can't add step sizes of curved functions like sine and cosine to the coordinates since to index the numpy array it must be an integer. What is a smart way to generate a curved tube from 2D slices by shifting the center coordinates?

Here is the code I am using to generate a straight tube as a 3D matrix:

import numpy as np 
import cv2
import matplotlib.pyplot as plt

slice_2d = np.zeros((128,128))
circle_center = (50,50)
radius=10

slice_2d = cv2.circle(slice_2d, circle_center, radius, color=1, thickness=-1)
plt.imshow(slice_2d)

# then we repeat the slice 128 times to create a straight tube in a 3D matrix of 128,128,128
tube_matrix = []
for i in range(0,128):
    tube_matrix.append(slice_2d)

tube_matrix = np.array(tube_matrix)
Michael S.
  • 3,050
  • 4
  • 19
  • 34
accAscrub
  • 609
  • 1
  • 6
  • 11
  • A picture would help us understand what you desire to do. Post to some free hosting service and put the URL here if you are not able to add an image directly here. – fmw42 Mar 12 '20 at 19:09

1 Answers1

1

You may use any curve, scale and add offset as needed, and round the center coordinates to integer.

I used the curve for this post.

Here is the loop that adds the slices:

tube_matrix = []
for i in range(128):    
    circle_center = np.round(curve[i]*12 + 15).astype(int)
    slice_2d = cv2.circle(np.zeros((128,128)), tuple(circle_center), radius, color=1, thickness=-1)
    tube_matrix.append(slice_2d)

Each iteration the circle center changes according to the value of curve[i].
Note that curve[i] is scaled and rounded (and converted to int).


Here is the complete code (with some testing code):

import numpy as np
import cv2
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt

# https://stackoverflow.com/questions/52014197/how-to-interpolate-a-2d-curve-in-python
# Define some points:
points = np.array([[0, 1, 8, 2, 2],
                   [1, 0, 6, 7, 2]]).T  # a (nbre_points x nbre_dim) array

# Linear length along the line:
distance = np.cumsum( np.sqrt(np.sum( np.diff(points, axis=0)**2, axis=1 )) )
distance = np.insert(distance, 0, 0)/distance[-1]

alpha = np.linspace(0, 1, 128)

method = 'cubic'   
interpolator =  interp1d(distance, points, kind=method, axis=0)
curve = interpolator(alpha)

#slice_2d = np.zeros((128,128))
#circle_center = (30, 30)
img = np.zeros((128, 128, 3), np.uint8) + 255
radius = 10

tube_matrix = []
for i in range(128):    
    circle_center = np.round(curve[i]*12 + 15).astype(int)
    slice_2d = cv2.circle(np.zeros((128,128)), tuple(circle_center), radius, color=1, thickness=-1)
    tube_matrix.append(slice_2d)

    #Draw cicle on image - for testing
    img = cv2.circle(img, tuple(circle_center), radius, color=(i*10 % 255, i*20 % 255, i*30 % 255), thickness=2)

# Graph:
plt.figure(figsize=(7,7))
plt.plot(*curve.T, 'o')
plt.axis('equal'); plt.legend(); plt.xlabel('x'); plt.ylabel('y')

plt.figure(figsize=(7,7))
plt.imshow(img)
plt.show()

Testing image (img):
enter image description here

Rotem
  • 30,366
  • 4
  • 32
  • 65