def register_scale2d(self, fixed, moving):
    sizex, sizey = moving.shape

    x0, y0 = np.mgrid[0:sizex,0:sizey]

    xc = float(sizex) / 2.0
    yc = float(sizey) / 2.0

    F = fixed
    M = moving

    G = SteeringGeneric.gaussian2(self, fixed.shape)

    D = G * (F - M)
    Dnorm = np.linalg.norm(D.ravel())

    Dnorm_ref = Dnorm

    I = np.identity(2, np.single)
    T = np.zeros((2,), np.single)

    scale = 1.0

    for iter in xrange(20):

      #print "2D diff", Dnorm

      S = I * scale
      dS = I

      Dnorm_prev = Dnorm

      D = G * (F - M)

      Mx, My = np.gradient(M)

      dScale = np.sum(D * (x0*Mx + y0*My))

      dT = np.zeros((2,), np.single)
      dT[0] = np.sum(D * Mx)
      dT[1] = np.sum(D * My)

      if iter == 0:
        stepScale = 0.2 / max(abs(dScale), 1e-5)
        stepT = 1.0 / max(np.max(np.abs(dT)), 1e-5)

      for sub_iter in xrange(20):
        scale_test = scale + dScale * stepScale

        T_test = T + dT * stepT

        Cx = (1.0 - scale_test) * xc
        Cy = (1.0 - scale_test) * yc

        x = x0*scale_test + T_test[0] + Cx
        y = y0*scale_test + T_test[1] + Cy

        M_test = SteeringGeneric.interp2(self, x, y, moving)

        D_test = G * (F - M_test)
        Dnorm_test = np.linalg.norm(D_test.ravel())
        if Dnorm_test < Dnorm_prev:
          stepScale *= 1.2
          stepT *= 1.2
          Dnorm = Dnorm_test
          scale = scale_test
          T = T_test
          M = M_test
          break
        else:
          stepScale *= 0.5
          stepT *= 0.5

      if abs(Dnorm-Dnorm_prev) < 1e-4 * abs(Dnorm-Dnorm_ref):
        break

    return scale, T
  def register_rigid2d(self, fixed, moving):
    sizex, sizey = moving.shape

    x0, y0 = np.mgrid[0:sizex,0:sizey]

    xc = float(sizex) / 2.0
    yc = float(sizey) / 2.0

    F = fixed
    M = moving

    G = SteeringGeneric.gaussian2(self, fixed.shape)

    D = G * (F - M)
    Dnorm = np.linalg.norm(D.ravel())

    Dnorm_ref = Dnorm

    R = np.identity(2, np.float32)
    T = np.zeros((2,), np.float32)

    angle = 0

    for iter in range(20):

      Dnorm_prev = Dnorm

      ca = math.cos(angle)
      sa = math.sin(angle)

      R = np.array([[ca, -sa], [sa, ca]], np.float32)
      dR = np.array([[-sa, -ca], [ca, -sa]], np.float32)

      D = G * (F - M)

      Mx, My = np.gradient(M)

      dRx = dR[0,0]*(x0-xc) + dR[0,1]*(y0-yc)
      dRy = dR[1,0]*(x0-xc) + dR[1,1]*(y0-yc)
      dAngle = np.sum(G * D * (dRx*Mx + dRy*My))

      dT = np.zeros((2,), np.float32)
      dT[0] = np.sum(D * Mx)
      dT[1] = np.sum(D * My)

      if iter == 0:
        stepAngle = 0.5 / max(abs(dAngle),1e-5)
        stepT = 1.0 / max(np.max(np.abs(dT)), 1e-5)


      for sub_iter in range(20):
        angle_test = angle + dAngle * stepAngle

        ca = math.cos(angle_test)
        sa = math.sin(angle_test)

        R = np.array([[ca, -sa], [sa, ca]], np.float32)

        Cx = xc - (R[0,0]*xc + R[0,1]*yc)
        Cy = yc - (R[1,0]*xc + R[1,1]*yc)

        T_test = T + dT * stepT

        x = R[0,0] * x0 + R[0,1] * y0 + T_test[0] + Cx
        y = R[1,0] * x0 + R[1,1] * y0 + T_test[1] + Cy
        M_test = SteeringGeneric.interp2(self, x, y, moving)

        D_test = G * (F - M_test)
        Dnorm_test = np.linalg.norm(D_test.ravel())
        if Dnorm_test < Dnorm_prev:
          stepAngle *= 1.2
          stepT *= 1.2
          M = M_test
          Dnorm = Dnorm_test
          angle = angle_test
          T = T_test
          break
        else:
          stepAngle *= 0.5
          stepT *= 0.5

      if abs(Dnorm-Dnorm_prev) < 1e-4 * abs(Dnorm-Dnorm_ref):
        break

    return R, T