首页 > 技术文章 > 图像配准系列之层次FFD形变配准

weijiakai 2021-02-19 12:45 原文

在前面的博文中,我们分别讲了使用FFD形变与梯度下降法、LM算法、粒子群算法来实现图像的非刚性配准:

图像配准系列之基于FFD形变与梯度下降法的图像配准

图像配准系列之基于FFD形变与LM算法的图像配准

图像配准系列之基于FFD形变与粒子群算法的图像配准

以上三篇博文所讲的配准方法中,有一个明显的共同点是:FFD形变的网格控制点数都是保持不变的。我们知道,理论上控制点越少,配准越快,但配准效果越差,控制点越多则配准越慢且配准效果越好。为了让配准效果好一点,我们往往一开始就把FFD形变的控制点设置得多一些,但是这同时导致了配准很耗时,而且,一开始控制点参数多还会有容易陷入局部极值的问题。为了加快配准速度,且减小陷入局部极值的概率,有研究人员提出了层次配准的方法:多次配准(通常3~5次就ok了),前一次配准的结果作为后一次配准的输入,第一次配准时设置较少的控制点,随后逐渐增加控制点。如下图所示:

下面我们使用C++与Opencv实现三次“FFD+梯度下降”的层次配准,在配准过程中逐渐增加控制点:8*8——>16*16——>30*30

绝大多数代码在前面的文章(上方的超链接)中都有贴出来过,此处不再重复,在此只给出实现层次配准的代码:

void ffd_match_test(void)
{
  Mat img1 = imread("wangge.png", CV_LOAD_IMAGE_GRAYSCALE);
  Mat img2 = imread("wangge1.png", CV_LOAD_IMAGE_GRAYSCALE);


  //第一层
  int row_block_num = 8;
  int col_block_num = 8;
  Mat grid_points;
  init_bpline_para(img1, row_block_num, col_block_num, grid_points, -0.001, 0.001);
  Mat out;
  bpline_match(img1, img2, out, row_block_num, col_block_num, grid_points);


  //第二层
  row_block_num = 16;
  col_block_num = 16;
  init_bpline_para(img1, row_block_num, col_block_num, grid_points, -0.001, 0.001);
  Mat out1;
  bpline_match(img1, out, out1, row_block_num, col_block_num, grid_points);


  //第三层
  row_block_num = 30;
  col_block_num = 30;
  init_bpline_para(img1, row_block_num, col_block_num, grid_points, -0.001, 0.001);
  Mat out2;
  bpline_match(img1, out1, out2, row_block_num, col_block_num, grid_points);


  imshow("img1", img1);
  imshow("img2", img2);
  imshow("out", out2);
  imshow("img1-img2", abs(img1-img2));
  imshow("img1-out", abs(img1-out2));
  waitKey();
}

运行上述代码,对扭曲的网格图像进行配准,结果如下。为了区分开来,我们称之前的一次配准为“单次配准”,本文讲的方法为“层次配准”。

参考图像

浮动图像

单次配准图像

层次配准图像

浮动图像与参考图像的差值图

单次配准图像与参考图像的差值图

层次配准图像与参考图像的差值图

由以上配准结果可知,单次配准陷入了局部极值,也即个别区域没能配准好,相比来说,层次配准的效果就好多了,不过由于层次配准经过了多次插值,导致图像变模糊了。从目标函数值的下降过程也可以看出来后者效果更好:

目标函数值下降过程

本人微信公众号如下,会不定时更新更精彩的内容,欢迎扫码关注:

推荐阅读