Mat.inv()在opencv中产生所有零 [英] Mat.inv() yielding all zeroes in opencv

查看:3189
本文介绍了Mat.inv()在opencv中产生所有零的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

  cv :: Mat temp0 = R.t 
cv :: Mat temp1 = R * temp0;
cv :: Mat temp2(960,960,CV_32FC1);
temp2 = temp1.inv();

cv :: Size s = temp1.size();
std :: cout<< s.height<<<< s.width<< std :: endl;

std :: cout<< cv :: format(temp1,numpy)< std :: endl;
std :: cout<< cv :: format(temp2,numpy)< std :: endl;

Transpose工作正常,矩阵乘法也正确。因此, Mat temp1 的大小为960x960。但是,当我做 temp2 = temp1.inv()时,我收到 temp2 中的所有零。我的意思是所有的960x960单元格。此外, R 仅为类型 CV_32FC1 。所以它可能不是数据类型问题。我不明白这里的问题。我google了这么多。



我复制下面的gdb输出为 Mat :: inv()函数。我有一个很难把所有的东西,但如果有人更熟悉OpenCV,也许它会有帮助:)

 断点1,CreateShares :: ConstructShares(this = 0x80556d0,channel = ...,k = 2,n = 4)CreateShares.cpp:165 
165 temp2 = temp1.inv
(gdb)step

cv :: Mat :: operator =(this = 0xbffff294,e = ...)at /usr/include/opencv2/core/mat.hpp:1373
1373 e.op-> assign(e,* this);
(gdb)
1374 return * this; / usr中的
(gdb)step
1375}
(gdb)step
cv :: MatExpr ::〜MatExpr(this = 0xbfffef64,__in_chrg =< optimized out>) /include/opencv2/core/mat.hpp:1167
1167 class CV_EXPORTS MatExpr
(gdb)step
cv :: Mat ::〜Mat(this = 0xbfffefdc,__in_chrg =< optimized out>)at /usr/include/opencv2/core/mat.hpp:295
295 release();
(gdb)step
cv :: Mat :: release(this = 0xbfffefdc)at /usr/include/opencv2/core/mat.hpp:381
381 if(refcount& ; CV_XADD(refcount,-1)== 1)
(gdb)step
383 data = datastart = dataend = datalimit = 0;
(gdb)step
384 size.p [0] = 0;
(gdb)step
385 refcount = 0; / usr中的
(gdb)step
386}
(gdb)step
cv :: Mat ::〜Mat(this = 0xbfffefdc,__in_chrg =< optimized out>) /include/opencv2/core/mat.hpp:296
296 if(step.p!= step.buf)
(gdb)step
298}
(gdb)step
cv :: Mat ::〜Mat(this = 0xbfffefa4,__in_chrg =< optimized out>)at /usr/include/opencv2/core/mat.hpp:295
295 release
(gdb)step
cv :: Mat :: release(this = 0xbfffefa4)at /usr/include/opencv2/core/mat.hpp:381
381 if(refcount& ; CV_XADD(refcount,-1)== 1)
(gdb)step
383 data = datastart = dataend = datalimit = 0;
(gdb)step
384 size.p [0] = 0;
(gdb)step
385 refcount = 0; / usr中的
(gdb)step
386}
(gdb)step
cv :: Mat ::〜Mat(this = 0xbfffefa4,__in_chrg =< optimized out>) /include/opencv2/core/mat.hpp:296
296 if(step.p!= step.buf)
(gdb)step
298}
(gdb)step
cv :: Mat ::〜Mat(this = 0xbfffef6c,__in_chrg =< optimized out>)at /usr/include/opencv2/core/mat.hpp:295
295 release
(gdb)step
cv :: Mat :: release(this = 0xbfffef6c)at /usr/include/opencv2/core/mat.hpp:381
381 if(refcount& ; CV_XADD(refcount,-1)== 1)
(gdb)step
383 data = datastart = dataend = datalimit = 0;
(gdb)step
384 size.p [0] = 0;
(gdb)step
385 refcount = 0; / usr下的
(gdb)step
386}
(gdb)step
cv :: Mat ::〜Mat(this = 0xbfffef6c,__in_chrg =< optimized out> /include/opencv2/core/mat.hpp:296
296 if(step.p!= step.buf)
(gdb)step
298}
(gdb)step
CreateShares :: ConstructShares(this = 0x80556d0,channel = ...,k = 2,n = 4)在CreateShares.cpp:167
167 cv :: Size s = temp1.size
(gdb)step
cv :: Mat :: MSize :: operator()(this = 0xbffff284)at /usr/include/opencv2/core/mat.hpp:705
705 return大小(p [1],p [0]);
(gdb)step
cv :: Size_< int> :: Size_(this = 0xbffff2f8,_width = 960,_height = 960)at /usr/include/opencv2/core/operations.hpp:1624
1624:width(_width),height(_height){}
(gdb)step
cv :: Mat :: MSize :: operator()(this = 0xbffff284) include / opencv2 / core / mat.hpp:706
706}
(gdb)step




维基百科:


不可逆的方形矩阵称为奇异
degenerate。当且仅当其行列式
为0时,方矩阵是奇异的。


  std :: cout<<determinant(temp1)=<< cv :: determinant(temp1) <<\ n; 

Mat :: inv()的文档,有三种方法可供选择:




  • DECOMP_LU(默认)是LU分解。 矩阵必须是非奇异的。

  • DECOMP_CHOLESKY是对称正定义矩阵的Cholesky分解。这种类型在大矩阵上比LU大约快两倍。

  • DECOMP_SVD是SVD分解。如果矩阵是奇异或甚至非正方形,则计算伪逆。



invert()的文档,可能由Mat :: inv()内部使用:


$在DECOMP_LU方法的情况下,该函数返回src
行列式(src必须是正方形)。bbb $ b


<如果它是0,矩阵不是
反转,并且dst用零填充。







关于数学的注意事项



I没有数学家,但我得到的印象是,颠倒一个矩阵可以是一个混乱的业务 - 更是如此,如果你的矩阵是非常大的。事实上,这些倒置可能是真的存在于原则上,但是实际上不可能以任何精度计算。在使用代码运行一些实验时,我发现在许多情况下,我会得到不完全为零,但非常接近零的行列式 - 也许表明数值精度可能是限制因素。我尝试使用64位值而不是32来指定矩阵,并且得到不同,但不一定更好的答案。



这可能有助于识别,基于你计算 temp1 矩阵,它总是对称的 DECOMP_CHOLESKY 方法专门用于对称 正定 矩阵,因此使用它可能提供一些优点。



正则化(由@cedrou建议)使得反函数更可能返回一个非零矩阵( DECOMP_LU ,但不是 DECOMP_CHOLESKY )。然而,根据我对如何初始化 R 矩阵的猜测,所得到的矩阵似乎不满足逆的定义: A * reverse(A)= Identity 。但是你不一定关心这 - 这也许是为什么SVD方法计算一个伪逆。



最后,这个更深层的为什么反演失败的问题可能是一个数学问题,而不是一个编程问题。根据我在数学网站上做了一些搜索,事实证明有人已经问过如何做这个事情: http: //math.stackexchange.com/questions/182662






调试注意事项



根据你的调试跟踪,我倾向于认为你感兴趣的部分被编译成一个不可跟踪的库,并跳过,当你运行 step 。换句话说,在你的第一个步骤之后的那个神秘的空行代表它实际上运行 inv()函数。之后,它将结果分配给 temp2 并销毁临时对象。所以你的调试跟踪不会告诉我们在 inv()里面发生了什么。

  165 temp2 = temp1.inv(); 
(gdb)step

cv :: Mat :: operator =(this = 0xbffff294,e = ...)at /usr/include/opencv2/core/mat.hpp:1373
1373 e.op-> assign(e,* this);

我自己运行了一个调试器,可以跟踪内部调用 invert(),并且基于矩阵的内部分析(确定它不是可逆的)来观察它失败 - 因此返回一个用零填充的矩阵,匹配你所报告的



invert()函数在 cxlapack.cpp ,以防万一你想看看源代码。


I have the following code :

    cv::Mat temp0 = R.t();
    cv::Mat temp1 = R * temp0;
    cv::Mat temp2(960, 960, CV_32FC1);
    temp2 = temp1.inv();

    cv::Size s = temp1.size();
    std::cout<<s.height<<" "<<s.width<<std::endl;

    std::cout<<cv::format(temp1, "numpy" ) << std::endl;
    std::cout<<cv::format(temp2, "numpy" ) << std::endl;

The Transpose works correctly, so does the matrix multiplication. Thus the Mat temp1 has a size of 960x960. However, when I do temp2 =temp1.inv(), I recieve all zeroes in temp2. I mean zeroes is all of the 960x960 cells. Also, R is of type CV_32FC1 only. So it is probably not a datatype issue. I cannot understand the issue here. I googled so much. Can you please help.

EDIT

I am copying below the gdb output for the Mat::inv() function. I am having a hard time figuring it all out, but if someone is more familiar with OpenCV, maybe it will be of help :)

Breakpoint 1, CreateShares::ConstructShares (this=0x80556d0, channel=..., k=2, n=4) at CreateShares.cpp:165
165     temp2 = temp1.inv();
(gdb) step

cv::Mat::operator= (this=0xbffff294, e=...) at /usr/include/opencv2/core/mat.hpp:1373
1373        e.op->assign(e, *this);
(gdb) 
1374        return *this;
(gdb) step
1375    }    
(gdb) step
cv::MatExpr::~MatExpr (this=0xbfffef64, __in_chrg=<optimized out>) at /usr/include/opencv2/core/mat.hpp:1167
1167    class CV_EXPORTS MatExpr
(gdb) step
cv::Mat::~Mat (this=0xbfffefdc, __in_chrg=<optimized out>) at /usr/include/opencv2/core/mat.hpp:295
295     release();
(gdb) step
cv::Mat::release (this=0xbfffefdc) at /usr/include/opencv2/core/mat.hpp:381
381     if( refcount && CV_XADD(refcount, -1) == 1 )
(gdb) step
383     data = datastart = dataend = datalimit = 0;
(gdb) step
384     size.p[0] = 0;
(gdb) step
385     refcount = 0;
(gdb) step
386 }
(gdb) step
cv::Mat::~Mat (this=0xbfffefdc, __in_chrg=<optimized out>) at /usr/include/opencv2/core/mat.hpp:296
296     if( step.p != step.buf )
(gdb) step
298 }
(gdb) step
cv::Mat::~Mat (this=0xbfffefa4, __in_chrg=<optimized out>) at /usr/include/opencv2/core/mat.hpp:295
295     release();
(gdb) step
cv::Mat::release (this=0xbfffefa4) at /usr/include/opencv2/core/mat.hpp:381
381     if( refcount && CV_XADD(refcount, -1) == 1 )
(gdb) step
383     data = datastart = dataend = datalimit = 0;
(gdb) step
384     size.p[0] = 0;
(gdb) step
385     refcount = 0;
(gdb) step
386 }
(gdb) step
cv::Mat::~Mat (this=0xbfffefa4, __in_chrg=<optimized out>) at /usr/include/opencv2/core/mat.hpp:296
296     if( step.p != step.buf )
(gdb) step
298 }
(gdb) step
cv::Mat::~Mat (this=0xbfffef6c, __in_chrg=<optimized out>) at /usr/include/opencv2/core/mat.hpp:295
295     release();
(gdb) step
cv::Mat::release (this=0xbfffef6c) at /usr/include/opencv2/core/mat.hpp:381
381     if( refcount && CV_XADD(refcount, -1) == 1 )
(gdb) step
383     data = datastart = dataend = datalimit = 0;
(gdb) step
384     size.p[0] = 0;
(gdb) step
385     refcount = 0;
(gdb) step
386 }
(gdb) step
cv::Mat::~Mat (this=0xbfffef6c, __in_chrg=<optimized out>) at /usr/include/opencv2/core/mat.hpp:296
296     if( step.p != step.buf )
(gdb) step
298 }
(gdb) step
CreateShares::ConstructShares (this=0x80556d0, channel=..., k=2, n=4) at CreateShares.cpp:167
167     cv::Size s = temp1.size();
(gdb) step
cv::Mat::MSize::operator() (this=0xbffff284) at /usr/include/opencv2/core/mat.hpp:705
705     return Size(p[1], p[0]);
(gdb) step
cv::Size_<int>::Size_ (this=0xbffff2f8, _width=960, _height=960) at /usr/include/opencv2/core/operations.hpp:1624
1624        : width(_width), height(_height) {}
(gdb) step
cv::Mat::MSize::operator() (this=0xbffff284) at /usr/include/opencv2/core/mat.hpp:706
706 }
(gdb) step

解决方案

Most likely, the determinant is zero.

From Wikipedia:

A square matrix that is not invertible is called singular or degenerate. A square matrix is singular if and only if its determinant is 0.

You can display the determinant like so...

std::cout<<"determinant(temp1)="<<cv::determinant(temp1)<<"\n";

From the documentation for Mat::inv(), there are three methods to choose from:

  • DECOMP_LU (default) is the LU decomposition. The matrix must be non-singular.
  • DECOMP_CHOLESKY is the Cholesky decomposition for symmetrical positively defined matrices only. This type is about twice faster than LU on big matrices.
  • DECOMP_SVD is the SVD decomposition. If the matrix is singular or even non-square, the pseudo inversion is computed.

From the documentation for invert(), which is presumably used internally by Mat::inv():

In the case of DECOMP_LU method, the function returns the src determinant ( src must be square). If it is 0, the matrix is not inverted and dst is filled with zeros.

This agrees with the results that you are seeing.


notes about the math

I'm no mathematician, but I get the impression that inverting a matrix can be a messy business -- all the more so if your matrix is very large. In fact, it may be true that these inverses exist in principle, but are practically impossible to calculate with any accuracy. In running some experiments with your code, I found that in many cases I would get determinants that were not exactly zero, but were very close to zero -- perhaps indicating that numerical precision may be the limiting factor. I tried specifying the matrices using 64-bit values instead of 32, and got different, but not necessarily better answers.

It may be useful to recognize that, based on the way you are calculating the temp1 matrix, it will always be symmetric. The DECOMP_CHOLESKY method is specifically designed to work on symmetric positive definite matrices, so using that might provide some advantages.

Experimentally, I found that normalizing (as suggested by @cedrou) makes it more likely that the inverse function returns a non-zero matrix (with DECOMP_LU but not with DECOMP_CHOLESKY). However, based on my guesses of how you might be initializing the R matrix, the resulting matrices never seemed to satisfy the definition of an inverse: A*inverse(A)=Identity. But you don't necessarily care about that -- which is perhaps why the SVD method computes a pseudo inverse.

Finally, it seems that this deeper question of why inversion is failing might be a math question rather than a programming question. Based on that I did some searching on the math site, and it turns out that someone has already asked how to do this very thing: http://math.stackexchange.com/questions/182662


notes about debugging

Based on your debug trace, I am inclined to think that the part that you are interested in was compiled into a non-traceable library and skipped over when you ran step. In other words, that mysterious blank line after your first step represents the part where it actually ran the inv() function. After that it is assigning the result to temp2 and destructing temporary objects. So your debug trace doesn't tell us anything about what is happening inside of inv().

165     temp2 = temp1.inv();
(gdb) step

cv::Mat::operator= (this=0xbffff294, e=...) at /usr/include/opencv2/core/mat.hpp:1373
1373        e.op->assign(e, *this);

I ran a debugger on this myself and was able to trace through the inner call to invert() and watch it decide to fail based on an internal analysis of the matrix (determining that it was not invertible) -- and therefore return a matrix filled with zeros, matching what you have reported.

The invert() function is defined in cxlapack.cpp, in case you are interested in taking a look at the source code.

这篇关于Mat.inv()在opencv中产生所有零的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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