使用OpenCV模拟Matlab的mldivide [英] Simulating matlab's mldivide with OpenCV

查看:122
本文介绍了使用OpenCV模拟Matlab的mldivide的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我昨天问了这个问题:用2个平方矩阵模拟matlab的mrdivide

I asked this question yesterday: Simulating matlab's mrdivide with 2 square matrices

这就是mrdivide的工作原理.但是现在我遇到了mldivide的问题,该问题当前实现如下:

And thats got mrdivide working. However now I'm having problems with mldivide, which is currently implemented as follows:

cv::Mat mldivide(const cv::Mat& A, const cv::Mat& B ) 
{
    //return  b * A.inv();
    cv::Mat a;
    cv::Mat b;
    A.convertTo( a, CV_64FC1 );
    B.convertTo( b, CV_64FC1 );

    cv::Mat ret;
    cv::solve( a, b, ret, cv::DECOMP_NORMAL );

    cv::Mat ret2;
    ret.convertTo( ret2, A.type() );
    return ret2;
}

据我了解,mrdivide正在工作这一事实应该意味着mldivide在工作,但我无法获得与matlab相同的结果.同样,结果也不尽相同.

By my understanding the fact that mrdivide is working should mean that mldivide is working but I can't get it to give me the same results as matlab. Again the results are nothing alike.

值得注意的是,我试图做一个[19x19] \ [19x200],所以这次不求平方.

Its worth noting I am trying to do a [19x19] \ [19x200] so not square matrices this time.

推荐答案

就像我之前在您的其他问题中提到的,我将MATLAB与 mexopencv 一起使用,这样我就可以轻松比较两个MATLAB的输出和OpenCV.

Like I've previously mentioned in your other question, I am using MATLAB along with mexopencv, that way I can easily compare the output of both MATLAB and OpenCV.

也就是说,我无法重现您的问题:我随机生成矩阵,并重复比较N=100次.我正在运行带有针对OpenCV 3.0.0编译的mexopencv的MATLAB R2015a:

That said, I can't reproduce your problem: I generated randomly matrices, and repeated the comparison N=100 times. I'm running MATLAB R2015a with mexopencv compiled against OpenCV 3.0.0:

N = 100;
r = zeros(N,2);
d = zeros(N,1);
for i=1:N
    % double precision, i.e CV_64F
    A = randn(19,19);
    B = randn(19,200);

    x1 = A\B;
    x2 = cv.solve(A,B);   % this a MEX function that calls cv::solve

    r(i,:) = [norm(A*x1-B), norm(A*x2-B)];
    d(i) = norm(x1-x2);
end

所有结果都已达成共识,并且误差很小,以1e-11的顺序排列:

All results agreed and the errors were very small in the order of 1e-11:

>> mean(r)
ans =
   1.0e-12 *
    0.2282    0.2698

>> mean(d)
ans =
   6.5457e-12

(顺便说一句,我也尝试过设置cv::DECOMP_NORMAL标志的x2 = cv.solve(A,B, 'IsNormal',true);,结果也没什么不同).

(btw I also tried x2 = cv.solve(A,B, 'IsNormal',true); which sets the cv::DECOMP_NORMAL flag, and the results were not that different either).

这使我相信,您的矩阵恰巧会加剧OpenCV求解器中的某些极端情况,导致无法给出适当的解决方案,或者更有可能您的代码中存在其他错误.

This leads me to believe that either your matrices happen to accentuate some edge case in the OpenCV solver, where it failed to give a proper solution, or more likely you have a bug somewhere else in your code.

首先要仔细检查数据的加载方式,尤其要注意矩阵的布局方式(显然,MATLAB是列为主的,而OpenCV是行为主的)...

I'd start by double checking how you load your data, and especially watch out for how the matrices are laid out (obviously MATLAB is column-major, while OpenCV is row-major)...

您也从未告诉过我们有关您矩阵的任何信息;它们是否表现出一定的特征,是否存在对称性,是否主要为零,其等级等?

Also you never told us anything about your matrices; do they exhibit a certain characteristic, are there any symmetries, are they mostly zeros, their rank, etc..

在OpenCV中,默认的求解器方法是LU因式分解,并且如果需要,您必须自己明确地对其进行更改.手上的MATLAB将自动 选择一种最适合矩阵A的方法,而LU只是可能的一种分解.

In OpenCV, the default solver method is LU factorization, and you have to explicitly change it yourself if appropriate. MATLAB on the hand will automatically choose a method that best suits the matrix A, and LU is just one of the possible decompositions.

在MATLAB中使用SVD分解时,左右特征向量UV的符号为任意(这确实来自 DGESVD LAPACK例程).为了获得一致的结果,一种约定是要求每个本征向量的第一个元素为某个符号,并将每个向量乘以+1或-1以适当地翻转该符号.我还建议您查看 eigenshuffle .

When using SVD decompositition in MATLAB, the sign of the left and right eigenvectors U and V is arbitrary (this really comes from the DGESVD LAPACK routine). In order to get consistent results, one convention is to require that the first element of each eigenvector be a certain sign, and multiplying each vector by +1 or -1 to flip the sign as appropriate. I would also suggest checking out eigenshuffle.

再过一次,这是我所做的一项测试,目的是确认我在MATLAB和OpenCV中获得与SVD类似的结果:

One more time, here is a test I did to confirm that I get similar results for SVD in MATLAB and OpenCV:

N = 100;
r = zeros(N,2);
d = zeros(N,3);
for i=1:N
    % double precision, i.e CV_64F
    A = rand(19);

    % compute SVD in MATLAB, and apply sign convention
    [U1,S1,V1] = svd(A);
    sn = sign(U1(1,:));
    U1 = bsxfun(@times, sn, U1);
    V1 = bsxfun(@times, sn, V1);
    r(i,1) = norm(U1*S1*V1' - A);

    % compute SVD in OpenCV, and apply sign convention
    [S2,U2,V2] = cv.SVD.Compute(A);
    S2 = diag(S2);
    sn = sign(U2(1,:));
    U2 = bsxfun(@times, sn, U2);
    V2 = bsxfun(@times, sn', V2)';  % Note: V2 was transposed w.r.t V1
    r(i,2) = norm(U2*S2*V2' - A);

    % compare
    d(i,:) = [norm(V1-V2), norm(U1-U2), norm(S1-S2)];
end

同样,所有结果都非常相似,并且误差接近机器ε并且可以忽略不计:

Again, all results were very similar and the errors close to machine epsilon and negligible:

>> mean(r)
ans =
   1.0e-13 *
    0.3381    0.1215

>> mean(d)
ans =
   1.0e-13 *
    0.3113    0.3009    0.0578

我不确定OpenCV中的一件事,但是MATLAB的svd函数返回以降序排序的奇异值(与eig函数不同),特征向量的列也以相应的顺序出现.

One thing I'm not sure about in OpenCV, but MATLAB's svd function returns the singular values sorted in decreasing order (unlike the eig function), with the columns of the eigenvectors in corresponding order.

现在,如果由于某些原因不能保证对OpenCV中的奇异值进行排序,那么如果要与MATLAB比较结果,则也必须手动进行,如:

Now if the singular values in OpenCV are not guaranteed to be sorted for some reason, you have to do it manually as well if you want to compare the results against MATLAB, as in:

% not needed in MATLAB
[U,S,V] = svd(A);
[S, ord] = sort(diag(S), 'descend');
S = diag(S);
U = U(:,ord)
V = V(:,ord);

这篇关于使用OpenCV模拟Matlab的mldivide的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆