图像配准拼接算法

目录

一,问题背景

二,简单场景——绝对配准

1,基本代码

2,减少配准

3,实时配准

三,实际场景——非绝对配准

1,最小生成树

2,最优化


一,问题背景

在扫描一个区域图像时,由于各种原因,需要把一个区域划分成若干个小区域,各自单独扫描成图像。

由于扫描设备对小区域的定位存在误差,不能直接把小图拼成大图,需要配准拼接算法进行处理。

上游的把区域划分成小区域的算法,叫扫描规划算法。

配准拼接算法和扫描规划算法是息息相关,互相配合。

扫描规划算法会给出所有小图的理论位置(即所有小区域的位置),配准拼接算法会基于图像算出所有图片的实际位置,理论位置和实际位置的差值就是扫描设备的定位误差。

配准拼接算法的原理就是计算所有相邻两张小图的相对位置关系(即配准算法),再基于这个数据计算所有小图的位置。

因为配准算法的需要,扫描规划算法会让所有相邻两张小图之间都有重合区域。

二,简单场景——绝对配准

如果配准算法是绝对准确可靠的,那么根据配准算法的结果,用搜索算法即可得到完整大图。

1,基本代码

输入所有图片信息,计算所有配准结果,再拼接大图。


struct ImageInfo
{
	//图片内容和坐标等数据
};
struct Shift
{
	int x, y;//两张图片的配准结果
};
struct Pos
{
	int x, y;//小图坐标
};

class RegistrationStitch
{
public:
	RegistrationStitch(int row, int col, vector<ImageInfo>images) :row{ row }, col{ col }, images{ images }{}
	ImageInfo GetStitchImage()
	{
		Registration();
		vector<Pos> allPos = GetPos(shiftLR, shiftUD);
		return GetStitchImage(images, allPos);
	}
private:
	int GetId(int r, int c) //所有小图编号0到row*col-1
	{
		return r * col + c;
	}
	void Registration()//配准算法
	{
		for (int r = 0; r < row; r++) {
			for (int c = 0; c < col; c++) {
				if (r)shiftUD[GetId(r, c)] = Registration(images[GetId(r - 1, c)], images[GetId(r, c)]);
				if (c)shiftLR[GetId(r, c)] = Registration(images[GetId(r, c - 1)], images[GetId(r, c)]);
			}
		}
	}
	Shift Registration(ImageInfo image1, ImageInfo image2)//两张小图配准
	{
		return Shift{};
	}
	static vector<Pos> GetPos(map<int, Shift>& shiftLR, map<int, Shift>& shiftUD)
	{
		return vector<Pos>{};
	}
	static ImageInfo GetStitchImage(vector<ImageInfo>& images, vector<Pos>& allPos)
	{
		ImageInfo ans;
		for (int i = 0; i < images.size(); i++) {
			// ans = CopyImage(ans,images[i],allPos[i]);
		}
		return ans;
	}
private:
	int row, col;
	vector<ImageInfo>images;
	map<int, Shift> shiftLR;
	map<int, Shift> shiftUD;
}

这里的GetPos函数是static的,即只需要入参不需要图片等信息。其他私有静态成员函数同理。

GetPos里面省略的是一个BFS或者DFS算法,也可以用带权并查集。

2,减少配准

上面的伪代码进行了所有配准,其实只需要一部分。

以3*3为例,不需要做12次配准,只需要做8次配准。

不是任意8个配准就行,其实就是从一个9个点12条边的图中选出任意一颗生成树。

既然配准算法是绝对准确可靠的,那么任选一颗生成树,结果都是一样的。

其实可以选择一个固定方式的生成树,如上图(所有的左右配准加第一列的上下配准)

3,实时配准

如果想加快拼接出图的速度,可以一边扫描小图一边完成配准。


struct ImageInfo
{
	//图片内容和坐标等数据
};
struct Shift
{
	int x, y;//两张图片的配准结果
};
struct Pos
{
	int x, y;//小图坐标
};

class RegistrationStitch
{
public:
	RegistrationStitch(int row, int col) :row{ row }, col{ col }{}
	void Push(ImageInfo image)
	{
		images.push_back(image);
		Registration(); //每次传入一张小图,调用一次配准
	}
	ImageInfo GetStitchImage()
	{
		vector<Pos> allPos = GetPos(shiftLR, shiftUD);
		return GetStitchImage(images, allPos);
	}
private:
	int GetId(int r, int c) //所有小图编号0到row*col-1
	{
		return r * col + c;
	}
	void Registration()//配准算法
	{
		vector<pair<int, int>> pairs;
		// pairs = ... 计算当前传入小图和哪些小图需要配准
		for (auto p : pairs) {
			auto shift = Registration(images[p.first], images[p.second]);
			// shiftLR or shiftUD 存入结果shift
		}
	}
	Shift Registration(ImageInfo image1, ImageInfo image2)//两张小图配准
	{
		return Shift{};
	}
	static vector<Pos> GetPos(map<int, Shift>& shiftLR, map<int, Shift>& shiftUD)
	{
		return vector<Pos>{};
	}
	static ImageInfo GetStitchImage(vector<ImageInfo>& images, vector<Pos>& allPos)
	{
		ImageInfo ans;
		for (int i = 0; i < images.size(); i++) {
			// ans = CopyImage(ans,images[i],allPos[i]);
		}
		return ans;
	}
private:
	int row, col;
	vector<ImageInfo>images;
	map<int, Shift> shiftLR;
	map<int, Shift> shiftUD;
}

三,实际场景——非绝对配准

正常情况下配准都不是绝对准确可靠的。

一般来说2张图片的配准结果会有2类问题,多解、精度误差。

限制配准算法的搜索范围,能一定程度上减少多解问题。而精度误差是不可能完全消除了,这就带来一个问题,不同的生成树对应的拼接结果是不一样的。

所以在完成所有配准(而不是只有生成树)后,如何计算所有小图坐标?

有两类方法,第一类是最小生成树,第二类是最优化算法。

1,最小生成树

每个配准结果都有一个置信度,以此作为权值,选择最高置信度的生成树。

2,最优化

优化目标是一个row*col*2元函数,即每张图的x坐标和y坐标,

f(x_1,x_2...x_{r*c},y_1,y_2...y_{r*c})= \sum _{(i,j)\in S} ((x_i-x_j-cx_{i,j})^2+(y_i-y_j-cy_{i,j})^2)*z_{i,j}

其中S是所有的相邻图像对,cx和cy是前序流程算出的偏移量,z是对应的置信度。

求f的最小值。

求f的最小值,可以用无需初始解的加权最小二乘法,也可以用需要初始解的梯度类算法。

初始解可以用固定默认值,也可以用最小生成树的结果。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值