实战 |
您所在的位置:网站首页 › 3d透视匹配怎么用 › 实战 |
点击上方“小白学视觉”,选择加"星标"或“置顶” 重磅干货,第一时间送达导读 本文将介绍使用OpenCV实现多角度模板匹配的详细步骤 + 代码。(来源公众号:OpenCV与AI深度学习) 背景介绍熟悉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掩码有什么用?看下面链接文章介绍: 实战 | OpenCV带掩码(mask)的模板匹配使用技巧与演示(附源码) ② 旋转时不放大目标图像尺寸,剔除黑边剩余部分做mask来匹配。 【2】图像金字塔下采样。什么是图像金字塔?什么是上下采样?直接百度。 下采样的目的前面已介绍,减小图像分辨率提高图像匹配速度,代码如下: //对模板图像和待检测图像分别进行图像金字塔下采样 for (int i = 0; i < numLevels; i++) { pyrDown(src, src, Size(src.cols / 2, src.rows / 2)); pyrDown(model, model, Size(model.cols / 2, model.rows / 2)); }【3】0~360°各角度匹配。旋转模板图像,依次调用matchTemplate在目标图中匹配,记录最佳匹配分数,以及对应的角度。 模板匹配详细使用说明: https://docs.opencv.org/4.x/df/dfb/group__imgproc__object.html#ga586ebfb0a7fb604b35a23d85391329be 旋转匹配代码: TemplateMatchModes matchMode = TM_CCOEFF_NORMED; switch (nccMethod) { case 0: matchMode = TM_SQDIFF; break; case 1: matchMode = TM_SQDIFF_NORMED; break; case 2: matchMode = TM_CCORR; break; case 3: matchMode = TM_CCORR_NORMED; break; case 4: matchMode = TM_CCOEFF; break; case 5: matchMode = TM_CCOEFF_NORMED; break; } //在没有旋转的情况下进行第一次匹配 double minVal, maxVal; Point minLoc, maxLoc; matchTemplate(src, model, result, matchMode); minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc); Point location = maxLoc; double temp = maxVal; double angle = 0; Mat newImg; //以最佳匹配点左右十倍角度步长进行循环匹配,直到角度步长小于参数角度步长 if (nccMethod == 0 || nccMethod == 1) { do { for (int i = 0; i angleStep); return ResultPoint(location.x * pow(2, numLevels) + modelImage.cols / 2, location.y * pow(2, numLevels) + modelImage.rows / 2, -angle, temp); } else { do { for (int i = 0; i temp) { location = maxloc; temp = maxval; angle = start + step * i; } } range = step * 2; start = angle - step; step = step / 10; } while (step > angleStep); if (temp > thresScore) { return ResultPoint(location.x * pow(2, numLevels), location.y * pow(2, numLevels), -angle, temp); } } return ResultPoint(-1, -1, 0, 0);【4】标注匹配结果。根据模板图大小、匹配结果角度计算出匹配后的矩形四个角点,根据角点关系即可绘制方向: //获取旋转后矩形对应的端点坐标 vector GetRotatePoints(Mat img, Rect inRect, double angle) { Rect rect = inRect; vectorpts; Point2f center = Point2f(img.cols / 2, img.rows / 2); Mat M = getRotationMatrix2D(center, angle, 1.0); //cout |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |