Reputation: 785
I am trying to smooth scaled-up opencv contour segments. I am using smoothed splines and I would like to start and end the spline in actual data points. I am not too familiar with the interpolation and spline fitting terminology, so I do not really know what to search for.
What I would like to achieve is something similar to the red graph below, which is smoothed and I would like to start/end in the same points where the other graphs start and end. I do not mind that it does not pass through the remaining data points, I would rather control the amount of smoothing, but the start and end need to be fixed. Can this be achieved with scipy.interpolate
? Are there alternatives?
I found https://stackoverflow.com/a/47233842/4556546 which is used for the orange graph, which is pretty similar to the splprep
version with s=0
, i.e. interpolation, but this also uses s=0 so I do not see how it helps with smoothing.
I also found https://stackoverflow.com/a/32421626/4556546 where the coefficients are manipulated; again, I do not see how it helps achieving my goal. The coefficients resulting from splprep
with smoothing are already leading to the starting points of the red graph.
import numpy as np
from matplotlib import pyplot as plt
from scipy.interpolate import splprep, splev, make_interp_spline
border_segment = 16 * np.asarray([[[2, 8], [2, 9], [2, 10], [2, 11], [1, 12], [0, 13], [0, 14], [0, 15], [1, 16], [2, 17], [2, 18]]])
plt.scatter( border_segment[0].T[0], border_segment[0].T[1] )
# With smoothing s<>0
tck, u = splprep(border_segment[0].T, u=None, s=border_segment[0].shape[0]*16, per=0)
u_new = np.linspace(u.min(), u.max(), border_segment[0].shape[0]*16)
x_new, y_new = splev(u_new, tck, der=0)
plt.plot(x_new, y_new, color='red')
# With interpolation s=0
tck, u = splprep(border_segment[0].T, u=None, s=0.0, per=0)
x_new, y_new = splev(u_new, tck, der=0)
plt.plot(x_new, y_new, color='green')
# With boundary conditions, also see https://stackoverflow.com/a/47233842/4556546
l, r = [(1, (0, 0))], [(1, (0, 0))]
clamped_spline = make_interp_spline(u, np.array(border_segment[0].T).T, bc_type=(l, r))
x_new, y_new = clamped_spline(u_new).T
plt.plot(x_new, y_new, color='orange')
Upvotes: 2
Views: 1722
Reputation: 11
Did you try cv::approxPolyDP? It removes intermediate points depending on specified precision but leaves the start and end points unchanged. You get a simplified polyline and then you can draw a spline through its points.
Upvotes: 1
Reputation: 26030
Not out of the box.
You can try using the weights, w
to clip the spline at the endpoints. YMMV though.
Upvotes: 1