初衷

果然halcon用顺手了,人就变懒了,正好有项目需要自己写个形状匹配的程序,就拿来练练手,程序不是很复杂,速度上感觉和halcon里面find_scaled_shape_model还是有差距,目前也不知道如何进一步改进,暂时就先这样了。大佬们如果有什么改进的想法可以评论一下,这样才能不断进步。

思路

主要的想法还是基于散点的重合度,虽然openCV自带matchTemplate和matchShape函数,但其内部是进行遍历像素矩计算,由于检测图中会有干扰边缘的存在,所以这些函数对于形状匹配(局部像素点集匹配)来说是不适合的。当然这些函数运行速度还是非常快的,目前我也不知道用什么办法可以达到同数量级的运算速度。

算法实现过程中主要遇到了几个问题:

1.生成旋转模版的问题

openCV没有自带的旋转函数,需要通过getRotationMatrix2D生成旋转矩阵,再用warpAffine进行仿射变换。但是warpAffine生成的图形会自动进行裁剪,会带来一些问题,因此需要稍微修改(详情见imrotate函数)。

2.遍历边缘点还是进行卷积的问题

由于openCV和halcon对于取像素点的操作都特别慢,所以对比之下只能采取用filter2D进行遍历,不得不说openCV自带的硬件加速库还是高效。

3.遍历运算速度过慢

openCV一些函数的源代码在内部还是进行了hal库的调用,用户没有办法修改,因此没有办法在函数内部进行算法修改。尝试用ppl库进行并行加速,效果还可以。

程序使用说明

(1)优先修改金字塔层数PyrLevel,层数越大,搜索速度越快,主函数中有缩放后的边缘图片,根据边缘是否清晰来修改PyrLevel和Canny函数的阈值,保证待检测图和模版图片的边缘足够清晰完整。
(2)如果找不到,适当减小minScore,越接近0,搜索相似容忍度越大,但运行速度同时也越慢。

函数片段

具体代码工程见
https://download.csdn.net/download/sillykog/10727775

/*************************************************
Function:       //  CreateScaledShapeModel
Description:    //  创建模版集
Input:          //  Template:模版图片的边缘图PyrLevel:金字塔缩小层数AngleStart,AngleExtent,AngleStep:旋转角度候选参数ScaleMin,ScaleMax,ScaleStep:缩放比例候选参数
Output:         //  pModelImageSet,pModelPointSet,pScaleSet,pAngleSet:模版集指针
Return:         //  无
Others:         //
*************************************************/
void CreateScaledShapeModel(Mat Template, int PyrLevel, int AngleStart, int AngleExtent, int AngleStep, float ScaleMin, float ScaleMax, float ScaleStep, \vector<Mat>* pModelImageSet, vector<int>* pModelPointSet, vector<float>* pScaleSet, vector<float>* pAngleSet)
{vector<Mat> ModelImageSet;vector<int> ModelPointSet;vector<float> AngleSet;vector<float> ScaleSet;while (ScaleMin <= ScaleMax){cout << ScaleMax << endl;ScaleSet.push_back(ScaleMax);ScaleMax -= ScaleStep;}while (AngleStart <= AngleExtent){cout << AngleExtent << endl;AngleSet.push_back(AngleExtent);AngleExtent -= AngleStep;}//模版生成   for (int level = 0; level <= PyrLevel; level++){Mat pyrmodelImage = Template;for (int i = 0; i < level; i++){pyrDown(pyrmodelImage, pyrmodelImage);}//缩放for (int i = 0; i < ScaleSet.size(); i++){Mat scaleImage;resize(pyrmodelImage, scaleImage, Size(round(pyrmodelImage.cols*ScaleSet[i]), round(pyrmodelImage.cols*ScaleSet[i])), 0, 0, INTER_LINEAR);//旋转for (int j = 0; j < AngleSet.size(); j++){Mat rotateImage;imrotate(scaleImage, rotateImage, AngleSet[j]);//threshold(rotateImage, rotateImage, 1, 255, 0);Canny(rotateImage, rotateImage, 50, 100, 3, false);rotateImage /= 255;//imshow("旋转", rotateImage);//imwrite("旋转.jpg", rotateImage);//waitKey(0);ModelImageSet.push_back(rotateImage);int pointNum = 0;for (int i = 0; i < rotateImage.cols; i++){for (int j = 0; j < rotateImage.rows; j++){if (rotateImage.at<uchar>(Point(i, j)) != 0)pointNum++;}}ModelPointSet.push_back(pointNum);rotateImage.release();}scaleImage.release();}}*pModelImageSet = ModelImageSet;*pModelPointSet = ModelPointSet;*pAngleSet = AngleSet;*pScaleSet = ScaleSet;
}/*************************************************
Function:       //  FindScaledShapeModel
Description:    //  在一张图片中搜索与模版相似的图形
Input:          //  Image:待检测图片ModelImageSet,ModelPointSet,ScaleSet,AngleSet:模版集PyrLevel:金字塔缩小层数MinScore:筛选相似度阈值
Output:         //  pRow,pCol,pScale,pAngle,pScore:输出匹配到的元素参数集合的指针
Return:         //  无
Others:         //  使用该函数前需要先调用CreateScaledShapeModel
*************************************************/
void FindScaledShapeModel(Mat Image, vector<Mat> ModelImageSet, vector<int> ModelPointSet, vector<float> ScaleSet, vector<float> AngleSet, int PyrLevel, float MinScore,\vector<int>* pRow, vector<int> * pCol, vector<float>* pScale, vector<float>* pAngle, vector<float>* pScore)
{mutex mt;Mat modelImage = ModelImageSet[0];vector<int> Row;vector<int> Col;vector<float> Scale;vector<float> Angle;vector<float> Score;bool findFlag = false;//金字塔分层匹配for (int level = PyrLevel; !findFlag && level >= PyrLevel; level--){        Mat pyrsrcImage = Image;for (int i = 0; i < level; i++){pyrDown(pyrsrcImage, pyrsrcImage);}int kernSize = floor(sqrt(min(pyrsrcImage.rows / 100, pyrsrcImage.cols / 100)));     Mat kern = Mat::ones(2 * kernSize + 1, 2 * kernSize + 1, CV_8U);Mat blurImage;filter2D(pyrsrcImage, blurImage, pyrsrcImage.depth(), kern);       //imshow("糊化原图", blurImage);//moveWindow("糊化原图", 0, 0);//waitKey(10);Mat tempblurImage;blurImage.convertTo(tempblurImage, CV_8U);tempblurImage /= 255;int parallelnum = ScaleSet.size() *AngleSet.size();parallel_for(0, parallelnum, [&](int k)  {Mat scoreImage(tempblurImage.size(), CV_16U);Mat tempmodelImage = ModelImageSet.at(ModelImageSet.size()- 1 - k);int temppointNum = ModelPointSet.at(ModelPointSet.size() - 1 - k);float max_score = 0;      /*imshow("模版", tempmodelImage);resizeWindow("模版", tempmodelImage.rows, tempmodelImage.cols);        moveWindow("模版", blurImage.cols,0);waitKey(10);*///double start = static_cast<double>(getTickCount());filter2D(tempblurImage, scoreImage, scoreImage.depth(), tempmodelImage);//double time = ((double)getTickCount() - start) / getTickFrequency();//cout << "所用时间为:" << time << "秒" << endl;mt.lock();while (1){double v_min, v_max;int idx_min[2] = { 255,255 }, idx_max[2] = { 255, 255 };minMaxIdx(scoreImage, &v_min, &v_max, idx_min, idx_max);scoreImage.at<ushort>(idx_max[0], idx_max[1]) = 0;max_score = v_max / temppointNum;//cout << "第" << level << "层" << "第" << k + 1 << "个成绩:" << max_score << endl;if (max_score > MinScore){float scale = ScaleSet[ScaleSet.size() - 1 - (k) / AngleSet.size()];float angle = AngleSet[AngleSet.size() - 1 - (k) % AngleSet.size()];//int selectx = (idx_max[1] - (tempmodelImage.cols - 1) / 2)*pow(2, level);//int selecty = (idx_max[0] - (tempmodelImage.rows - 1) / 2)*pow(2, level);//int pyrselectx = idx_max[1] - tempmodelImage.cols / 2;//int pyrselecty = idx_max[0] - tempmodelImage.rows / 2;Row.push_back(idx_max[1] * pow(2, level));Col.push_back(idx_max[0] * pow(2, level));Scale.push_back(scale);Angle.push_back(angle);Score.push_back(max_score);//cout << Point(selectx, selecty) << " " << Point(pyrselectx, pyrselecty) << endl;//rectangle(blurImage, Rect(pyrselectx, pyrselecty, tempmodelImage.cols, tempmodelImage.rows), 255, 2, 8);//rectangle(Image, Rect(selectx, selecty, modelImage.cols / scale, modelImage.rows / scale), 255, 2, 8);//imshow("缩放图位置", blurImage);//imshow("原图位置", Image);//waitKey(0);//findFlag = true;              }       else break;}tempmodelImage.release();scoreImage.release();mt.unlock();});for (int m = 0; m < Row.size() ; m++){for (int n = m+1; n < Row.size() ; n++){if (abs(Row[n] - Row[m])<modelImage.rows*0.3  && abs(Col[n] - Col[m])< modelImage.cols*03){if (Score[n] < Score[m]){Row.erase(Row.begin() + n);Col.erase(Col.begin() + n);Scale.erase(Scale.begin() + n);Angle.erase(Angle.begin() + n);Score.erase(Score.begin() + n);n--;}else if (Score[n] >= Score[m]){swap(Row[m], Row[n]);swap(Col[m], Col[n]);swap(Scale[m], Scale[n]); swap(Angle[m], Angle[n]); swap(Score[m], Score[n]);Row.erase(Row.begin() + n);Col.erase(Col.begin() + n);Scale.erase(Scale.begin() + n);Angle.erase(Angle.begin() + n);Score.erase(Score.begin() + n);n = m ;}}}}*pRow = Row;*pCol = Col;*pScale = Scale;*pAngle = Angle;*pScore = Score;}
}
void imrotate(Mat& img, Mat& newIm, double angle)
{int heightNew = int(img.cols*fabs(sin(angle*3.14 / 180)) + img.rows * fabs(cos(angle*3.14 / 180)));int widthNew = int(img.rows*fabs(sin(angle*3.14 / 180)) + img.cols * fabs(cos(angle*3.14 / 180)));int len = max(img.cols, img.rows);Point2f pt(len / 2., len / 2.);Mat r = getRotationMatrix2D(pt, angle, 1.0);r.at<double>(0, 2) += (widthNew - img.cols) / 2;r.at<double>(1, 2) += (heightNew - img.rows) / 2;  warpAffine(img, newIm, r, Size(widthNew, heightNew), INTER_LINEAR, BORDER_REPLICATE);
}

基于openCV的形状模版匹配相关推荐

  1. 基于opencv的图片模板匹配及其简单应用

    opencv的图片模板匹配及其简单应用 我的个人博客 基础知识 基于opencv的图片模板匹配 注: python及其相关包的安装不在讨论范围内 opencv提供了图片模板匹配的方法, cv2.mat ...

  2. 基于OpenCV的形状检测

    摘要 点击此处下载源代码:https://jbox.sjtu.edu.cn/l/85O9ur 本教程是我们关于形状检测和分析的三部分系列文章的第二篇. 上周我们学习了如何使用OpenCV计算轮廓的中心 ...

  3. Opencv之形状距离匹配--createShapeContextDistanceExtractor

    代码展示: c++版: #include <iostream> #include <string> #include <opencv2/shape.hpp> #in ...

  4. 案例-使用python实现基于opencv的形状识别

    该案例主要涉及到不同形状的图形.根据获得轮廓,计算边数.来判断属于什么形状,并将之输出在图片上.具体代码和结果如下: import cv2 from urllib3 import connection ...

  5. 计算机视觉与深度学习 | ORB特征匹配:基于OpenCV+Python(暴力匹配、FLANN)

    ===================================================== github:https://github.com/MichaelBeechan CSDN: ...

  6. opencv实现基于边缘的形状匹配算法

    1.参考资料 https://www.codeproject.com/Articles/99457/Edge-Based-Template-Matching 用opencv编写的形状匹配算法,但不具旋 ...

  7. 基于opencv的模板匹配详解

    1.什么是模板匹配 在OpenCV教程中这样解释模板匹配: 模板匹配是一项在一幅图像中寻找与另一幅模板图像最匹配(相似)部分的技术.这里说的模板是我们已知的小图像,模板匹配就是在一副大图像中搜寻目标. ...

  8. 【Opencv】基于Opencv和PCV两种方法的Harris 角点检测与匹配

    [Opencv]基于Opencv和PCV两种方法的Harris 角点检测与匹配[附代码] 理解Harris角点检测 代码:Harris角点检测 1.[opencv版]Harris角点检测 2.[PCV ...

  9. 图像目标检索:基于Opencv的颜色空间匹配法

    图像目标检索:基于Opencv的颜色空间匹配法 目标效果:近似于淘宝上--拍照搜索,检索商品的效果,在传统算法领域,也有一些优秀的算法能粗略的实现该效果,本文便基于传统算法中的颜色空间匹配法来实现,代 ...

最新文章

  1. python 无头模式 绕过检测_Python chrome 无头模式的问题
  2. 19-flutter的ListView 和 GridView的使用
  3. Spring Boot Spring MVC 异常处理的N种方法
  4. 5中打开safari_iOS13版Safari浏览器新功能上线:可调节上传照片大小
  5. php生产任务,php生产实用技能之计划任务(视频讲解)
  6. POI 导出文件以文件流形式返回
  7. java获取apk启动activity_兼容 Android 10 启动 APK 实现方案
  8. vi/vim 三种模式及命令 (简单粗暴,轻松搞懂)
  9. 三、Java 面向对象高级——数据结构、List、Set、Collection
  10. 【网络流】【Dinic】【Next Array】Dinic模板
  11. excel表自动向下填充
  12. 强大的sed_拔剑-浆糊的传说_新浪博客
  13. python pip安装第三方库出现error: option --single-version-externally-managed not recognized
  14. stimulsoft 变量
  15. 伪随机二进制序列(PRBS)
  16. Linux下查看显卡型号
  17. C++学习心得和进阶路线总结
  18. 洛谷P1458 [USACO2.1]顺序的分数 Ordered Fractions
  19. openjudge 丛林中的路
  20. ENVI去除影像的地理坐标信息

热门文章

  1. Android DownloadManager下载管理,app更新
  2. linux 添加开机动画,如何更改linux 开机画面?
  3. Mingw + msys编译libmono.so
  4. linux下通过串口ftp,eftp简单文件传输工具支持串口、网络、Windows、Linux、单片机平台-博客...
  5. TexturePacker命令行使用(command line)
  6. android r AB ota fail
  7. Qt QNetworkAccessManager请求返回reply内存泄漏
  8. 为什么极品飞车服务器维修,极品飞车:无极限赛车无法连接服务器是什么原因...
  9. 如何做好网站的日常优化推广
  10. 莫听穿林打叶声,何妨吟啸且徐行。—第十八天