4

I'm reading source code of opencv: cvProjectPoints2, cvRodrigues2.

In cvProjectPoints2, the Jacobian matrix is first got using cvRodrigues2( &_r, &matR, &_dRdr );, and then used to calculate the partial derivative of pixels w.r.t the rvec (axis-angle representation)。

if( dpdr_p )
{
    double dx0dr[] =
    {
        X*dRdr[0] + Y*dRdr[1] + Z*dRdr[2],
        X*dRdr[9] + Y*dRdr[10] + Z*dRdr[11],
        X*dRdr[18] + Y*dRdr[19] + Z*dRdr[20]
    };
    double dy0dr[] =
    {
        X*dRdr[3] + Y*dRdr[4] + Z*dRdr[5],
        X*dRdr[12] + Y*dRdr[13] + Z*dRdr[14],
        X*dRdr[21] + Y*dRdr[22] + Z*dRdr[23]
    };
    double dz0dr[] =
    {
        X*dRdr[6] + Y*dRdr[7] + Z*dRdr[8],
        X*dRdr[15] + Y*dRdr[16] + Z*dRdr[17],
        X*dRdr[24] + Y*dRdr[25] + Z*dRdr[26]
    };
    for( j = 0; j < 3; j++ )
    {
        double dxdr = z*(dx0dr[j] - x*dz0dr[j]);
        double dydr = z*(dy0dr[j] - y*dz0dr[j]);
        double dr2dr = 2*x*dxdr + 2*y*dydr;
        double dcdist_dr = k[0]*dr2dr + 2*k[1]*r2*dr2dr + 3*k[4]*r4*dr2dr;
        double dicdist2_dr = -icdist2*icdist2*(k[5]*dr2dr + 2*k[6]*r2*dr2dr + 3*k[7]*r4*dr2dr);
        double da1dr = 2*(x*dydr + y*dxdr);
        double dmxdr = fx*(dxdr*cdist*icdist2 + x*dcdist_dr*icdist2 + x*cdist*dicdist2_dr +
                           k[2]*da1dr + k[3]*(dr2dr + 2*x*dxdr));
        double dmydr = fy*(dydr*cdist*icdist2 + y*dcdist_dr*icdist2 + y*cdist*dicdist2_dr +
                           k[2]*(dr2dr + 2*y*dydr) + k[3]*da1dr);
        dpdr_p[j] = dmxdr;
        dpdr_p[dpdr_step+j] = dmydr;
    }
    dpdr_p += dpdr_step*2;
}

The shape of dRdr is 3*9, and from how the indices of dRdr is used:

X*dRdr[0] + Y*dRdr[1] + Z*dRdr[2], //-> dx0dr1
X*dRdr[9] + Y*dRdr[10] + Z*dRdr[11], //-> dx0dr2
X*dRdr[18] + Y*dRdr[19] + Z*dRdr[20] //-> dx0dr3

the Jacobian matrix seems to be:

dR1/dr1, dR2/dr1, ..., dR9/dr1,
dR1/dr2, dR2/dr2, ..., dR9/dr2,
dR1/dr3, dR2/dr3, ..., dR9/dr3,

But to my knowledge the Jacobian matrix should be of shape 9*3, since it's derivatives of R(1~9) w.r.t r(1~3):

dR1/dr1, dR1/dr2, dR1/dr3,
dR2/dr1, dR2/dr2, dR2/dr3,
...
...
dR9/dr1, dR9/dr2, dR9/dr3,

As the docs of cvRodrigues2 says:

jacobian – Optional output Jacobian matrix, 3x9 or 9x3, which is a matrix of partial derivatives of the output array components with respect to the input array components.

So am I misunderstanding the code & docs? Or is the code using other convention? Or is it a bug (not likely...)?

zhangxaochen
  • 32,744
  • 15
  • 77
  • 108
  • Should have clarify the "3x9 or 9x3" part in the docs.. – iantonuk May 16 '17 at 13:10
  • You are indeed right with respect to math definition, I'll lookup what that part means – iantonuk May 16 '17 at 13:16
  • Any updates about this topic? I have the same issue when I use cv2.Rodrigues() function. When I pass a rotation vector, I get a rotation matrix as output and a 3x9 Jacobian instead of a 9x3. – ahmad seyfi Mar 02 '22 at 19:20

1 Answers1

1

If you look up the docs:

src – Input rotation vector (3x1 or 1x3) or rotation matrix (3x3).
dst – Output rotation matrix (3x3) or rotation vector (3x1 or 1x3), respectively.
jacobian – Optional output Jacobian matrix, 3x9 or 9x3, which is a matrix of partial derivatives of the output array components with respect to the input array components.

As you see you can switch source and destination places(mathematically it will be exactly transposition), but the code does not account for it.

Therefore, indeed you've got a transposed Jacobian, because you switched first arguments places(from default places for their types). Switch them again, and you'll get normal Jacobian!

iantonuk
  • 1,178
  • 8
  • 28
  • what do you mean by *"because you switched first arguments places"*? In my example code, **src** is a rvec (3x1), and **dst** is a rmat (3x3). If your **switch** mean "swap the src & dst", that will NOT get the Jacob-mat transposed, but each element of the matrix changed from `dR/dr` to `dr/dR` to my knowledge. – zhangxaochen May 17 '17 at 07:35
  • Try to do it and post the result. It will not change dR/dr to dr/dR for sure per docs, because they explicitly state 3x3 or 3x1 and won't misplace one for another. – iantonuk May 17 '17 at 08:17