If you ever needed to parametrize a family of lines, you may have stumbled upon a discontinuity problem. When the slope of two consecutive lines in your discrete family change sign, it means that in the continuous family you're trying to fit, there is a vertical line somewhere inbetween. As you know, a vertical line has its slope and y-intercept both undefined, and if you were to plot them for the continuous family you would observe a singularity. So you can't use the slope-intercept form to parametrize your family of lines. Don't despair, here's a trick for you!
The problem
Let be a set of lines in the plane , which seem to obey a certain rule as progresses. For instance, , as compared to could be translated and rotated a bit, by some functions of . These lines are known by the values and of their slope and y-intercept respectively, so they all have the following slope-intercept form:
Moreover, the slope is unconstrained, and can very well change sign from one line to the next. We would like to find a smooth parametrization , such that each line is generated by a specific value of the parameter :
Then forms a continuous family of lines, and . Note that I will use the same symbol to refer to either the continuous family of lines, or the line generated by a given value of the parameter. The context will be sufficient to distinguish between both uses.
Solution
Obviously, as both the slope and the y-intercept of the line are discontinuous functions of , a very high-order series expansion would be needed to approximate and as functions of , if we were to use a slope-intercept form. But let’s not go there. The discontinuity, akin to coordinate singularities, originates from choosing this form in the first place, and can be removed by choosing a different one.
The Hesse normal form
When I began solving this problem, I remembered that the same singularity issue was circumvented by Duda and Hart in their implementation of the Hough transform, by the use of the Hessian normal form (see [1]). Any line admits two parameters and such that for every point the following equation must hold:
This is called the Hesse normal form, and is an alternative to the slope-intercept form to represent a line. A bit of algebraic manipulation gives:
Then, by identification of the coefficients, we deduce the following formulas to transform a Hesse normal form to a slope-intercept form and back:
Fitting
Using we can transform the pairs describing the lines into pairs parametrizing their respective Hesse normal forms:
Then, all is left to do is to fit the and using an -th order polynomial regression for example:
The values of the and are computed by the regression algorithm as functions of the and respectively. So we have the following continuous parametrization in Hesse normal form:
Then of course, we can go back to a slope-intercept form using , giving:
And as long as and are defined, we have the following parametrization in slope-intercept form:
The advantage of going down this route is that, because and are continuous functions of , there is a chance that only a low-order polynomial fit will be required to have good enough precision. So and , as functions of these two, will be good estimators by design, at a low cost.
Implementation
Let’s do this in Python, with numpy and matplotlib:
importnumpyasnpfrommatplotlibimportpyplotasplt
Suppose we have a function get_data() that returns a -tuple containing multiple values of the parameter , followed by the slopes and the y-intercepts of the lines for each value of . In the full code (link below), I implemented such a function featuring the same exact experimental data I was fiddling with when this parametrization problem first came up. I also added a bit of context for those of you who are interested! Now, let’s write two functions to convert coefficients from the slope-intercept form to coefficients of the Hesse normal form and vice versa:
These are direct implementations of and . And now, we can import some lines using the get_data() function mentioned above, convert them to Hessian form, fit polynomials on and , get our and and do some plotting:
defmain():s,a,b=get_data()# Fit the Hesse normal form parameters using 2nd order polynomials
r,theta=to_hesse_normal_form(a,b)r_coeffs=np.polyfit(s,r,2)theta_coeffs=np.polyfit(s,theta,2)r_fit=np.poly1d(r_coeffs)theta_fit=np.poly1d(theta_coeffs)# For multiple values of the parameter s, calculate slope and y-intercept
sp=np.linspace(np.min(s),np.max(s),100)a_fit,b_fit=to_slope_intercept_form(r_fit(sp),theta_fit(sp))# Plot stuff
# ...
Finally we can plot our fits. The code for this task is a bit lengthy so it was omitted, but you can check the full source code if needed.
Notice how -given the data that I use- only second order polynomials suffice to capture the dependency in of both and . There is no way a second order would be enough if we were to fit and directly! The discontinuity of and is quite visible, but was captured effortlessly by this method. Let’s also display a few lines of our smooth parametrized family , together with the original lines :
That’s pretty convincing, if I may say so myself! So it appears you can use this method to interpolate between lines of a discrete set… My Google-fu is not so strong, but the only similar result I could find was this article on Cross-Linear Interpolation, so I guess that’s the name of the problem we solved here? It seems elementary enough that a myriad of applications could exist, but I’m quite the unimaginative type as far as applications go. Maybe you have some ideas to share?
The comment section requires the Utterances cookie in order to work properly.
If you want to see people's comments or post a comment yourself,
please enable the Utterances cookie here.