Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

High `cv::solve` error if trained on single line

I use cv::solve to solve two dimensional linear regression. If the training data happen to be on single line (that is, y is equal for all training variables, then the extrapolation produces large error.

Say, the training data are:

X     Y     Z
----  ----  -----
4     7     458
5     7     554
7     7     735
8     7     826

The calculated coefficients are (notice the last two are very large numbers):

{92.8825, 3.74394e+007, -2.62076e+008}

If I use these to extrapolate the original values, large error is produced:

X     Y     Z'
----  ----  -----
4     7     427.53
5     7     520.412
7     7     706.177
8     7     799.06

All values are smaller by about 26-30. Why?

Here is the code:

static void print(float a, float b, float c, int x, int y) {
    cout << "x=" << x << ", y=" << y << ", z=" << (a*x + b*y + c) << endl;
}

int main() {
    Mat matX(4, 3, CV_32F);
    Mat matZ(4, 1, CV_32F);

    int idx = 0;
    matX.at<float>(idx, 0) = 4;
    matX.at<float>(idx, 1) = 7;
    matX.at<float>(idx, 2) = 1;
    matZ.at<float>(idx++, 0) = 458;

    matX.at<float>(idx, 0) = 5;
    matX.at<float>(idx, 1) = 7;
    matX.at<float>(idx, 2) = 1;
    matZ.at<float>(idx++, 0) = 554;

    matX.at<float>(idx, 0) = 7;
    matX.at<float>(idx, 1) = 7;
    matX.at<float>(idx, 2) = 1;
    matZ.at<float>(idx++, 0) = 734;

    matX.at<float>(idx, 0) = 8;
    matX.at<float>(idx, 1) = 7;
    matX.at<float>(idx, 2) = 1;
    matZ.at<float>(idx++, 0) = 826;

    Mat res(3, 1, CV_32F);

    cv::solve(matX, matZ, res, CV_QR);

    float a = res.at<float>(0);
    float b = res.at<float>(1);
    float c = res.at<float>(2);

    cout << "a=" << a << ", b=" << b << ", c=" << c << endl;
    print(a, b, c, 4, 7);
    print(a, b, c, 5, 7);
    print(a, b, c, 6, 7);
    print(a, b, c, 7, 7);
    print(a, b, c, 8, 7);
}

High `cv::solve` error if trained on single line

I use cv::solve to solve two dimensional linear regression. If the training data happen to be on single line (that is, y is equal for all training variables, then the extrapolation produces large error.

Say, the training data are:

X     Y     Z
----  ----  -----
4     7     458
5     7     554
7     7     735
8     7     826

The calculated coefficients are (notice the last two are very large numbers):

{92.8825, 3.74394e+007, -2.62076e+008}

If I use these to extrapolate the original values, large error is produced:

X     Y     Z'
----  ----  -----
4     7     427.53
5     7     520.412
7     7     706.177
8     7     799.06

All values are smaller by about 26-30. Why?This seems to be an edge case. In my use case, if I have values all on single line (horizontal or vertical), I will predict the values only for that line, turning it effectively into one-dimensional linear regression. But the error is unacceptable.

Here is the code:

static void print(float a, float b, float c, int x, int y) {
    cout << "x=" << x << ", y=" << y << ", z=" << (a*x + b*y + c) << endl;
}

int main() {
    Mat matX(4, 3, CV_32F);
    Mat matZ(4, 1, CV_32F);

    int idx = 0;
    matX.at<float>(idx, 0) = 4;
    matX.at<float>(idx, 1) = 7;
    matX.at<float>(idx, 2) = 1;
    matZ.at<float>(idx++, 0) = 458;

    matX.at<float>(idx, 0) = 5;
    matX.at<float>(idx, 1) = 7;
    matX.at<float>(idx, 2) = 1;
    matZ.at<float>(idx++, 0) = 554;

    matX.at<float>(idx, 0) = 7;
    matX.at<float>(idx, 1) = 7;
    matX.at<float>(idx, 2) = 1;
    matZ.at<float>(idx++, 0) = 734;

    matX.at<float>(idx, 0) = 8;
    matX.at<float>(idx, 1) = 7;
    matX.at<float>(idx, 2) = 1;
    matZ.at<float>(idx++, 0) = 826;

    Mat res(3, 1, CV_32F);

    cv::solve(matX, matZ, res, CV_QR);

    float a = res.at<float>(0);
    float b = res.at<float>(1);
    float c = res.at<float>(2);

    cout << "a=" << a << ", b=" << b << ", c=" << c << endl;
    print(a, b, c, 4, 7);
    print(a, b, c, 5, 7);
    print(a, b, c, 6, 7);
    print(a, b, c, 7, 7);
    print(a, b, c, 8, 7);
}

High `cv::solve` error if trained on single line

I use cv::solve to solve two dimensional linear regression. If the training data happen to be on single line (that is, y is equal for all training variables, then the extrapolation produces large error.

Say, the training data are:

X     Y     Z
----  ----  -----
4     7     458
5     7     554
7     7     735
8     7     826

The calculated coefficients are (notice the last two are very large numbers):

{92.8825, 3.74394e+007, -2.62076e+008}

If I use these to extrapolate the original values, large error is produced:

X     Y     Z'
----  ----  -----
4     7     427.53
5     7     520.412
7     7     706.177
8     7     799.06

All values are smaller by about 26-30. This seems to be an edge case. In my use case, if I have values all on single line (horizontal or vertical), I will predict the values only for that line, turning it effectively into one-dimensional linear regression. But the error is unacceptable.

Here is the code:

static void print(float a, float b, float c, int x, int y) {
    cout << "x=" << x << ", y=" << y << ", z=" << (a*x + b*y + c) << endl;
}

int main() {
    Mat matX(4, 3, CV_32F);
    Mat matZ(4, 1, CV_32F);

    int idx = 0;
    matX.at<float>(idx, 0) = 4;
    matX.at<float>(idx, 1) = 7;
    matX.at<float>(idx, 2) = 1;
    matZ.at<float>(idx++, 0) = 458;

    matX.at<float>(idx, 0) = 5;
    matX.at<float>(idx, 1) = 7;
    matX.at<float>(idx, 2) = 1;
    matZ.at<float>(idx++, 0) = 554;

    matX.at<float>(idx, 0) = 7;
    matX.at<float>(idx, 1) = 7;
    matX.at<float>(idx, 2) = 1;
    matZ.at<float>(idx++, 0) = 734;

    matX.at<float>(idx, 0) = 8;
    matX.at<float>(idx, 1) = 7;
    matX.at<float>(idx, 2) = 1;
    matZ.at<float>(idx++, 0) = 826;

    Mat res(3, 1, CV_32F);

    cv::solve(matX, matZ, res, CV_QR);
DECOMP_QR);

    float a = res.at<float>(0);
    float b = res.at<float>(1);
    float c = res.at<float>(2);

    cout << "a=" << a << ", b=" << b << ", c=" << c << endl;
    print(a, b, c, 4, 7);
    print(a, b, c, 5, 7);
    print(a, b, c, 6, 7);
    print(a, b, c, 7, 7);
    print(a, b, c, 8, 7);
}