Issue
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 centre 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)
Solution
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()
Answered By - Rotem
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.