干货 | 基于特征的图像配准用于缺陷检测

news/2024/7/7 22:42:35

点击上方“小白学视觉”,选择加"星标"或“置顶

重磅干货,第一时间送达

特征提取

基于特征的图像配准,具有非常广泛的应用,大致流程可以如下:

经典的特征匹配算法有SIFT、SURF、ORB等,这三种方法在OpenCV里面都已实现。SURF基本就是SIFT的全面升级版,有 SURF基本就不用考虑SIFT,而ORB的强点在于计算时间,以下具体比较:

计算速度:ORB>>SURF>>SIFT(各差一个量级)
旋转鲁棒性:SURF>ORB~SIFT(~表示差不多)
模糊鲁棒性:SURF>ORB~SIFT
尺度变换鲁棒性:SURF>SIFT>ORB(ORB并不具备尺度变换性)

所以结论就是,如果对计算实时性要求非常高,可选用ORB算法,但基本要保证正对拍摄;如果对稳定性要求稍高,可以选择SURF;基本不用SIFT。此外补充一点,自从OpenCV3.x开始,受到SIFT跟SURF专利授权的影响,OpenCV正式的发布版本中已经移除了SIFT跟SURF算法。ORB特征提取算法是基于FAST跟BRIEF算法改进的组合算法,其中FAST实现关键点/特征点的检测,在此基础上基于几何矩添加方向属性,BRIEF实现描述子生成,添加旋转不变性支持。

ORB特征匹配速度快的一个原因之一就是使用字符串向量的描述子,避免了浮点数计算。字符串描述子匹配上可以采用汉明距离或者LSH改进算法实现,相比浮点数计算L2距离进一步降低了计算量。所以在一般情况下建议使用ORB特征匹配,如果效果不好再尝试AKAZE/SURF/SIFT等其它特征匹配算法。

特征对齐/配准

两幅图像之间的基于特征匹配的透视变换矩阵求解通常被称为图像对齐或者配准。基于特征的匹配可以很好实现图像对齐或者配准,首先需要获取两张图像的特征关键点与特征描述子,然后通过暴力匹配或者FLANN匹配寻找匹配度高的相关特征点。最后基于这些相关特征点估算它们之间的单应性矩阵,通过单应性矩阵实现透视变换,完成图像对齐与配准。OpenCV中有两个函数可以获得单映射变换矩阵,分别为:

- findHomography
- getPerspectiveTransform

两者之间的区别在于getPerspectiveTransform只会拿4个点去计算,findHomography则会拿一堆点(>=4)去计算。

应用代码演示

下面是一个简单的代码演示,基于特征对齐,实现基于分差的缺陷检测。

用基于ORB特征的匹配结果,如下图所示,可以看到有一些错误的匹配点

基于ORB特征实现图像相关特征点匹配的代码实现如下:

constint MAX_FEATURES = 5000;
constfloat GOOD_MATCH_PERCENT = 0.45f;
//im1为待配准图片
//im2为模板图片
//im1Reg为配准后的图片
//h为单应性矩阵
void alignImages(Mat&im1, Mat&im2, Mat&im1Reg, Mat&h)
{// 将图像转为灰度图Mat im1Gray, im2Gray;cvtColor(im1, im1Gray, COLOR_BGR2GRAY);cvtColor(im2, im2Gray, COLOR_BGR2GRAY);// 存储特征与特征描述子的变量std::vector<KeyPoint> keypoints1, keypoints2;Mat descriptors1, descriptors2;// 检测ORB特征计算特征描述子.Ptr<Feature2D> orb = ORB::create(MAX_FEATURES);orb->detectAndCompute(im1Gray, Mat(), keypoints1, descriptors1);clock_t start, end;start = clock();orb->detectAndCompute(im2Gray, Mat(), keypoints2, descriptors2);  //77ms// 特征匹配.std::vector<DMatch> matches;Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");matcher->match(descriptors1, descriptors2, matches, Mat());// Sort matches by scorestd::sort(matches.begin(), matches.end());//基于GMS的特征匹配算法//vector<DMatch> matchesAll, matchesGMS;//BFMatcher matcher(NORM_HAMMING);//std::vector<DMatch> matches;//matcher.match(descriptors1, descriptors2, matchesAll);//cout << "matchesAll: " << matchesAll.size() << endl;//matchGMS(im1.size(), im2.size(), keypoints1, keypoints2, matchesAll, matches);//std::sort(matches.begin(), matches.end());end = clock();cout << (float)(end - start) * 1000 / CLOCKS_PER_SEC<<"ms"<< endl;// 移除不好的匹配点constint numGoodMatches = matches.size() * GOOD_MATCH_PERCENT;matches.erase(matches.begin() + numGoodMatches, matches.end());// 画匹配点Mat imMatches;drawMatches(im1, keypoints1, im2, keypoints2, matches, imMatches);imwrite("matches.jpg", imMatches);// 存储好的匹配点std::vector<Point2f> points1, points2;for (size_t i = 0; i < matches.size(); i++){points1.push_back(keypoints1[matches[i].queryIdx].pt);points2.push_back(keypoints2[matches[i].trainIdx].pt);}// 找出最优单映射变换矩阵hh= findHomography(points1, points2, RANSAC);// 利用h矩阵进行透视变换warpPerspective(im1, im1Reg, h, im2.size());
}

Grid-based Motion Statistics(GMS)通过网格划分、运动统计特性的方法可以迅速剔除错误匹配,以此来提高匹配的稳定性。ORB+GMS的匹配效果如下,可见错误的匹配点少了很多。

配准后的图如下图所示:

将配准后的图与基准模板图做差分,效果如下:

进行形态学操作,

找出缺陷,比较大的缺陷可以找出来,较小的缺陷还是不能找出来。

这部分的代码实现如下:

int main(intargc, char **argv)
{// Read reference imagestring refFilename("8.jpg");cout <<"Reading reference image : "<< refFilename << endl;Mat imReference = imread(refFilename);// Read image to be alignedstring imFilename("7.jpg");cout <<"Reading image to align : "<< imFilename << endl;Mat im = imread(imFilename);// Registered image will be resotred in imReg. // The estimated homography will be stored in h. Mat imReg, h;// Align imagescout <<"Aligning images ..."<< endl;alignImages(im, imReference, imReg, h);// Write aligned image to disk. string outFilename("aligned.jpg");cout <<"Saving aligned image : "<< outFilename << endl;imwrite(outFilename, imReg);// Print estimated homographycout <<"Estimated homography : \n"<< h << endl;Mat currentframe, previousframe;cvtColor(imReference, previousframe, COLOR_BGR2GRAY);cvtColor(imReg, currentframe, COLOR_BGR2GRAY);  //转化为单通道灰度图absdiff(currentframe, previousframe, currentframe);//做差求绝对值imshow("1", currentframe);imwrite("re.jpg", currentframe);threshold(currentframe, currentframe, 120, 255.0, THRESH_BINARY);imwrite("re11.jpg", currentframe);erode(currentframe, currentframe, Mat());//腐蚀dilate(currentframe, currentframe, Mat());//膨胀dilate(currentframe, currentframe, Mat());//膨胀imshow("moving area", currentframe);    //显示图像vector<vector<Point>> v;vector<Vec4i> hierarchy;Mat result;Rect rect;findContours(currentframe, v, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE);for (int i = 0; i < hierarchy.size(); i++){rect = boundingRect(v.at(i));if (rect.area() > 1){rectangle(imReg, rect, Scalar(0, 0, 255), 2);}}imwrite("res1.jpg", imReg);imshow("moving area1", imReg);waitKey(0);
}

下载1:OpenCV-Contrib扩展模块中文版教程

在「小白学视觉」公众号后台回复:扩展模块中文教程即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。

下载2:Python视觉实战项目52讲

在「小白学视觉」公众号后台回复:Python视觉实战项目即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。

下载3:OpenCV实战项目20讲

在「小白学视觉」公众号后台回复:OpenCV实战项目20讲即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。

交流群

欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~


http://lihuaxi.xjx100.cn/news/275854.html

相关文章

android存储器,Android——寄存器和存储器的区别

【20160924】GOCVHelper 图像增强部分(4)//使得rect区域半透明 Mat translucence(Mat src,Rect rect,int idepth){ Mat dst src.clone(); ...boost之词法解析器spirit摘要:解析器就是编译原理中的语言的词法分析器,可以按照文法规则提取字符或者单词.功能:接受…

LA 5717枚举+最小生成树回路性质

1 /*LA 57172 《训练指南》P3433 最小生成树的回路性质4 在生成的最小生成树上&#xff0c;新增一条边e(u,v)5 若原图上u到v的路径的最大边大于e&#xff0c;则删除此边&#xff0c;加上e&#xff0c;否则不变。6 7 若原图上u到v的路径的最大边的产生&#xff1a;BFS/DFS都可 &…

System.Transactions介绍

在.Net Framework 2.0中&#xff0c;新增了一个名称空间&#xff1a;System.Transactions。从其名字就可以看出来&#xff0c;里面包含了Transaction相关的类。System.Transactions提供了一个“轻量级”的、易于使用的Transaction框架。 在以前&#xff0c;要实现Transaction需…

类选择器和所作用的标签一起写为什么不起作用? - CSDN博客

原文:类选择器和所作用的标签一起写为什么不起作用&#xff1f; - CSDN博客HTML代码&#xff1a; css样式&#xff1a; 这不是将样式作用于circle类下的有current类的li标签吗&#xff1f;为什么不起作用&#xff1f; 原因&#xff1a; 选择器理解错误&#xff01; 一般常用的选…

wps在线预览接口_文档在线预览的实现

最近在研究企业文档管理&#xff0c;这个是基本上所有企业都需要的软件&#xff0c;当然也是有很多种解决方案。对于企业文档来说&#xff0c;最基本的需求就是独立存储&#xff0c;共享。这种需求只需要建立一个Windows共享文件夹或者架一个Samba服务器即可实现&#xff0c;无…

你知道为什么Java的main方法必须是public static void?

点击上方“方志朋”&#xff0c;选择“设为星标”回复”666“获取新整理的面试资料来源&#xff1a;http://suo.im/6v9d64Main 方法是我们学习 Java 编程语言时知道的第一个方法&#xff0c;你是否曾经想过为什么 main 方法是 public、static、void 的。当然&#xff0c;很多人…

985 CV 找不到工作? 4 点诚恳建议

点击上方“小白学视觉”&#xff0c;选择加"星标"或“置顶”重磅干货&#xff0c;第一时间送达本文转自|视觉算法【新智元导读】985研究生&#xff0c;学计算机视觉&#xff0c;出来后找不到工作&#xff1f;新智元带你看看这个70万浏览量问题下的答案干货&#xff1…

10月1日之后,你新建的GitHub库默认分支不叫「master」了

点击上方“视学算法”&#xff0c;选择加"星标"重磅干货&#xff0c;第一时间送达本文转载自&#xff1a;机器之心 | 作者&#xff1a;张倩、杜伟从 2020 年 10 月 1 日开始&#xff0c;GitHub 上的所有新库都将用中性词「main」命名&#xff0c;取代原来的「maste…