在前面的博文中,我们分别讲了使用FFD形变与梯度下降法、LM算法、粒子群算法来实现图像的非刚性配准:
以上三篇博文所讲的配准方法中,有一个明显的共同点是: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();
-
}
运行上述代码,对扭曲的网格图像进行配准,结果如下。为了区分开来,我们称之前的一次配准为“单次配准”,本文讲的方法为“层次配准”。
参考图像
浮动图像
单次配准图像
层次配准图像
浮动图像与参考图像的差值图
单次配准图像与参考图像的差值图
层次配准图像与参考图像的差值图
由以上配准结果可知,单次配准陷入了局部极值,也即个别区域没能配准好,相比来说,层次配准的效果就好多了,不过由于层次配准经过了多次插值,导致图像变模糊了。从目标函数值的下降过程也可以看出来后者效果更好:
目标函数值下降过程
本人微信公众号如下,会不定时更新更精彩的内容,欢迎扫码关注:
转载:https://blog.csdn.net/shandianfengfan/article/details/113875026