Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/163.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ opencv:两个三维点云之间的刚性变换_C++_Opencv - Fatal编程技术网

C++ opencv:两个三维点云之间的刚性变换

C++ opencv:两个三维点云之间的刚性变换,c++,opencv,C++,Opencv,我有两个3D点云,我想使用opencv找到刚性变换矩阵(平移、旋转、所有3个轴之间的恒定缩放) 我找到了一个函数,但它显然只适用于二维点 此外,我还发现,它似乎不支持刚性转换模式 我需要只编写自己的刚性转换函数吗?我在OpenCV中没有找到所需的功能,因此我编写了自己的实现。基于……的想法 cv::Vec3d CalculateMean(常数cv::材料和点) { cv::Mat_u结果; cv::reduce(点数、结果、0、cv_reduce_平均值); 返回结果(0,0); } cv::M

我有两个3D点云,我想使用opencv找到刚性变换矩阵(平移、旋转、所有3个轴之间的恒定缩放)

我找到了一个函数,但它显然只适用于二维点

此外,我还发现,它似乎不支持刚性转换模式


我需要只编写自己的刚性转换函数吗?

我在OpenCV中没有找到所需的功能,因此我编写了自己的实现。基于……的想法

cv::Vec3d
CalculateMean(常数cv::材料和点)
{
cv::Mat_u结果;
cv::reduce(点数、结果、0、cv_reduce_平均值);
返回结果(0,0);
}
cv::Mat_
FindRigidTransform(常数cv::Mat_u和points1,常数cv::Mat_u和points2)
{
/*计算质心*/
cv::Vec3d t1=-CalculateMean(点1);
cv::Vec3d t2=-CalculateMean(点S2);
cv::Mat_Ut1=cv::Mat_Ut1::eye(4,4);
T1(0,3)=T1[0];
T1(1,3)=T1[1];
T1(2,3)=T1[2];
cv::Mat_uT2=cv::Mat_uuT2::eye(4,4);
T2(0,3)=-T2[0];
T2(1,3)=-T2[1];
T2(2,3)=-T2[2];
/*计算输入点的协方差矩阵。还计算与质心的均方根偏差
*用于比例计算。
*/
cv::Mat_C(3,3,0.0);
双p1Rms=0,p2Rms=0;
对于(int-ptIdx=0;ptIdx
我发现它是OpenCV的一个很好的附件。看看他们的照片。提供的示例注册两个点云,然后显示刚性变换。

以下是我的rmsd代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>

typedef struct
{
  float m[4][4];
} MATRIX;

#define vdiff2(a,b) ( ((a)[0]-(b)[0]) * ((a)[0]-(b)[0]) +   \
  ((a)[1]-(b)[1]) * ((a)[1]-(b)[1]) + \
  ((a)[2]-(b)[2]) * ((a)[2]-(b)[2]) )

static double alignedrmsd(float *v1, float *v2, int N);
static void centroid(float *ret, float *v, int N);
static int getalignmtx(float *v1, float *v2, int N, MATRIX *mtx);
static void crossproduct(float *ans, float *pt1, float *pt2);
static void mtx_root(MATRIX *mtx);
static int almostequal(MATRIX *a, MATRIX *b);
static void mulpt(MATRIX *mtx, float *pt);
static void mtx_mul(MATRIX *ans, MATRIX *x, MATRIX *y);
static void mtx_identity(MATRIX *mtx);
static void mtx_trans(MATRIX *mtx, float x, float y, float z);
static int mtx_invert(float *mtx, int N);
static float absmaxv(float *v, int N);

/*
  calculate rmsd between two structures
  Params: v1 - first set of points
          v2 - second set of points
          N - number of points
          mtx - return for transfrom matrix used to align structures
  Returns: rmsd score
  Notes: mtx can be null. Transform will be rigid. Inputs must
         be previously aligned for sequence alignment
 */
double rmsd(float *v1, float *v2, int N, float *mtx)
{
  float cent1[3];
  float cent2[3];
  MATRIX tmtx;
  MATRIX tempmtx;
  MATRIX move1;
  MATRIX move2;
  int i;
  double answer;
  float *temp1 = 0;
  float *temp2 = 0;
  int err;

  assert(N > 3);

  temp1 = malloc(N * 3 * sizeof(float));
  temp2 = malloc(N * 3 * sizeof(float));
  if(!temp1 || !temp2)
    goto error_exit;

  centroid(cent1, v1, N);
  centroid(cent2, v2, N);
  for(i=0;i<N;i++)
  {
    temp1[i*3+0] = v1[i*3+0] - cent1[0];
    temp1[i*3+1] = v1[i*3+1] - cent1[1];
    temp1[i*3+2] = v1[i*3+2] - cent1[2];

    temp2[i*3+0] = v2[i*3+0] - cent2[0];
    temp2[i*3+1] = v2[i*3+1] - cent2[1];
    temp2[i*3+2] = v2[i*3+2] - cent2[2];
  }

  err = getalignmtx(temp1, temp2, N, &tmtx);
  if(err == -1)
    goto error_exit;

  mtx_trans(&move1, -cent2[0], -cent2[1], -cent2[2]);
  mtx_mul(&tempmtx, &move1, &tmtx);
  mtx_trans(&move2, cent1[0], cent1[1], cent1[2]);
  mtx_mul(&tmtx, &tempmtx, &move2);
  memcpy(temp2, v2, N * sizeof(float) * 3);
  for(i=0;i<N;i++)
    mulpt(&tmtx, temp2 + i * 3);
  answer = alignedrmsd(v1, temp2, N);
  free(temp1);
  free(temp2);
  if(mtx)
    memcpy(mtx, &tmtx.m, 16 * sizeof(float));

  return answer;
 error_exit:
  free(temp1);
  free(temp2);
  if(mtx)
  {
    for(i=0;i<16;i++)
      mtx[i] = 0;
  }
  return sqrt(-1.0);
}

/*
  calculate rmsd between two aligned structures (trivial)
  Params: v1 - first structure
          v2 - second structure
          N - number of points
  Returns: rmsd
 */
static double alignedrmsd(float *v1, float *v2, int N)
{
  double answer =0;
  int i;

  for(i=0;i<N;i++)
    answer += vdiff2(v1 + i *3, v2 + i * 3);
  return sqrt(answer/N);
}

/*
  compute the centroid
 */
static void centroid(float *ret, float *v, int N)
{
  int i;

  ret[0] = 0;
  ret[1] = 0;
  ret[2] = 0;
  for(i=0;i<N;i++)
  {
    ret[0] += v[i*3+0];
    ret[1] += v[i*3+1];
    ret[2] += v[i*3+2];
  }
  ret[0] /= N;
  ret[1] /= N;
  ret[2] /= N;
}

/*
  get the matrix needed to align two structures
  Params: v1 - reference structure
          v2 - structure to align
          N - number of points
          mtx - return for rigid body alignment matrix
  Notes: only calculates rotation part of matrix.
         assumes input has been aligned to centroids 
 */
static int getalignmtx(float *v1, float *v2, int N, MATRIX *mtx)
{
  MATRIX A = { {{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,1}} };
  MATRIX At;
  MATRIX Ainv;
  MATRIX temp;
  float tv[3];
  float tw[3];
  float tv2[3];
  float tw2[3];
  int k, i, j;
  int flag = 0;
  float correction;

  correction = absmaxv(v1, N * 3) * absmaxv(v2, N * 3);

  for(k=0;k<N;k++)
    for(i=0;i<3;i++)
      for(j=0;j<3;j++)
    A.m[i][j] += (v1[k*3+i] * v2[k*3+j])/correction;

  while(flag < 3)
  {
    for(i=0;i<4;i++)
      for(j=0;j<4;j++)
        At.m[i][j] = A.m[j][i];

    memcpy(&Ainv, &A, sizeof(MATRIX));
    /* this will happen if all points are in a plane */
    if( mtx_invert((float *) &Ainv, 4) == -1)
    {
      if(flag == 0)
      {
        crossproduct(tv, v1, v1+3);
        crossproduct(tw, v2, v2+3);
      }
      else
      {
        crossproduct(tv2, tv, v1);
        crossproduct(tw2, tw, v2);
        memcpy(tv, tv2, 3 * sizeof(float));
        memcpy(tw, tw2, 3 * sizeof(float));
      }
      for(i=0;i<3;i++)
        for(j=0;j<3;j++)
      A.m[i][j] += tv[i] * tw[j];

      flag++;
    }
    else
      flag = 5;
  }
  if(flag != 5)
    return -1;

  mtx_mul(&temp, &At, &A);
  mtx_root(&temp);
  mtx_mul(mtx, &temp, &Ainv); 
  return 0;
}

/*
  get the crossproduct of two vectors.
  Params: ans - return pinter for answer.
          pt1 - first vector
          pt2 - second vector.
  Notes: crossproduct is at right angles to the two vectors.
*/
static void crossproduct(float *ans, float *pt1, float *pt2)
{
  ans[0] = pt1[1] * pt2[2] - pt1[2] * pt2[1];
  ans[1] = pt1[0] * pt2[2] - pt1[2] * pt2[0];
  ans[2] = pt1[0] * pt2[1] - pt1[1] * pt2[0];
}

/*
  Denman-Beavers square root iteration
 */
static void mtx_root(MATRIX *mtx)
{
  MATRIX Y = *mtx;
  MATRIX Z;
  MATRIX Y1;
  MATRIX Z1;
  MATRIX invY;
  MATRIX invZ;
  MATRIX Y2;
  int iter = 0;
  int i, ii;

  mtx_identity(&Z);

  do
  {
    invY = Y;
    invZ = Z;
    if( mtx_invert((float *) &invY, 4) == -1)
      return;
    if( mtx_invert((float *) &invZ, 4) == -1)
      return;
    for(i=0;i<4;i++)
      for(ii=0;ii<4;ii++)
      {
        Y1.m[i][ii] = 0.5 * (Y.m[i][ii] + invZ.m[i][ii]);
    Z1.m[i][ii] = 0.5 * (Z.m[i][ii] + invY.m[i][ii]);
      }
    Y = Y1;
    Z = Z1;

    mtx_mul(&Y2, &Y, &Y);
  }
  while(!almostequal(&Y2, mtx) && iter++ < 20 );

  *mtx = Y;
}

/*
  Check two matrices for near-enough equality
  Params: a - first matrix
          b - second matrix
  Returns: 1 if almost equal, else 0, epsilon 0.0001f.
 */
static int almostequal(MATRIX *a, MATRIX *b)
{
  int i, ii;
  float epsilon = 0.001f;

  for(i=0;i<4;i++)
    for(ii=0;ii<4;ii++)
      if(fabs(a->m[i][ii] - b->m[i][ii]) > epsilon) 
        return 0;
  return 1;
}  

/*
  multiply a point by a matrix.
  Params: mtx - matrix
          pt - the point (transformed)
*/
static void mulpt(MATRIX *mtx, float *pt)
{
  float ans[4] = {0};
  int i;
  int ii;

  for(i=0;i<4;i++)
  {
    for(ii=0;ii<3;ii++)
    {
      ans[i] += pt[ii] * mtx->m[ii][i];
    }
    ans[i] += mtx->m[3][i];
  }
  pt[0] = ans[0];
  pt[1] = ans[1];
  pt[2] = ans[2];
} 

/*
  multiply two matrices.
  Params: ans - return pointer for answer.
          x - first matrix
          y - second matrix.
  Notes: ans may not be equal to x or y.
*/
static void mtx_mul(MATRIX *ans, MATRIX *x, MATRIX *y)
{
  int i;
  int ii;
  int iii;

  for(i=0;i<4;i++)
    for(ii=0;ii<4;ii++)
    {
      ans->m[i][ii] = 0;
      for(iii=0;iii<4;iii++)
        ans->m[i][ii] += x->m[i][iii] * y->m[iii][ii];
    }
}


/*
  create an identity matrix.
  Params: mtx - return pointer.
*/
static void mtx_identity(MATRIX *mtx)
{
  int i;
  int ii;

  for(i=0;i<4;i++)
    for(ii=0;ii<4;ii++)
    {
      if(i==ii)
        mtx->m[i][ii] = 1.0f;
      else
        mtx->m[i][ii] = 0;
    }
}

/*
  create a translation matrix.
  Params: mtx - return pointer for matrix.
          x - x translation.
          y - y translation.
          z - z translation
*/
static void mtx_trans(MATRIX *mtx, float x, float y, float z)
{
  mtx->m[0][0] = 1;
  mtx->m[0][1] = 0;
  mtx->m[0][2] = 0;
  mtx->m[0][3] = 0;

  mtx->m[1][0] = 0;
  mtx->m[1][1] = 1;
  mtx->m[1][2] = 0;
  mtx->m[1][3] = 0;

  mtx->m[2][0] = 0;
  mtx->m[2][1] = 0;
  mtx->m[2][2] = 1;
  mtx->m[2][3] = 0;

  mtx->m[3][0] = x;
  mtx->m[3][1] = y;
  mtx->m[3][2] = z;
  mtx->m[3][3] = 1; 
}

/*
   matrix invert routine
  Params: mtx - the matrix in raw format, in/out
          N - width and height
  Returns: 0 on success, -1 on fail
 */
static int mtx_invert(float *mtx, int N)
{
  int indxc[100]; /* these 100s are the only restriction on matrix size */
  int indxr[100];
  int ipiv[100];
  int i, j, k;
  int irow, icol;
  double big;
  double pinv;
  int l, ll;
  double dum;
  double temp;

  assert(N <= 100);

  for(i=0;i<N;i++)
    ipiv[i] = 0;

  for(i=0;i<N;i++)
  {
    big = 0.0;

    /* find biggest element */
    for(j=0;j<N;j++)
      if(ipiv[j] != 1)
        for(k=0;k<N;k++)
          if(ipiv[k] == 0)
            if(fabs(mtx[j*N+k]) >= big)
        {
           big = fabs(mtx[j*N+k]);
               irow = j;
               icol = k;
        }       

    ipiv[icol]=1;

    if(irow != icol)
      for(l=0;l<N;l++)
      {
        temp = mtx[irow * N + l];
        mtx[irow * N + l] = mtx[icol * N + l];
    mtx[icol * N + l] = temp;
      }

    indxr[i] = irow;
    indxc[i] = icol;


    /* if biggest element is zero matrix is singular, bail */
    if(mtx[icol* N + icol] == 0)
       goto error_exit;

    pinv = 1.0/mtx[icol * N + icol];

    mtx[icol * N + icol] = 1.0;

    for(l=0;l<N;l++)
      mtx[icol * N + l] *= pinv;

    for(ll=0;ll<N;ll++)
      if(ll != icol)
      {
        dum = mtx[ll * N + icol];
        mtx[ll * N + icol] = 0.0;
        for(l=0;l<N;l++) 
          mtx[ll * N + l] -= mtx[icol * N + l]*dum;
      }
  }                


  /* unscramble matrix */
  for (l=N-1;l>=0;l--) 
  {
    if (indxr[l] != indxc[l])
    for (k=0;k<N;k++)
    {
      temp = mtx[k * N + indxr[l]];
      mtx[k * N + indxr[l]] = mtx[k * N + indxc[l]];
      mtx[k * N + indxc[l]] = temp;
    }
  } 

  return 0;

 error_exit:
  return -1;
}

/*
  get the asolute maximum of an array
 */
static float absmaxv(float *v, int N)
{
  float answer;
  int i;

  for(i=0;i<N;i++)
    if(answer < fabs(v[i]))
      answer = fabs(v[i]);
  return answer;
}

#include <stdio.h>

/*
  debug utlitiy
 */
static void printmtx(FILE *fp, MATRIX *mtx)
{
  int i, ii;

  for(i=0;i<4;i++)
  {
    for(ii=0;ii<4;ii++)
      fprintf(fp, "%f, ", mtx->m[i][ii]);
    fprintf(fp, "\n");
  }
}

int rmsdmain(void)
{
  float one[4*3] = {0,0,0, 1,0,0, 2,1,0, 0,3,1};
  float two[4*3] = {0,0,0, 0,1,0, 1,2,0, 3,0,1};
  MATRIX mtx;
  double diff;
  int i;

  diff = rmsd(one, two, 4, (float *) &mtx.m);
  printf("%f\n", diff);
  printmtx(stdout, &mtx);
  for(i=0;i<4;i++)
  {
    mulpt(&mtx, two + i * 3);
    printf("%f %f %f\n", two[i*3], two[i*3+1], two[i*3+2]);
  }
  return 0;
}
#包括
#包括
#包括
#包括
#包括
类型定义结构
{
浮动m[4][4];
}基质;
#定义vdiff2(a,b)((a)[0]-(b)[0])*((a)[0]-(b)[0])+\
((a)[1]-(b)[1])*((a)[1]-(b)[1])+\
((a)[2]-(b)[2])*((a)[2]-(b)[2]))
静态双对齐MSD(浮点*v1,浮点*v2,整数N);
静态空洞形心(浮点数*ret,浮点数*v,整数N);
静态int-getalignmtx(浮点*v1,浮点*v2,int-N,矩阵*mtx);
静态空隙交叉积(浮点数*ans,浮点数*pt1,浮点数*pt2);
静态无效mtx_根(矩阵*mtx);
静态int-almostequal(矩阵*a,矩阵*b);
静态空隙率mulpt(矩阵*mtx,浮动*pt);
静态空隙mtx_mul(矩阵*ans,矩阵*x,矩阵*y);
静态无效mtx_恒等式(矩阵*mtx);
静态无效mtx_trans(矩阵*mtx,浮点x,浮点y,浮点z);
静态整数mtx_反转(浮点*mtx,整数N);
静态浮点absmaxv(浮点*v,整数N);
/*
计算两个结构之间的rmsd
参数:v1-第一组点
v2-第二组点
N-点数
mtx-用于对齐结构的转换矩阵的返回
返回:rmsd分数
注意:mtx可以为空。变换将是刚性的。输入必须
为序列对齐而预先对齐
*/
双rmsd(浮点*v1,浮点*v2,整数N,浮点*mtx)
{
浮动中心1[3];
浮动中心2[3];
矩阵tmtx;
矩阵tempTx;
基质移动1;
基质2;
int i;
双重回答;
浮点*temp1=0;
浮点*temp2=0;
INTERR;
断言(N>3);
temp1=malloc(N*3*sizeof(float));
temp2=malloc(N*3*sizeof(float));
如果(!temp1 | |!temp2)
转到错误退出;
质心(cent1,v1,N);
质心(cent2,v2,N);
对于(i=0;im[2][3]=0;
mtx->m[3][0]=x;
mtx->m[3][1]=y;
mtx->m[3][2]=z;
mtx->m[3][3]=1;
}
/*
矩阵求逆程序
参数:mtx-原始格式的矩阵,输入/输出
N-宽度和高度
返回:成功时为0,失败时为1
*/
静态整数mtx_反转(浮点*mtx,整数N)
{
int indxc[100];/*这100是对矩阵大小的唯一限制*/
int-indxr[100];
int ipiv[100];
int i,j,k;
int irow,icol;
双大;
双品脱;
int l,ll;
双dum;
双温;

assert(N estimateAffine3D似乎完全符合您的要求,不是吗?给定两个“点云”,也就是说,每个都不是4个完全不同的点,不可能创建一个不是估计值的变换。4个完全不同的点定义了3个完全独立的向量。欠定义的点越少,过度定义的点就越多。此函数按名称执行,返回最佳估计值,即e或更小对应于有些嘈杂的点所经历的变换的“平均值”。谢谢。我确实想估计,但我想要一个刚性变换,即没有剪切之类的东西。在我看来,estimateAffine3D不支持这一点,除非我弄错了。很晚了,但不知道这是否有帮助:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>

typedef struct
{
  float m[4][4];
} MATRIX;

#define vdiff2(a,b) ( ((a)[0]-(b)[0]) * ((a)[0]-(b)[0]) +   \
  ((a)[1]-(b)[1]) * ((a)[1]-(b)[1]) + \
  ((a)[2]-(b)[2]) * ((a)[2]-(b)[2]) )

static double alignedrmsd(float *v1, float *v2, int N);
static void centroid(float *ret, float *v, int N);
static int getalignmtx(float *v1, float *v2, int N, MATRIX *mtx);
static void crossproduct(float *ans, float *pt1, float *pt2);
static void mtx_root(MATRIX *mtx);
static int almostequal(MATRIX *a, MATRIX *b);
static void mulpt(MATRIX *mtx, float *pt);
static void mtx_mul(MATRIX *ans, MATRIX *x, MATRIX *y);
static void mtx_identity(MATRIX *mtx);
static void mtx_trans(MATRIX *mtx, float x, float y, float z);
static int mtx_invert(float *mtx, int N);
static float absmaxv(float *v, int N);

/*
  calculate rmsd between two structures
  Params: v1 - first set of points
          v2 - second set of points
          N - number of points
          mtx - return for transfrom matrix used to align structures
  Returns: rmsd score
  Notes: mtx can be null. Transform will be rigid. Inputs must
         be previously aligned for sequence alignment
 */
double rmsd(float *v1, float *v2, int N, float *mtx)
{
  float cent1[3];
  float cent2[3];
  MATRIX tmtx;
  MATRIX tempmtx;
  MATRIX move1;
  MATRIX move2;
  int i;
  double answer;
  float *temp1 = 0;
  float *temp2 = 0;
  int err;

  assert(N > 3);

  temp1 = malloc(N * 3 * sizeof(float));
  temp2 = malloc(N * 3 * sizeof(float));
  if(!temp1 || !temp2)
    goto error_exit;

  centroid(cent1, v1, N);
  centroid(cent2, v2, N);
  for(i=0;i<N;i++)
  {
    temp1[i*3+0] = v1[i*3+0] - cent1[0];
    temp1[i*3+1] = v1[i*3+1] - cent1[1];
    temp1[i*3+2] = v1[i*3+2] - cent1[2];

    temp2[i*3+0] = v2[i*3+0] - cent2[0];
    temp2[i*3+1] = v2[i*3+1] - cent2[1];
    temp2[i*3+2] = v2[i*3+2] - cent2[2];
  }

  err = getalignmtx(temp1, temp2, N, &tmtx);
  if(err == -1)
    goto error_exit;

  mtx_trans(&move1, -cent2[0], -cent2[1], -cent2[2]);
  mtx_mul(&tempmtx, &move1, &tmtx);
  mtx_trans(&move2, cent1[0], cent1[1], cent1[2]);
  mtx_mul(&tmtx, &tempmtx, &move2);
  memcpy(temp2, v2, N * sizeof(float) * 3);
  for(i=0;i<N;i++)
    mulpt(&tmtx, temp2 + i * 3);
  answer = alignedrmsd(v1, temp2, N);
  free(temp1);
  free(temp2);
  if(mtx)
    memcpy(mtx, &tmtx.m, 16 * sizeof(float));

  return answer;
 error_exit:
  free(temp1);
  free(temp2);
  if(mtx)
  {
    for(i=0;i<16;i++)
      mtx[i] = 0;
  }
  return sqrt(-1.0);
}

/*
  calculate rmsd between two aligned structures (trivial)
  Params: v1 - first structure
          v2 - second structure
          N - number of points
  Returns: rmsd
 */
static double alignedrmsd(float *v1, float *v2, int N)
{
  double answer =0;
  int i;

  for(i=0;i<N;i++)
    answer += vdiff2(v1 + i *3, v2 + i * 3);
  return sqrt(answer/N);
}

/*
  compute the centroid
 */
static void centroid(float *ret, float *v, int N)
{
  int i;

  ret[0] = 0;
  ret[1] = 0;
  ret[2] = 0;
  for(i=0;i<N;i++)
  {
    ret[0] += v[i*3+0];
    ret[1] += v[i*3+1];
    ret[2] += v[i*3+2];
  }
  ret[0] /= N;
  ret[1] /= N;
  ret[2] /= N;
}

/*
  get the matrix needed to align two structures
  Params: v1 - reference structure
          v2 - structure to align
          N - number of points
          mtx - return for rigid body alignment matrix
  Notes: only calculates rotation part of matrix.
         assumes input has been aligned to centroids 
 */
static int getalignmtx(float *v1, float *v2, int N, MATRIX *mtx)
{
  MATRIX A = { {{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,1}} };
  MATRIX At;
  MATRIX Ainv;
  MATRIX temp;
  float tv[3];
  float tw[3];
  float tv2[3];
  float tw2[3];
  int k, i, j;
  int flag = 0;
  float correction;

  correction = absmaxv(v1, N * 3) * absmaxv(v2, N * 3);

  for(k=0;k<N;k++)
    for(i=0;i<3;i++)
      for(j=0;j<3;j++)
    A.m[i][j] += (v1[k*3+i] * v2[k*3+j])/correction;

  while(flag < 3)
  {
    for(i=0;i<4;i++)
      for(j=0;j<4;j++)
        At.m[i][j] = A.m[j][i];

    memcpy(&Ainv, &A, sizeof(MATRIX));
    /* this will happen if all points are in a plane */
    if( mtx_invert((float *) &Ainv, 4) == -1)
    {
      if(flag == 0)
      {
        crossproduct(tv, v1, v1+3);
        crossproduct(tw, v2, v2+3);
      }
      else
      {
        crossproduct(tv2, tv, v1);
        crossproduct(tw2, tw, v2);
        memcpy(tv, tv2, 3 * sizeof(float));
        memcpy(tw, tw2, 3 * sizeof(float));
      }
      for(i=0;i<3;i++)
        for(j=0;j<3;j++)
      A.m[i][j] += tv[i] * tw[j];

      flag++;
    }
    else
      flag = 5;
  }
  if(flag != 5)
    return -1;

  mtx_mul(&temp, &At, &A);
  mtx_root(&temp);
  mtx_mul(mtx, &temp, &Ainv); 
  return 0;
}

/*
  get the crossproduct of two vectors.
  Params: ans - return pinter for answer.
          pt1 - first vector
          pt2 - second vector.
  Notes: crossproduct is at right angles to the two vectors.
*/
static void crossproduct(float *ans, float *pt1, float *pt2)
{
  ans[0] = pt1[1] * pt2[2] - pt1[2] * pt2[1];
  ans[1] = pt1[0] * pt2[2] - pt1[2] * pt2[0];
  ans[2] = pt1[0] * pt2[1] - pt1[1] * pt2[0];
}

/*
  Denman-Beavers square root iteration
 */
static void mtx_root(MATRIX *mtx)
{
  MATRIX Y = *mtx;
  MATRIX Z;
  MATRIX Y1;
  MATRIX Z1;
  MATRIX invY;
  MATRIX invZ;
  MATRIX Y2;
  int iter = 0;
  int i, ii;

  mtx_identity(&Z);

  do
  {
    invY = Y;
    invZ = Z;
    if( mtx_invert((float *) &invY, 4) == -1)
      return;
    if( mtx_invert((float *) &invZ, 4) == -1)
      return;
    for(i=0;i<4;i++)
      for(ii=0;ii<4;ii++)
      {
        Y1.m[i][ii] = 0.5 * (Y.m[i][ii] + invZ.m[i][ii]);
    Z1.m[i][ii] = 0.5 * (Z.m[i][ii] + invY.m[i][ii]);
      }
    Y = Y1;
    Z = Z1;

    mtx_mul(&Y2, &Y, &Y);
  }
  while(!almostequal(&Y2, mtx) && iter++ < 20 );

  *mtx = Y;
}

/*
  Check two matrices for near-enough equality
  Params: a - first matrix
          b - second matrix
  Returns: 1 if almost equal, else 0, epsilon 0.0001f.
 */
static int almostequal(MATRIX *a, MATRIX *b)
{
  int i, ii;
  float epsilon = 0.001f;

  for(i=0;i<4;i++)
    for(ii=0;ii<4;ii++)
      if(fabs(a->m[i][ii] - b->m[i][ii]) > epsilon) 
        return 0;
  return 1;
}  

/*
  multiply a point by a matrix.
  Params: mtx - matrix
          pt - the point (transformed)
*/
static void mulpt(MATRIX *mtx, float *pt)
{
  float ans[4] = {0};
  int i;
  int ii;

  for(i=0;i<4;i++)
  {
    for(ii=0;ii<3;ii++)
    {
      ans[i] += pt[ii] * mtx->m[ii][i];
    }
    ans[i] += mtx->m[3][i];
  }
  pt[0] = ans[0];
  pt[1] = ans[1];
  pt[2] = ans[2];
} 

/*
  multiply two matrices.
  Params: ans - return pointer for answer.
          x - first matrix
          y - second matrix.
  Notes: ans may not be equal to x or y.
*/
static void mtx_mul(MATRIX *ans, MATRIX *x, MATRIX *y)
{
  int i;
  int ii;
  int iii;

  for(i=0;i<4;i++)
    for(ii=0;ii<4;ii++)
    {
      ans->m[i][ii] = 0;
      for(iii=0;iii<4;iii++)
        ans->m[i][ii] += x->m[i][iii] * y->m[iii][ii];
    }
}


/*
  create an identity matrix.
  Params: mtx - return pointer.
*/
static void mtx_identity(MATRIX *mtx)
{
  int i;
  int ii;

  for(i=0;i<4;i++)
    for(ii=0;ii<4;ii++)
    {
      if(i==ii)
        mtx->m[i][ii] = 1.0f;
      else
        mtx->m[i][ii] = 0;
    }
}

/*
  create a translation matrix.
  Params: mtx - return pointer for matrix.
          x - x translation.
          y - y translation.
          z - z translation
*/
static void mtx_trans(MATRIX *mtx, float x, float y, float z)
{
  mtx->m[0][0] = 1;
  mtx->m[0][1] = 0;
  mtx->m[0][2] = 0;
  mtx->m[0][3] = 0;

  mtx->m[1][0] = 0;
  mtx->m[1][1] = 1;
  mtx->m[1][2] = 0;
  mtx->m[1][3] = 0;

  mtx->m[2][0] = 0;
  mtx->m[2][1] = 0;
  mtx->m[2][2] = 1;
  mtx->m[2][3] = 0;

  mtx->m[3][0] = x;
  mtx->m[3][1] = y;
  mtx->m[3][2] = z;
  mtx->m[3][3] = 1; 
}

/*
   matrix invert routine
  Params: mtx - the matrix in raw format, in/out
          N - width and height
  Returns: 0 on success, -1 on fail
 */
static int mtx_invert(float *mtx, int N)
{
  int indxc[100]; /* these 100s are the only restriction on matrix size */
  int indxr[100];
  int ipiv[100];
  int i, j, k;
  int irow, icol;
  double big;
  double pinv;
  int l, ll;
  double dum;
  double temp;

  assert(N <= 100);

  for(i=0;i<N;i++)
    ipiv[i] = 0;

  for(i=0;i<N;i++)
  {
    big = 0.0;

    /* find biggest element */
    for(j=0;j<N;j++)
      if(ipiv[j] != 1)
        for(k=0;k<N;k++)
          if(ipiv[k] == 0)
            if(fabs(mtx[j*N+k]) >= big)
        {
           big = fabs(mtx[j*N+k]);
               irow = j;
               icol = k;
        }       

    ipiv[icol]=1;

    if(irow != icol)
      for(l=0;l<N;l++)
      {
        temp = mtx[irow * N + l];
        mtx[irow * N + l] = mtx[icol * N + l];
    mtx[icol * N + l] = temp;
      }

    indxr[i] = irow;
    indxc[i] = icol;


    /* if biggest element is zero matrix is singular, bail */
    if(mtx[icol* N + icol] == 0)
       goto error_exit;

    pinv = 1.0/mtx[icol * N + icol];

    mtx[icol * N + icol] = 1.0;

    for(l=0;l<N;l++)
      mtx[icol * N + l] *= pinv;

    for(ll=0;ll<N;ll++)
      if(ll != icol)
      {
        dum = mtx[ll * N + icol];
        mtx[ll * N + icol] = 0.0;
        for(l=0;l<N;l++) 
          mtx[ll * N + l] -= mtx[icol * N + l]*dum;
      }
  }                


  /* unscramble matrix */
  for (l=N-1;l>=0;l--) 
  {
    if (indxr[l] != indxc[l])
    for (k=0;k<N;k++)
    {
      temp = mtx[k * N + indxr[l]];
      mtx[k * N + indxr[l]] = mtx[k * N + indxc[l]];
      mtx[k * N + indxc[l]] = temp;
    }
  } 

  return 0;

 error_exit:
  return -1;
}

/*
  get the asolute maximum of an array
 */
static float absmaxv(float *v, int N)
{
  float answer;
  int i;

  for(i=0;i<N;i++)
    if(answer < fabs(v[i]))
      answer = fabs(v[i]);
  return answer;
}

#include <stdio.h>

/*
  debug utlitiy
 */
static void printmtx(FILE *fp, MATRIX *mtx)
{
  int i, ii;

  for(i=0;i<4;i++)
  {
    for(ii=0;ii<4;ii++)
      fprintf(fp, "%f, ", mtx->m[i][ii]);
    fprintf(fp, "\n");
  }
}

int rmsdmain(void)
{
  float one[4*3] = {0,0,0, 1,0,0, 2,1,0, 0,3,1};
  float two[4*3] = {0,0,0, 0,1,0, 1,2,0, 3,0,1};
  MATRIX mtx;
  double diff;
  int i;

  diff = rmsd(one, two, 4, (float *) &mtx.m);
  printf("%f\n", diff);
  printmtx(stdout, &mtx);
  for(i=0;i<4;i++)
  {
    mulpt(&mtx, two + i * 3);
    printf("%f %f %f\n", two[i*3], two[i*3+1], two[i*3+2]);
  }
  return 0;
}