OpenCV least square (solve) solution accuracy - c++

I am using the OpenCV method solve (https://docs.opencv.org/2.4/modules/core/doc/operations_on_arrays.html#solve) in C++ to fit a curve (grade 3, ax^3+bx^2+cx+d) through a set of points. I am solving A * x = B, A contain the powers of the points x-coordinates (so x^3, x^2, x^1, 1), and B contains the y coordinates of the points, x (Matrix) contains the parameters a, b, c and d.
I am using the flag DECOMP_QR on cv::solve to fit the curve.
The problem I am facing is that the set of points do not neccessarily follow a mathematical function (e.g. the function changes it's equation, see picture). So, in order to fit an accurate curve, I need to split the set of points where the curvature changes. In case of the picture below, I would split the regression at the index where the curve starts. So I need to detect where the curvature changes.
So, if I don't split, I'll get the yellow curve as a result, which is inaccurate. What I want is the blue curve.
Finding curvature changes:
To find out where the curvature changes, I want to use the solution accuracy.
So basically:
int splitIndex = 0;
for(int pointIndex = 0; pointIndex < numberOfPoints; pointIndex += 5) {
cv::Range rowR = Range(0, pointIndex); //Selected rows to index
cv::Range colR = Range(0,3); //Grade: 3 (x^3)
cv::Mat x;
bool res = cv::solve(A(rowR, colR), B(rowR, Range(0,1)),x , DECOMP_QR);
if(res == true) {
//Check for accuracy
if (accuracy too bad) {
splitIndex = pointIndex;
return splitIndex;
}
}
}
My questions are:
- is there a way of getting the accuracy / standard deviation from the solve command (efficiently & fast, because of real-time application (around 1ms compute time left))
- is this a good way of finding the curvature change / does anyone know a better way?
Thanks :)

Related

How to generate the best curved fit for an unknown set of 2D points in C++

I am trying to get the best fit for an unknown set of 2D points. The points are centered points of rivers, and they don't come in a certain order.
I've tried to use polynomial regression but I don't know what is the best polynomial order for different sets of data.
I've also tried cubic spline, but I don't want a line through all the points I have, I want an approximation of the best fit line through the points.
I would like to get something like this even for lines that have more curves. This example is computed with polynomial regression, and it works fine.
Is there a way to do some smooth or regression algorithm that can get the best fit line even for a set of points like the following?
PolynomialRegression<double> pol;
static int polynomOrder = <whateverPolynomOrderFitsBetter>;
double error = 0.005f;
std::vector<double> coeffs;
pol.fitIt(x, y, polynomOrder, coeffs);
// get fitted values
for(std::size_t i = 0; i < points.size(); i++)
{
int order = polynomOrder;
long double yFitted = 0;
while(order >= 0)
{
yFitted += (coeffs[order] * pow(points[i].x, order) + error);
order --;
}
points[i].y = yFitted;
}
In my implementation with an 35 polynomial order this is all I can get , and also changing the polynomial order with higher values turns into Nan values for the coefficients.
I'm not sure if this is the best approach I can have.

Convolutional network filter always negative

I asked a question about a network which I've been building last week, and I iterated on the suggestions which lead me to finding a few problems. I've come back to this project and fixed up all the issues and learnt a lot more about CNNs in the process. Now I'm stuck on an issue were all of my weights move to massively negative values, which coupled with the RELU ends in the output image always being completely black (making it impossible for the classifier to do it's job).
On two labeled images:
These are passed into a two layer network, one classifier (which gets 100% on its own) and a one filter 3*3 convolutional layer.
On the first iteration the output from the conv layer looks like (images in same order as above):
The filter is 3*3*3, due to the images being RGB. The weights are all random numbers between 0.0f-1.0f. On the next iteration the images are completely black, printing the filters shows that they are now in range of -49678.5f (the highest I can see) and -61932.3f.
This issue in turn is due to the gradients being passed back from the Logistic Regression/Linear layer being crazy high for the cross (label 0, prediction 0). For the circle (label 1, prediction 0) the values are between roughly -12 and -5, but for the cross they are all in the positive high 1000 to high 2000 range.
The code which sends these back looks something like (some parts omitted):
void LinearClassifier::Train(float * x,float output, float y)
{
float h = output - y;
float average = 0.0f;
for (int i =1; i < m_NumberOfWeights; ++i)
{
float error = h*x[i-1];
m_pGradients[i-1] = error;
average += error;
}
average /= static_cast<float>(m_NumberOfWeights-1);
for (int theta = 1; theta < m_NumberOfWeights; ++theta)
{
m_pWeights[theta] = m_pWeights[theta] - learningRate*m_pGradients[theta-1];
}
// Bias
m_pWeights[0] -= learningRate*average;
}
This is passed back to the single convolution layer:
// This code is in three nested for loops (for layer,for outWidth, for outHeight)
float gradient = 0.0f;
// ReLu Derivative
if ( m_pOutputBuffer[outputIndex] > 0.0f)
{
gradient = outputGradients[outputIndex];
}
for (int z = 0; z < m_InputDepth; ++z)
{
for ( int u = 0; u < m_FilterSize; ++u)
{
for ( int v = 0; v < m_FilterSize; ++v)
{
int x = outX + u - 1;
int y = outY + v - 1;
int inputIndex = x + y*m_OutputWidth + z*m_OutputWidth*m_OutputHeight;
int kernelIndex = u + v*m_FilterSize + z*m_FilterSize*m_FilterSize;
m_pGradients[inputIndex] += m_Filters[layer][kernelIndex]*gradient;
m_GradientSum[layer][kernelIndex] += input[inputIndex]*gradient;
}
}
}
This code is iterated over by passing each image in a one at a time fashion. The gradients are obviously going in the right direction but how do I stop the huge gradients from throwing the prediction function?
RELU activations are notorious for doing this. You usually have to use a low learning rate. The reasoning behind this is that when the RELU returns positive numbers it can continue to learn freely, but if a unit gets in a position where the signal coming into it is always negative it can become a "dead" neuron and never activate again.
Also initializing your weights is more delicate with RELU. It appears that you are initializing to range 0-1 which creates a huge bias. Two tips here - Use a range centered around 0, and a range that is much smaller. A normal distribution with mean 0 and std 0.02 usually works well.
I fixed it by downscaling the gradients int the CNN layer, but now I'm confused as to why this works/is needed so if anyone has any intuition as to why this works that'd be great.

C++ - Efficient way to compare vectors

At the moment i'm working with a camera to detect a marker. I use opencv and the Aruco Libary.
Only I'm stuck with a problem right now. I need to detect if the distance between 2 marker is less than a specific value. I have a function to calculate the distance, I can compare everything. But I'm looking for the most efficient way to keep track of all the markers (around 5/6) and how close they are together.
There is a list with markers but I cant find a efficient way to compare all of them.
I have a
Vector <Marker>
I also have a function called getDistance.
double getDistance(cv::Point2f punt1, cv::Point2f punt2)
{
float xd = punt2.x-punt1.x;
float yd = punt2.y-punt1.y;
double Distance = sqrtf(xd*xd + yd*yd);
return Distance;
}
The Markers contain a Point2f, so i can compare them easily.
One way to increase performance is to keep all the distances squared and avoid using the square root function. If you square the specific value you are checking against then this should work fine.
There isn't really a lot to recommend. If I understand the question and I'm counting the pairs correctly, you'll need to calculate 10 distances when you have 5 points, and 15 distances when you have 6 points. If you need to determine all of the distances, then you have no choice but to calculate all of the distances. I don't see any way around that. The only advice I can give is to make sure you calculate the distance between each pair only once (e.g., once you know the distance between points A and B, you don't need to calculate the distance between B and A).
It might be possible to sort the vector in such a way that you can short circuit your loop. For instance, if you sort it correctly and the distance between point A and point B is larger than your threshold, then the distances between A and C and A and D will also be larger than the threshold. But keep in mind that sorting isn't free, and it's likely that for small sets of points it would be faster to just calculate all distances ("Fancy algorithms are slow when n is small, and n is usually small. Fancy algorithms have big constants. Until you know that n is frequently going to be big, don't get fancy. ... For example, binary trees are always faster than splay trees for workaday problems.").
Newer versions of the C and C++ standard library have a hypot function for calculating distance between points:
#include <cmath>
double getDistance(cv::Point2f punt1, cv::Point2f punt2)
{
return std::hypot(punt2.x - punt1.x, punt2.y - punt1.y);
}
It's not necessarily faster, but it should be implemented in a way that avoids overflow when the points are far apart.
One minor optimization is to simply check if the change in X or change in Y exceeds the threshold. If it does, you can ignore the distance between those two points because the overall distance will also exceed the threshold:
const double threshold = ...;
std::vector<cv::Point2f> points;
// populate points
...
for (auto i = points.begin(); i != points.end(); ++i) {
for (auto j = i + 1; j != points.end(); ++j) {
double dx = std::abs(i->x - j->x), dy = std::abs(i->y - j->y);
if (dx > threshold || dy > threshold) {
continue;
}
double distance = std::hypot(dx, dy);
if (distance > threshold) {
continue;
}
...
}
}
If you're dealing with large amounts of data inside your vector you may want to consider some multithreading using future.
Vector <Marker> could be chunked into X chunks which are asynchronously computed together and stored inside std::future<>, putting to use #Sesame's suggestion will also increase your speed as well.

Face Recognition Classifier

By referring to the previous post, the method used for classification was Euclidean Distance with Nearest Neighbor. However, the result obtained is not accurate as both known dataset and unknown dataset are giving similarity 99%. Even with Mahalanobis distance also gives similar result.
Is there any other method for face recognition classification? Could you provide me some examples/formulae?
float d_i = projectedTestFace[i] - projectedTrainFaceMat->data.fl[iTrain*nEigens + i];
distSq += d_i*d_i; // Euclidean distance
imho, if you get bad results, blame your input, not the distance formula
without any further preprocessing(alignment,cropping,equalization), even a plain L2 norm over the pixels gives better results, than eigenfaces. (sad truth here)
since 2.4.2, opencv has face-recognition out of-the-box. (also with alternative fisher and lbph features)
you probably should use that, instead of rolling your own (and please use the c++ api, not the arcane c one).
if you do want to stick with eigenfaces, you still could try the L2 distance beween a 'reconstructed' (from the eigenvecs) image and the test image as a confidence measure, as done here (by shervin, again)
// Compare two images by getting the L2 error (square-root of sum of squared error).
double getSimilarity(const Mat A, const Mat B)
{
if (A.rows > 0 && A.rows == B.rows && A.cols > 0 && A.cols == B.cols) {
// Calculate the L2 relative error between the 2 images.
double errorL2 = norm(A, B, CV_L2);
// Convert to a reasonable scale, since L2 error is summed across all pixels of the image.
double similarity = errorL2 / (double)(A.rows * A.cols);
return similarity;
}
else {
//cout << "WARNING: Images have a different size in 'getSimilarity()'." << endl;
return 100000000.0; // Return a bad value
}
}
I wonder why i always get return 100000000. Does it means that the preprocessed and reconstructed face have difference size? That's why it skips the L2 distance comparison?
Below are part of my coding:
Mat j =projectedTestFace[i];
Mat k =projectedTrainFaceMat>data.fl[iTrain*nEigens + i];
similarity=getSimilarity(j,k);
without the else statement, i get similarity=-nan result, wondering what are -nan and -inf stand for.

Calculate the gradient for an histogram in c++

I calculated the histogram(a simple 1d array) for an 3D grayscale Image.
Now I would like to calculate the gradient for the this histogram at each point. So this would actually mean I have to calculate the gradient for a 1D function at certain points. However I do not have a function. So how can I calculate it with concrete x and y values?
For the sake of simplicity could you probably explain this to me on an example histogram - for example with the following values (x is the intensity, and y the frequency of this intensity):
x1 = 1; y1 = 3
x2 = 2; y2 = 6
x3 = 3; y3 = 8
x4 = 4; y4 = 5
x5 = 5; y5 = 9
x6 = 6; y6 = 12
x7 = 7; y7 = 5
x8 = 8; y8 = 3
x9 = 9; y9 = 5
x10 = 10; y10 = 2
I know that this is also a math problem, but since I need to solve it in c++ I though you could help me here.
Thank you for your advice
Marc
I think you can calculate your gradient using the same approach used in image border detection (which is a gradient calculus). If your histogram is in a vector you can calculate an approximation of the gradient as*:
for each point in the histogram compute
gradient[x] = (hist[x+1] - hist[x])
This is a very simple way to do it, but I'm not sure if is the most accurate.
approximation because you are working with discrete data instead of continuous
Edited:
Other operators will may emphasize small differences (small gradients will became more emphasized). Roberts algorithm derives from the derivative calculus:
lim delta -> 0 = f(x + delta) - f(x) / delta
delta tends infinitely to 0 (in order to avoid 0 division) but is never zero. As in computer's memory this is impossible, the smallest we can get of delta is 1 (because 1 is the smallest distance from to points in an image (or histogram)).
Substituting
lim delta -> 0 to lim delta -> 1
we get
f(x + 1) - f(x) / 1 = f(x + 1) - f(x) => vet[x+1] - vet[x]
Two generally approaches here:
a discrete approximation to the derivative
take the real derivative of a fitted function
In the first case try:
g = (y_(i+1) - y_(i-1))/2*dx
at all the points except the ends, or one of
g_left-end = (y_(i+1) - y_i)/dx
g_right-end = (y_i - y_(i-1))/dx
where dx is the spacing between x points. (Unlike the equally correct definition Andres suggested, this one is symmetric. Whether it matters or not depends on you use case.)
In the second case, fit a spline to your data[*], and ask the spline library the derivative at the point you want.
[*] Use a library! Do not implement this yourself unless this is a learning project. I'd use ROOT because I already have it on my machine, but it is a pretty heavy package just to get a spline...
Finally, if you data is noisy, you ma want to smooth it before doing slope detection. That was you avoid chasing the noise, and only look at large scale slopes.
Take some squared paper and draw on it your histogram. Draw also vertical and horizontal axes through the 0,0 point of your histogram.
Take a straight edge and, at each point you are interested in, rotate the straight edge until it accords with your idea of what the gradient at that point is. It is most important that you do this, your definition of gradient is the one you want.
Once the straight edge is at the angle you desire draw a line at that angle.
Drop perpendiculars from any 2 points on the line you just drew. It will be easier to take the following step if the horizontal distance between the 2 points you choose is about 25% or more of the width of your histogram. From the same 2 points draw horizontal lines to intersect the vertical axis of your histogram.
Your lines now define an x-distance and a y-distance, ie the length of the horizontal/ vertical (respectively) axes marked out by their intersections with the perpendiculars/horizontal lines. The gradient you want is the y-distance divided by the x-distance.
Now, to translate this into code is very straightforward, apart from step 2. You have to define what the criteria are for determining what the gradient at any point on the histogram is. Simple choices include:
a) at each point, set down your straight edge to pass through the point and the next one to its right;
b) at each point, set down your straight edge to pass through the point and the next one to its left;
c) at each point, set down your straight edge to pass through the point to the left and the point to the right.
You may want to investigate more complex choices such as fitting a curve (such as a quadratic or higher-order polynomial) through a number of points on your histogram and using the derivative of that to represent the gradient.
Until you understand the question on paper avoid coding in C++ or anything else. Once you do understand it, coding should be trivial.