多角度的模板匹配
背景介绍
熟悉OpenCV的朋友肯定都知道OpenCV自带的模板匹配matchTemplate方法是不支持旋转的,也就是说当目标和模板有角度差异时匹配常常会失败,可能目标只是轻微的旋转,匹配分数就会下降很多,导致匹配精度下降甚至匹配出错。另一个方法是matchShape(形状匹配),匹配时需要轮廓分明才容易匹配成功,但无法的到匹配角度,也不方便使用。本文介绍基于matchTemplate + 旋转 + 金字塔下采样实现多角度的模板匹配,返回匹配结果(斜矩形的端点、角度、匹配得分)。
实现思路
【1】如何适应目标的角度变化?
- 我们可以将模板旋转,从0~360依次匹配找到最佳的匹配位置
【2】如何提高匹配速度?
- 使用金字塔下采样,将模板和待匹配图均缩小后匹配;加大匹配搜寻角度的步长,比如从每1匹配一次改为每5匹配一次等。
实现步骤:
【1】旋转模板图像。
旋转图像本身比较简单,下面是代码:
//旋转图像
Mat ImageRotate(Mat image, double angle)
{
Mat newImg;
Point2f pt = Point2f((float)image.cols / 2, (float)image.rows / 2);
Mat M = getRotationMatrix2D(pt, angle, 1.0);
warpAffine(image, newImg, M, image.size());
return newImg;
}
但需要注意,很多时候按照上面方法旋转时,会丢失模板信息产生黑边,这里提供两种方法供大家参考尝试:
① 旋转时放大目标图像尺寸,保证模板图像上信息不丢失,然后模板匹配时使用mask;
② 旋转时不放大目标图像尺寸,剔除黑边剩余部分做mask来匹配。
【2】图像金字塔下采样。
什么是图像金字塔?什么是上下采样?
下采样的目的前面已介绍,减小图像分辨率提高图像匹配速度,代码如下:
//对模板图像和待检测图像分别进行图像金字塔下采样
for (int i = 0; i
【3】0~360各角度匹配。
旋转模板图像,依次调用matchTemplate在目标图中匹配,记录最佳匹配分数,以及对应的角度。
【4】计算匹配结果。
根据模板图大小、匹配结果角度计算出匹配后的矩形四个角点,根据角点关系即可绘制方向:
【5】举例演示。
模板图从下图中截取并保存template.png:
测试图像12张,来自Halcon例程图片,路径如下:
…MVTecHALCON-20.11-Steadyexamplesimagesmodules
匹配结果:
相关代码
/*
旋转模板匹配函数(通过图像金字塔、增大旋转步长来提升匹配速度)
Mat src:原图像
Mat model:模板图
double startAngle:旋转的最小角
double endAngle:旋转的最大角
double firstStep:角度旋转时的最大步长
double secondStep:角度旋转时的最小步长
int numLevels = 0:图像金字塔缩放次数
*/
服务器托管网MatchResult rotateMatch(Mat src, Mat model, double startAngle, double endAngle, double firstStep, double secondStep, int numLevels = 0) {
//对模板图像和待检测图像分别进行图像金字塔下采样
for (int i = 0; i score)
{
location = maxloc;
score = maxval;
angle = curAngle;
}
}
if (isSecond) break;
startAngle = angle - firs服务器托管网tStep;
endAngle = angle + firstStep;
if ((endAngle - startAngle) / 5 > secondStep) {
firstStep = (endAngle - startAngle) / 5;
} else {
firstStep = secondStep;
isSecond = true;
}
}
Point finalPoint = Point(location.x * pow(2, numLevels), location.y * pow(2, numLevels));
vector points = GetRotatePoints(Size(model.cols * pow(2, numLevels), model.rows * pow(2, numLevels)), angle);
for (int j = 0; j imgs;
string imageName;
string path = "D:zMaterialsalgorithmAlgoDatamodules";
ifstream fin(path + "modules.seq");
while (getline(fin, imageName))
{
Mat img = imread(path + imageName + ".png");
imgs.push_back(img);
}
Mat templateImg = imread(path + "template.png");
int i = 0;
for (Mat img: imgs)
{
i += 1;
MatchResult matchResult = rotateMatch(img, templateImg, 0, 360, 30, 1, 0);
vector points = matchResult.points;
cout
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
编码声明主要是为了解决编码问题。由于Python 3的默认编码是UTF-8,因此在使用Python 3编写源代码时,通常不需要在文件开头添加编码声明。但是,如果您使用的编码不是UTF-8,则需要在文件开头添加编码声明,以确保Python解释器能够正确地解析源代…