Linear interpolation code on wikipedia - I don't understand it - c++

I'm reading the following code (taken from here)
void linear_interpolation_CPU(float2* result, float2* data,
float* x_out, int M, int N) {
float a;
for(int j = 0; j < N; j++) {
int k = floorf(x_out[j]);
a = x_out[j] - floorf(x_out[j]);
result[j].x = a*data[k+1].x + (-data[k].x*a + data[k].x);
result[j].y = a*data[k+1].y + (-data[k].y*a + data[k].y);
}
}
but I don't get it.
Why isn't the result[y] calculated by using the
formula?

It is calculated that way.
Look at the first two lines:
int k = floorf(x_out[j]);
a = x_out[j] - floorf(x_out[j]);
The first line defines x0 using the floor function. This is because the article assumes a lattice spacing of one for the sample points, as per the line:
the samples are obtained on the 0,1,...,M lattice
Now we could rewrite the second line for clarity as:
a = x_out[j] - k;
The second line is therefore x-x0.
Now, let us examine the equation:
result[j].y = a*data[k+1].y + (-data[k].y*a + data[k].y);
Rewriting this in terms of y, x, and x0 gives:
y = (x-x0)*data[k+1].y + (-data[k].y*(x-x0) + data[k].y);
Let's rename data[k+1].y as y1 and data[k].y as y0:
y = (x-x0)*y1 + (-y0*(x-x0) + y0);
Let's rearrange this by pulling out x-x0:
y = (x-x0)*(y1-y0) + y0;
And rearrange again:
y = y0 + (y1-y0)*(x-x0);
Again, the lattice spacing is important:
the samples are obtained on the 0,1,...,M lattice
Thus, x1-x0 is always 1. If we put it back in, we get
y = y0 + (y1-y0)*(x-x0)/(x1-x0);
Which is just the equation you were looking for.
Granted, it's ridiculous that the code is not written so as to make that apparent.

Related

Intersection of ray and ellipsoid

Yes, I know that it is a popular problem. But I found nowhere the full clear implementing code without using OpenGL classes or a lot of headers files.
Okay, the math solution is to transfer ellipsoid to sphere. Then find intersections dots (if they exist of course) and make inverse transformation. Because affine transformation respect intersection.
But I have difficulties when trying to implement this.
I tried something for sphere but it is completely incorrect.
double CountDelta(Point X, Point Y, Sphere S)
{
double a = 0.0;
for(int i = 0; i < 3; i++){
a += (Y._coordinates[i] - X._coordinates[i]) * (Y._coordinates[i] - X._coordinates[i]);
}
double b = 0.0;
for(int i = 0; i < 3; i++)
b += (Y._coordinates[i] - X._coordinates[i]) * (X._coordinates[i] - S._coordinates[i]);
b *= 2;
double c = - S.r * S.r;
for(int i = 0; i < 3; i++)
c += (X._coordinates[i] - S._coordinates[i]) * (X._coordinates[i] - S._coordinates[i]);
return b * b - 4 * a * c;
}
Let I have start point P = (Px, Py, Pz), direction V = (Vx, Vy, Vz), ellipsoid = (Ex, Ey, Ec) and (a, b, c). How to construct clear code?
Let a line from P to P + D intersecting a sphere of center C and radius R.
WLOG, C can be the origin and R unit (otherwise translate by -C and scale by 1/R). Now using the parametric equation of the line and the implicit equation of the sphere,
(Px + t Dx)² + (Py + t Dy)² + (Pz + t Dz)² = 1
or
(Dx² + Dy² + Dz²) t² + 2 (Dx Px + Dy Py + Dz Pz) t + Px² + Py² + Pz² - 1 = 0
(Vectorially, D² t² + 2 D P t + P² - 1 = 0 and t = (- D P ±√((D P)² - D²(P² - 1))) / D².)
Solve this quadratic equation for t and get the two intersections as P + t D. (Don't forget to invert the initial transformations.)
For the ellipsoid, you can either plug the parametric equation of the line directly into the implicit equation of the conic, or reduce the conic (and the points simultaneously) and plug in the reduced equation.

Normalizing 2D lines in Eigen C++

A line in the 2D plane can be represented with the implicit equation
f(x,y) = a*x + b*y + c = 0
= dot((a,b,c),(x,y,1))
If a^2 + b^2 = 1, then f is considered normalized and f(x,y) gives you the Euclidean (signed) distance to the line.
Say you are given a 3xK matrix (in Eigen) where each column represents a line:
Eigen::Matrix<float,3,Eigen::Dynamic> lines;
and you wish to normalize all K lines. Currently I do this a follows:
for (size_t i = 0; i < K; i++) { // for each column
const float s = lines.block(0,i,2,1).norm(); // s = sqrt(a^2 + b^2)
lines.col(i) /= s; // (a, b, c) /= s
}
I know there must be a more clever and efficient method for this that does not require looping. Any ideas?
EDIT: The following turns out being slower for optimized code... hmmm..
Eigen::VectorXf scales = lines.block(0,0,2,K).colwise().norm().cwiseInverse()
lines *= scales.asDiagonal()
I assume that this as something to do with creating KxK matrix scales.asDiagonal().
P.S. I could use Eigen::Hyperplane somehow, but the docs seem little opaque.

interior angles of irregular polygon with angles > 180

I'm trying to calculate the values shown in the picture in red i.e. the interior angles.
I've got an array of the points where lines intersect and have tried using the dot-product but it only returns the smallest angles. I need the full range of internal angles (0-359) but can't seem to find much that meets this criteria.
Assuming your angles are in standard counterclockwise format, the following should work:
void angles(double points[][2], double angles[], int npoints){
for(int i = 0; i < npoints; i++){
int last = (i - 1 + npoints) % npoints;
int next = (i + 1) % npoints;
double x1 = points[i][0] - points[last][0];
double y1 = points[i][1] - points[last][1];
double x2 = points[next][0] - points[i][0];
double y2 = points[next][1] - points[i][1];
double theta1 = atan2(y1, x1)*180/3.1415926358979323;
double theta2 = atan2(y2, x2)*180/3.1415926358979323;
angles[i] = (180 + theta1 - theta2 + 360);
while(angles[i]>360)angles[i]-=360;
}
}
Obviously, if you are using some sort of data structure for your points, you will want to replace double points[][2] and references to it with references to your data structure.
You can obtain full angle range (-Pi..Pi) with atan2 function:
atan2(crossproduct, dotproduct)

How to fit the 2D scatter data with a line with C++

I used to work with MATLAB, and for the question I raised I can use p = polyfit(x,y,1) to estimate the best fit line for the scatter data in a plate. I was wondering which resources I can rely on to implement the line fitting algorithm with C++. I understand there are a lot of algorithms for this subject, and for me I expect the algorithm should be fast and meantime it can obtain the comparable accuracy of polyfit function in MATLAB.
This page describes the algorithm easier than Wikipedia, without extra steps to calculate the means etc. : http://faculty.cs.niu.edu/~hutchins/csci230/best-fit.htm . Almost quoted from there, in C++ it's:
#include <vector>
#include <cmath>
struct Point {
double _x, _y;
};
struct Line {
double _slope, _yInt;
double getYforX(double x) {
return _slope*x + _yInt;
}
// Construct line from points
bool fitPoints(const std::vector<Point> &pts) {
int nPoints = pts.size();
if( nPoints < 2 ) {
// Fail: infinitely many lines passing through this single point
return false;
}
double sumX=0, sumY=0, sumXY=0, sumX2=0;
for(int i=0; i<nPoints; i++) {
sumX += pts[i]._x;
sumY += pts[i]._y;
sumXY += pts[i]._x * pts[i]._y;
sumX2 += pts[i]._x * pts[i]._x;
}
double xMean = sumX / nPoints;
double yMean = sumY / nPoints;
double denominator = sumX2 - sumX * xMean;
// You can tune the eps (1e-7) below for your specific task
if( std::fabs(denominator) < 1e-7 ) {
// Fail: it seems a vertical line
return false;
}
_slope = (sumXY - sumX * yMean) / denominator;
_yInt = yMean - _slope * xMean;
return true;
}
};
Please, be aware that both this algorithm and the algorithm from Wikipedia ( http://en.wikipedia.org/wiki/Simple_linear_regression#Fitting_the_regression_line ) fail in case the "best" description of points is a vertical line. They fail because they use
y = k*x + b
line equation which intrinsically is not capable to describe vertical lines. If you want to cover also the cases when data points are "best" described by vertical lines, you need a line fitting algorithm which uses
A*x + B*y + C = 0
line equation. You can still modify the current algorithm to produce that equation:
y = k*x + b <=>
y - k*x - b = 0 <=>
B=1, A=-k, C=-b
In terms of the above code:
B=1, A=-_slope, C=-_yInt
And in "then" block of the if checking for denominator equal to 0, instead of // Fail: it seems a vertical line, produce the following line equation:
x = xMean <=>
x - xMean = 0 <=>
A=1, B=0, C=-xMean
I've just noticed that the original article I was referring to has been deleted. And this web page proposes a little different formula for line fitting: http://hotmath.com/hotmath_help/topics/line-of-best-fit.html
double denominator = sumX2 - 2 * sumX * xMean + nPoints * xMean * xMean;
...
_slope = (sumXY - sumY*xMean - sumX * yMean + nPoints * xMean * yMean) / denominator;
The formulas are identical because nPoints*xMean == sumX and nPoints*xMean*yMean == sumX * yMean == sumY * xMean.
I would suggest coding it from scratch. It is a very simple implementation in C++. You can code up both the intercept and gradient for least-squares fit (the same method as polyfit) from your data directly from the formulas here
http://en.wikipedia.org/wiki/Simple_linear_regression#Fitting_the_regression_line
These are closed form formulas that you can easily evaluate yourself using loops. If you were using higher degree fits then I would suggest a matrix library or more sophisticated algorithms but for simple linear regression as you describe above this is all you need. Matrices and linear algebra routines would be overkill for such a problem (in my opinion).
Equation of line is Ax + By + C=0.
So it can be easily( when B is not so close to zero ) convert to y = (-A/B)*x + (-C/B)
typedef double scalar_type;
typedef std::array< scalar_type, 2 > point_type;
typedef std::vector< point_type > cloud_type;
bool fit( scalar_type & A, scalar_type & B, scalar_type & C, cloud_type const& cloud )
{
if( cloud.size() < 2 ){ return false; }
scalar_type X=0, Y=0, XY=0, X2=0, Y2=0;
for( auto const& point: cloud )
{ // Do all calculation symmetric regarding X and Y
X += point[0];
Y += point[1];
XY += point[0] * point[1];
X2 += point[0] * point[0];
Y2 += point[1] * point[1];
}
X /= cloud.size();
Y /= cloud.size();
XY /= cloud.size();
X2 /= cloud.size();
Y2 /= cloud.size();
A = - ( XY - X * Y ); //!< Common for both solution
scalar_type Bx = X2 - X * X;
scalar_type By = Y2 - Y * Y;
if( fabs( Bx ) < fabs( By ) ) //!< Test verticality/horizontality
{ // Line is more Vertical.
B = By;
std::swap(A,B);
}
else
{ // Line is more Horizontal.
// Classical solution, when we expect more horizontal-like line
B = Bx;
}
C = - ( A * X + B * Y );
//Optional normalization:
// scalar_type D = sqrt( A*A + B*B );
// A /= D;
// B /= D;
// C /= D;
return true;
}
You can also use or go over this implementation there is also documentation here.
Fitting a Line can be acomplished in different ways.
Least Square means minimizing the sum of the squared distance.
But you could take another cost function as example the (not squared) distance. But normaly you use the squred distance (Least Square).
There is also a possibility to define the distance in different ways. Normaly you just use the "y"-axis for the distance. But you could also use the total/orthogonal distance. There the distance is calculated in x- and y-direction. This can be a better fit if you have also errors in x direction (let it be the time of measurment) and you didn't start the measurment on the exact time you saved in the data. For Least Square and Total Least Square Line fit exist algorithms in closed form. So if you fitted with one of those you will get the line with the minimal sum of the squared distance to the datapoints. You can't fit a better line in the sence of your defenition. You could just change the definition as examples taking another cost function or defining distance in another way.
There is a lot of stuff about fitting models into data you could think of, but normaly they all use the "Least Square Line Fit" and you should be fine most times. But if you have a special case it can be necessary to think about what your doing. Taking Least Square done in maybe a few minutes. Thinking about what Method fits you best to the problem envolves understanding the math, which can take indefinit time :-).
Note: This answer is NOT AN ANSWER TO THIS QUESTION but to this one "Line closest to a set of points" that has been flagged as "duplicate" of this one (incorrectly in my opinion), no way to add new answers to it.
The question asks for:
Find the line whose distance from all the points is minimum ? By
distance I mean the shortest distance between the point and the line.
The most usual interpretation of distance "between the point and the line" is the euclidean distance and the most common interpretation of "from all points" is the sum of distances (in absolute or squared value).
When the target is minimize the sum of squared euclidean distances, the linear regression (LST) is not the algorithm to use. In addition, linear regression can not result in a vertical line. The algorithm to be used is the "total least squares". See by example wikipedia for the problem description and this answer in math stack exchange for details about the formulation.
to fit a line y=param[0]x+param[1] simply do this:
// loop over data:
{
sum_x += x[i];
sum_y += y[i];
sum_xy += x[i] * y[i];
sum_x2 += x[i] * x[i];
}
// means
double mean_x = sum_x / ninliers;
double mean_y = sum_y / ninliers;
float varx = sum_x2 - sum_x * mean_x;
float cov = sum_xy - sum_x * mean_y;
// check for zero varx
param[0] = cov / varx;
param[1] = mean_y - param[0] * mean_x;
More on the topic http://easycalculation.com/statistics/learn-regression.php
(formulas are the same, they just multiplied and divided by N, a sample sz.). If you want to fit plane to 3D data use a similar approach -
http://www.mymathforum.com/viewtopic.php?f=13&t=8793
Disclaimer: all quadratic fits are linear and optimal in a sense that they reduce the noise in parameters. However, you might interested in the reducing noise in the data instead. You might also want to ignore outliers since they can bia s your solutions greatly. Both problems can be solved with RANSAC. See my post at:

Speeding up self-similarity in an image

I'm writing a program that will generate images. One measurement that I want is the amount of "self-similarity" in the image. I wrote the following code that looks for the countBest-th best matches for each sizeWindow * sizeWindow window in the picture:
double Pattern::selfSimilar(int sizeWindow, int countBest) {
std::vector<int> *pvecount;
double similarity;
int match;
int x1;
int x2;
int xWindow;
int y1;
int y2;
int yWindow;
similarity = 0.0;
// (x1, y1) is the original that's looking for matches.
for (x1 = 0; x1 < k_maxX - sizeWindow; x1++) {
for (y1 = 0; y1 < k_maxY - sizeWindow; y1++) {
pvecount = new std::vector<int>();
// (x2, y2) is the possible match.
for (x2 = 0; x2 < k_maxX - sizeWindow; x2++) {
for (y2 = 0; y2 < k_maxY - sizeWindow; y2++) {
// Testing...
match = 0;
for (xWindow = 0; xWindow < sizeWindow; xWindow++) {
for (yWindow = 0; yWindow < sizeWindow; yWindow++) {
if (m_color[x1 + xWindow][y1 + yWindow] == m_color[x2 + xWindow][y2 + yWindow]) {
match++;
}
}
}
pvecount->push_back(match);
}
}
nth_element(pvecount->begin(), pvecount->end()-countBest, pvecount->end());
similarity += (1.0 / ((k_maxX - sizeWindow) * (k_maxY - sizeWindow))) *
(*(pvecount->end()-countBest) / (double) (sizeWindow * sizeWindow));
delete pvecount;
}
}
return similarity;
}
The good news is that the algorithm does what I want it to: it will return a value from 0.0 to 1.0 about how 'self-similar' a picture is.
The bad news -- as I'm sure that you've already noted -- is that the algorithm is extremely slow. It takes (k_maxX - sizeWindow) * (k_maxY - sizeWindow) * (k_maxX - sizeWindow) * (k_maxY - sizeWindow) * sizeWindow * sizeWindow steps for a run.
Some typical values for the variables:
k_maxX = 1280
k_maxY = 1024
sizeWindow = between 5 and 25
countBest = 3, 4, or 5
m_color[x][y] is defined as short m_color[k_maxX][k_maxY] with values between 0 and 3 (but may increase in the future.)
Right now, I'm not worried about the memory footprint taken by pvecount. Later, I can use a sorted data set that doesn't add another element when it's smaller than countBest. I am only worried about algorithm speed.
How can I speed this up?
Ok, first, this approach is not stable at all. If you add random noise to your image, it will greatly decrease the similarity between the two images. More importantly, from an image processing standpoint, it's not efficient or particularly good. I suggest another approach; for example, using a wavelet-based approach. If you performed a 2d DWT on your image for a few levels and compared the scaling coefficients, you would probably get better results. Plus, the discrete wavelet transform is O(n).
The downside is that wavelets are an advanced mathematical topic. There are some good OpenCourseWare notes on wavelets and filterbanks here.
Your problem strongly reminds me of the calculations that have to be done for motion compensation in video compression. Maybe you should take a closer look what's done in that area.
As rlbond already pointed out, counting the number of points in a window where the colors exactly match isn't what's normally done in comparing pictures. A conceptually simpler method than using discrete cosine or wavelet transformations is to add the squares of the differences
diff = (m_color[x1 + xWindow][y1 + yWindow] - m_color[x2 + xWindow][y2 + yWindow]);
sum += diff*diff;
and use sum instead of match as criterion for similarity (now smaller means better).
Back to what you really asked: I think it is possible to cut down the running time by the factor 2/sizeWindow (maybe squared?), but it is a little bit messy. It's based on the fact that certain pairs of squares you compare stay almost the same when incrementing y1 by 1. If the offsets xOff = x2-x1 and yOff = y2-y1 are the same, only the top (rsp. bottom) vertical stripes of the squares are no longer (rsp. now, but not before) matched. If you keep the values you calculate for match in a two-dimensional array indexed by the offsets xOff = x2-x1 and yOff = y2-y1, then can calculate the new value for match[xOff][yOff] for y1 increased by 1 and x1 staying the same by 2*sizeWindow comparisons:
for (int x = x1; x < x1 + sizeWindow; x++) {
if (m_color[x][y1] == m_color[x + xOff][y1 + yOff]) {
match[xOff][yOff]--; // top stripes no longer compared
}
if (m_color[x][y1+sizeWindow] == m_color[x + xOff][y1 + sizeWindow + yOff]) {
match[xOff][yOff]++; // bottom stripe compared not, but wasn't before
}
}
(as the possible values for yOff changed - by incrementing y1 - from the interval [y2 - y1, k_maxY - sizeWindow - y1 - 1] to the interval [y2 - y1 - 1, k_maxY - sizeWindow - y1 - 2] you can discard the matches with second index yOff = k_maxY - sizeWindow - y1 - 1 and have to calculate the matches with second index yOff = y2 - y1 - 1 differently). Maybe you can also keep the values by how much you increase/decrease match[][] during the loop in an array to get another 2/sizeWindow speed-up.