C++|OpenCV 之零件识别的四种方法
opencv
OpenCV: 开源计算机视觉库
项目地址:https://gitcode.com/gh_mirrors/opencv31/opencv
免费下载资源
·
零件识别的四种方法
下面为函数声明和命名空间:
#include <opencv2\opencv.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace cv;
一、 形状匹配
int main()
{
VideoCapture capture(1);//1.读入视频
while (1)//2.循环显示每一帧
{
Mat frame;//定义一个Mat变量,用于存储每一帧的图像
capture >> frame;//读取当前帧
//若视频播放完成,退出循环
if (frame.empty())
{
break;
}
//Mat img = imread("D:/PyCharm/pythonProject/OpenCV-py/test1.jpg");
//if (img.empty())
//{
// cout << "请确认图像文件名称是否正确" << endl;
// return -1;
//}
Mat img = frame, img2;
//Mat img1, img2;
//img.copyTo(img1); //深拷贝用来绘制最大外接矩形
img.copyTo(img2); //深拷贝用来绘制最小外接矩形
//imshow("img", img);
Mat gray;//灰度处理
cvtColor(img, gray, COLOR_BGR2GRAY); //转化成灰度图
//GaussianBlur(gray, gray, Size(5, 5), 4, 4); //平滑滤波
//imshow("GaussianBlur", gray);
Mat canny; // 去噪声与二值化
Canny(gray, canny, 80, 255, 3, false);//?3是sobel直径 不能改动
imshow("canny detect", canny);
//膨胀运算,将细小缝隙填补上
Mat kernel = getStructuringElement(0, Size(6, 5));
dilate(canny, canny, kernel);
imshow("dilate", canny);
// 轮廓发现与绘制
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(canny, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point());//RETR_EXTERNAL//RETR_LIST
//寻找轮廓的外接矩形
for (int n = 0; n < contours.size(); n++)
{
最大外接矩形
//Rect rect = boundingRect(contours[n]);
//rectangle(img1, rect, Scalar(0, 0, 255), 2, 8, 0);
int a = rect[0];//错误
//int a = rect.height;
//int b = rect.width;
//cout << "max 长" << a << " " << "宽" << b << endl;
// 最小外接矩形
RotatedRect rrect = minAreaRect(contours[n]);
Point2f points[4];
rrect.points(points); //读取最小外接矩形的四个顶点
Point2f cpt = rrect.center; //最小外接矩形的中心
int x = rrect.size.height;
int y = rrect.size.width;
cout << "设置长宽比:0.83~1.25" <<endl<<"实际长宽比:"<< x / y << endl;
if ((rrect.size.width > 0.8 * rrect.size.height) && (rrect.size.width < 1.2 * rrect.size.height) && rrect.size.width > 10) //长宽比 0.8长<宽<1.2长
// 绘制旋转矩形与中心位置
{
for (int i = 0; i < 4; i++)
{
if (i == 3)
{
line(img2, points[i], points[0], Scalar(0, 255, 0), 2, 8, 0);
break;
}
line(img2, points[i], points[i + 1], Scalar(0, 255, 0), 2, 8, 0);
}
//绘制矩形的中心
circle(img, cpt, 2, Scalar(255, 0, 0), 2, 8, 0);
putText(img2, "nut", Point(cpt), 2, 1, Scalar(0, 0, 255));
}
}
//putText(img2, "parts",Point(100, 100), 2, 1, Scalar(0, 0, 255));
//输出绘制外接矩形的结果
//imshow("max", img1);
namedWindow("最小外接矩形识别", WINDOW_FREERATIO);
imshow("最小外接矩形识别", img2);
waitKey(30);//延时30毫秒
}
waitKey(0);
return 0;
}
二、单模板匹配
Point getNextMinLoc(Mat result, Point maxLoc, int maxVaule, int templatW, int templatH)
{
// 先将第一个最大值点附近两倍模板宽度和高度的都设置为最大值防止产生干扰
int startX = maxLoc.x - 0.55*templatW;
int startY = maxLoc.y - 0.55*templatH;
int endX = maxLoc.x + 0.55*templatW;
int endY = maxLoc.y + 0.55*templatH;
if (startX < 0 || startY < 0)
{
startX = 0;
startY = 0;
}
if (endX > result.cols - 1 || endY > result.rows - 1)
{
endX = result.cols - 1;
endY = result.rows - 1;
}
for (int y = startY; y < endY; y++)
{
for (int x = startX; x < endX; x++)
{
//cvsetReal2D(result, y, x, maxVaule);//读取图像像素值
result.at<float>(y, x) = maxVaule;//覆盖
}
}
// 然后得到下一个最大值并且返回
double new_minVaule, new_maxValue;
Point new_minLoc, new_maxLoc;
minMaxLoc(result, &new_minVaule, &new_maxValue, &new_minLoc, &new_maxLoc);
return new_maxLoc;
}
下面为主函数:
int main()
{
VideoCapture capture(1);//1.从摄像头读入视频
Mat edges;
while (1)//2.循环显示每一帧
{
Mat frame;//定义一个Mat变量,用于储存每一帧的图像
capture >> frame;//把取得的影像放置到矩阵中 读取当前帧
imshow("读取视频", frame);//显示当前帧
Mat img = frame;
//Mat img = imread("D:/PyCharm/pythonProject/OpenCV-py/test1.jpg");
Mat temp = imread("D:/PyCharm/pythonProject/OpenCV-py/k.jpg"); //D:/PyCharm/pythonProject/OpenCV-py/muban/1.jpg
if (img.empty() || temp.empty())
{
cout << "请确认图像文件名称是否正确" << endl;
return -1;
}
Mat result;
matchTemplate(img, temp, result, TM_CCOEFF_NORMED);//模板匹配
double maxVal, minVal;
Point minLoc, maxLoc;
//寻找匹配结果中的最大值和最小值以及坐标位置
minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc);
//保存结果1
Rect rect(minLoc.x, minLoc.y, temp.cols, temp.rows);//1
Mat image_roi = img(rect);
//绘制最佳匹配区域
rectangle(img, Rect(maxLoc.x, maxLoc.y, temp.cols, temp.rows), Scalar(0, 0, 255), 2);
putText(img, "nut", Point(maxLoc.x + temp.cols / 2, maxLoc.y + temp.rows / 2), 2, 1, Scalar(0, 0, 255));
cout << "相似度" << 0 << ": " << TM_CCOEFF_NORMED << endl;
for (int i = 0; i < 2; i++)
{
//计算下一个最大值
Point new_maxLoc;
new_maxLoc = getNextMinLoc(result, maxLoc, maxVal, temp.cols, temp.rows);
rectangle(img, new_maxLoc, Point(new_maxLoc.x + temp.cols, new_maxLoc.y + temp.rows), Scalar(0, 255, 0), 2, 8, 0);
//保存结果2
Rect rect2(new_maxLoc.x, new_maxLoc.y, temp.cols, temp.rows);//2
image_roi = img(rect2);
putText(img, "nut", Point(new_maxLoc.x + temp.cols / 2, new_maxLoc.y + temp.rows / 2), 2, 1, Scalar(0, 0, 255));
cout << "相似度" << i << ": " << TM_CCOEFF_NORMED << endl;
//再计算下一个最大值
new_maxLoc = getNextMinLoc(result, new_maxLoc, maxVal, temp.cols, temp.rows);
rectangle(img, new_maxLoc, Point(new_maxLoc.x + temp.cols, new_maxLoc.y + temp.rows), Scalar(255, 0, 0), 2, 8, 0);
//保存结果3
Rect rect3(new_maxLoc.x, new_maxLoc.y, temp.cols, temp.rows);//3
image_roi = img(rect3);
putText(img, "nut", Point(new_maxLoc.x + temp.cols / 2, new_maxLoc.y + temp.rows / 2), 2, 1, Scalar(0, 0, 255));
cout << "相似度" << i + 1 << ": " << TM_CCOEFF_NORMED << endl;
}
imshow("原图", img);
imshow("模板图像", temp);
imshow("result", result);
waitKey(30);
}
waitKey(0);
return 0;
}
三、多模板匹配
#include <opencv2\opencv.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace cv;
int main() //多模板匹配 零件识别
{ /*Mat img = imread("D:/PyCharm/pythonProject/OpenCV-py/lslm/12.jpg");
if (img.empty())
{
cout << "请确认图像文件名称是否正确" << endl;
return -1;
}
*/
VideoCapture capture(1);//1.从摄像头读入视频
while (1)//2.循环显示每一帧
{
Mat frame;//定义一个Mat变量,用于储存每一帧的图像
capture >> frame;//把取得的影像放置到矩阵中 读取当前帧
//imshow("读取视频", frame);//显示当前帧
Mat img = frame;
vector<String> filenames;//读取文件夹图片
glob("D:/PyCharm/pythonProject/OpenCV-py/muban/amount 5/*.*png", filenames, 0);
for (size_t i = 0; i < filenames.size(); ++i)
{
cout << filenames[i] << endl;
Mat src = imread(filenames[i]);
if (!src.data)
cerr << "Problem loading image!!!" << endl;
//imshow("temp", src);
waitKey(30);
// do whatever you want with your images here
Mat temp = src;
Mat result;
matchTemplate(img, temp, result, TM_CCOEFF_NORMED);//模板匹配
double maxVal, minVal;
Point minLoc, maxLoc;
//寻找匹配结果中的最大值和最小值以及坐标位置
minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc);
result.rows;
//绘制最佳匹配区域
rectangle(img, Rect(maxLoc.x, maxLoc.y, temp.cols, temp.rows), Scalar(0, 0, 255), 2);
putText(img, "nut", Point(maxLoc.x + temp.cols / 4, maxLoc.y + temp.rows / 4), 2, 1, Scalar(0, 0, 255));
namedWindow("模板匹配结果", WINDOW_FREERATIO);
namedWindow("模板图像", WINDOW_FREERATIO);
imshow("模板匹配结果", img);
imshow("模板图像", temp);
//imshow("模板匹配结果", result);
}
}
waitKey(0);
return 0;
}
四、ORB RANSAC优化特征点匹配
void match_min(vector<DMatch> matches, vector<DMatch>& good_matches)
{
double min_dist = 10000, max_dist = 0;
for (int i = 0; i < matches.size(); i++)
{
double dist = matches[i].distance;
if (dist < min_dist) min_dist = dist;
if (dist > max_dist) max_dist = dist;
}
cout << "min_dist=" << min_dist << endl;
cout << "max_dist=" << max_dist << endl;
for (int i = 0; i < matches.size(); i++)
if (matches[i].distance <= max(2 * min_dist, 20.0))
good_matches.push_back(matches[i]);
}
//RANSAC算法实现
void ransac(vector<DMatch> matches, vector<KeyPoint> queryKeyPoint, vector<KeyPoint> trainKeyPoint, vector<DMatch>& matches_ransac)
{
//定义保存匹配点对坐标
vector<Point2f> srcPoints(matches.size()), dstPoints(matches.size());
//保存从关键点中提取到的匹配点对的坐标
for (int i = 0; i < matches.size(); i++)
{
srcPoints[i] = queryKeyPoint[matches[i].queryIdx].pt;
dstPoints[i] = trainKeyPoint[matches[i].trainIdx].pt;
}
//匹配点对进行RANSAC过滤
vector<int> inliersMask(srcPoints.size());
//Mat homography;
//homography = findHomography(srcPoints, dstPoints, RANSAC, 5, inliersMask);
findHomography(srcPoints, dstPoints, RANSAC, 5, inliersMask);
//手动的保留RANSAC过滤后的匹配点对
for (int i = 0; i < inliersMask.size(); i++)
if (inliersMask[i])
matches_ransac.push_back(matches[i]);
}
void orb_features(Mat& gray, vector<KeyPoint>& keypionts, Mat& descriptions)
{
Ptr<ORB> orb = ORB::create(1000, 1.2f);
orb->detect(gray, keypionts);
orb->compute(gray, keypionts, descriptions);
}
int main()
{
VideoCapture capture(1);//1.读入视频
while (1)//2.循环显示每一帧
{
Mat frame;//定义一个Mat变量,用于存储每一帧的图像
capture >> frame;//读取当前帧
//若视频播放完成,退出循环
if (frame.empty())
{
break;
}
Mat img2 = frame;
//Mat img1 = imread("D:/PyCharm/pythonProject/OpenCV-py/ORB/RANSAC/5.jpg"); //读取图像,根据图片所在位置填写路径即可
Mat img1 = imread("D:/PyCharm/pythonProject/OpenCV-py/ORB/RANSAC/wrench.jpg");
if (!(img1.data && img2.data))
{
cout << "读取图像错误,请确认图像文件是否正确" << endl;
return -1;
}
//提取ORB特征点
vector<KeyPoint> Keypoints1, Keypoints2;
Mat descriptions1, descriptions2;
//基于区域分割的ORB特征点提取
orb_features(img1, Keypoints1, descriptions1);
orb_features(img2, Keypoints2, descriptions2);
//特征点匹配
vector<DMatch> matches, good_min, good_ransac;
BFMatcher matcher(NORM_HAMMING);
matcher.match(descriptions1, descriptions2, matches);
cout << "matches=" << matches.size() << endl;
//最小汉明距离
match_min(matches, good_min);
cout << "good_min=" << good_min.size() << endl;
//用ransac算法筛选匹配结果
ransac(good_min, Keypoints1, Keypoints2, good_ransac);
cout << "good_matches.size=" << good_ransac.size() << endl;
//绘制匹配结果
Mat outimg1, outimg2;
drawMatches(img1, Keypoints1, img2, Keypoints2, good_min, outimg1);
drawMatches(img1, Keypoints1, img2, Keypoints2, good_ransac, outimg2);
std::vector<Point2f> obj;
std::vector<Point2f> scene;
for (size_t i = 0; i < good_ransac.size(); i++)
{
//-- Get the keypoints from the good matches
obj.push_back(Keypoints1[good_ransac[i].queryIdx].pt);
scene.push_back(Keypoints2[good_ransac[i].trainIdx].pt);
}
Mat H = findHomography(obj, scene, RANSAC);
//-- Get the corners from the image_1 ( the object to be "detected" )
std::vector<Point2f> obj_corners(4);
obj_corners[0] = Point(0, 0);
obj_corners[1] = Point(img1.cols, 0);
obj_corners[2] = Point(img1.cols, img1.rows);
obj_corners[3] = Point(0, img1.rows);
std::vector<Point2f> scene_corners(4);
perspectiveTransform(obj_corners, scene_corners, H);
//-- Draw lines between the corners (the mapped object in the scene - image_2 )
Point2f offset((float)img1.cols, 0);
line(outimg2, scene_corners[0] + offset, scene_corners[1] + offset, Scalar(0, 0, 255), 4);
line(outimg2, scene_corners[1] + offset, scene_corners[2] + offset, Scalar(0, 0, 255), 4);
line(outimg2, scene_corners[2] + offset, scene_corners[3] + offset, Scalar(0, 0, 255), 4);
line(outimg2, scene_corners[3] + offset, scene_corners[0] + offset, Scalar(0, 0, 255), 4);
//putText(outimg2, "wrench1", scene_corners[0], 2, 1, Scalar(0, 255, 0));
putText(outimg2, "wrench", Point(scene_corners[0].x + offset.x, scene_corners[1].y + offset.y), 2, 1, Scalar(0, 0, 255));
namedWindow("ransac筛选", WINDOW_FREERATIO);
//namedWindow("最小汉明距离筛选", WINDOW_FREERATIO);
//imshow("最小汉明距离筛选", outimg1);
imshow("ransac筛选", outimg2);
waitKey(30); //等待键盘输入
}
waitKey(0); //等待键盘输入
return 0; //程序结束
}
完成时间:2022-01-02
作者:夔曦. 欢迎转载或分享,但请务必声明文章出处。
参考博客:
1、opencv3中的glob函数读取文件夹中数据.
2、opencv学习_11 (模板匹配(包括单模板和多模板)).
3、OpenCV】透视变换 Perspective Transformation(续).
4、OpenCV透视变换官网案例.
GitHub 加速计划 / opencv31 / opencv
149
15
下载
OpenCV: 开源计算机视觉库
最近提交(Master分支:4 个月前 )
96d6395a
Add include chrono gstreamersource.cpp 3 天前
fe649f4a - 3 天前
更多推荐
已为社区贡献3条内容
所有评论(0)