inaccurate result in function polyfit (Bug #2887)
Description
The default datatype in polyfit is CV_32F and the method is Least square method.
In some circumstances where input data on x-axis are uniformly large enough(e.g. 24-47, 24 input numbers) while data on y-axis are relatively close and large too, the fitting curve could be tremendously inaccurate.
Example(pseudocode):¶
x1 = [0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16;17;18;19;20;21;22;23];
y1 = [488.3692016601563
488.4369506835938
488.4021911621094
488.3995666503906
488.3041076660156
488.3595581054688
488.2347412109375
488.2492065429688
488.0935974121094
488.1622314453125
488.1072082519531
488.2424011230469
488.1407165527344
488.2175903320313
488.2396850585938
488.27587890625];
x2 = [24;25;26;27;28;29;30;31;32;33;34;35;36;37;38;39;40;41;42;43;44;45;46;47];
y2 = [488.3522644042969
488.2658996582031
488.3119812011719
488.3011474609375
488.3711853027344
488.3617248535156
488.3223266601563
488.2750549316406
488.2916259765625
488.3085632324219
488.3853454589844
488.3346862792969
488.2177734375
488.3077392578125
488.29150390625
488.3375854492188];
Mat result1, result2;
polyfit(x1, y1, result1, 2);//fitting a second order curve
polyfit(x2, y2, result2, 2);//fitting a second order curve
Result(datatype:CV_32F, see picture "datatype : CV_32F"):¶
result1 = [488.4185180664063
-0.03082548454403877
0.001051958999596536];
result2 = [488.6778259277344
-0.02593995630741119
0.0003619703638833016];
I modified the code to use datatyoe CV_64F.X = Mat::zeros(src_x.rows, order+1,CV_64F);
Mat srcy;
src_y.convertTo(srcy,CV_64F);for(int i = 0; i <=order;i++){
src_x.convertTo(copy,CV_64F);
pow(copy,i,copy);
Mat M1 = X.col(i);
copy.col(0).copyTo(M1);}
Result(datatype:CV_64F, see picture "datatype : CV_64F" ):¶
result1 = [488.4181859764685
-0.03089823452888219
0.001054061977798282];
result2 = [488.6890140021986
-0.02416449552013233
0.0003906240721791021];
I think this is because for some input data on x-axis, the sum of x.^4 could be extremly large which may result in a extremly inaccurate reverse matrix.(In the example above, the sum of x.^4 is 46912204)
Associated revisions
Merge pull request #2887 from ilya-lavrenov:ipp_morph_fix
History
Updated by Zhoucheng Li almost 12 years ago
One can simply do the following procedures(The example is order 2)
foreach element x2(n) and y2(n) in x2 and y2 respectively
x2(n) -= average_x;
y2(n) -= average_y;polyfit(x2, y2, result2, 2);
- Since the two curves have the same shape but are at different locations,we can derive the ralations between these 2 sets of curve parameters.
Take "y = a*x.^2 + b*x + c" as an example.The new curve we've got is "y - average_y = a'*(x - average_x)^2 + b'*(x - average_x) + c'".
From step2, we've got parameters a',b'and c'.
Compare these 2 equations, we can derive thata = a';
b = b' - 2*average_x*a';
c = c' + average_y + a'*(average_x)^2 - b'*average_x; - thus
new_result2 = [488.6890572353125
-0.024164495611330
0.0003906240744981915];
The answer is very close to the CV_64F version one.result2 = [488.6890140021986
-0.02416449552013233
0.0003906240721791021];
However, with a higher order(>=4),it's gonna be tough to derive the relations between parameters by paper work.
Updated by Daniil Osokin almost 12 years ago
Hi, Zhoucheng! Could you contribute a bugfix (http://code.opencv.org/projects/opencv/wiki/How_to_contribute). It will speedup fixing in many times! Anyway, thank you for attention.
- Assignee changed from Vadim Pisarevsky to Zhoucheng Li
Updated by Zhoucheng Li almost 12 years ago
Daniil Osokin wrote:
Hi, Zhoucheng! Could you contribute a bugfix (http://code.opencv.org/projects/opencv/wiki/How_to_contribute). It will speedup fixing in many times! Anyway, thank you for attention.
My pleasure :D
Updated by Daniil Osokin almost 12 years ago
Great, thanks!
- Pull request set to https://github.com/Itseez/opencv/pull/674
Updated by Andrey Kamaev almost 12 years ago
- Target version changed from 2.4.5 to 3.0
Updated by Dmitry Retinskiy over 11 years ago
- Status changed from Open to Done
- HW Platform set to Any
- Operating System set to Any
- Affected version changed from 2.4.4 to branch 'master' (3.0-dev)