C++|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优化特征点匹配

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透视变换官网案例.

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 利用OpenCV进行图像识别是一种常见的计算机视觉应用。OpenCV是一个开源计算机视觉库,支持多种编程语言,包括C++、Python等。它提供了丰富的图像处理和计算机视觉算法,可以用来进行图像识别、目标检测、人脸识别、手势识别等任务。 在进行图像识别时,首先需要加载和处理图像。OpenCV提供了读取、保存和处理图像的函数,可以对图像进行灰度化、二值化、滤波等预处理操作,以提高后续识别的准确性。 接下来,可以使用OpenCV提供的特征提取算法,如SIFT、SURF、HOG等,来提取图像的特征。这些算法可以提取出图像中的关键特征点或特征向量,用于识别匹配。 然后,可以使用OpenCV提供的机器学习算法,如支持向量机(SVM)、K最近邻(KNN)等,来训练一个分类器或回归器。通过给分类器提供一系列已知的图像样本和其对应的标签,可以训练模型,使其可以自动识别未知图像。 最后,可以使用训练好的模型对新的图像进行识别。将新的图像输入到分类器中,分类器将输出一个标签,表示图像所属的类别。根据这个标签,可以判断图像中的物体或场景是什么。 总之,利用OpenCV进行图像识别可以实现多种应用,如车牌识别、人脸识别、文字识别等。通过选择合适的图像处理和机器学习算法,可以有效提高图像识别的准确性和效率。 ### 回答2: OpenCV是一个开源的计算机视觉库,常用于图像处理和计算机视觉任务。使用OpenCV进行图像识别可以通过以下步骤实现。 1. 导入OpenCV库:首先需要安装并导入OpenCV库,确保可以在代码中使用相关函数和类。 2. 加载图像:使用OpenCV的函数或方法加载待识别的图像文件。可以通过指定文件路径或者从摄像头实时获取图像。 3. 图像预处理:在进行图像识别之前,通常需要进行一些预处理操作。比如调整图像大小、灰度化处理、去除噪声等。这些预处理操作有助于提高识别准确率和效果。 4. 特征提取:通过OpenCV提供的函数或方法,从图像中提取出有用的特征信息。这些特征可以是图像的边缘、角点、颜色直方图等等,可以根据具体任务选择合适的特征。 5. 训练模型:使用提取出的特征数据,训练一个机器学习模型或者深度学习模型。可以选择使用OpenCV的机器学习模块,也可以使用其他深度学习框架如TensorFlow、PyTorch等。 6. 图像识别:使用训练好的模型对新的图像进行识别。将预处理和特征提取应用到待识别图像上,然后输入到模型中进行识别。根据不同的任务,可以得到不同的识别结果,比如物体识别、手势识别、人脸识别等。 7. 分析结果:根据识别结果进行分析,可以对图像内容进行标记、分类、计数等处理。根据具体需求,可以输出结果图像、生成报告或者执行其他进一步的操作。 总之,通过使用OpenCV进行图像识别,可以实现从加载图像到预处理、特征提取、模型训练和图像识别的完整过程,提供了强大的工具和函数库来支持各种图像识别任务。通过合理的处理和使用相关技术,可以实现高效准确的图像识别应用。 ### 回答3: OpenCV是一个开源的计算机视觉库,可以帮助我们进行图像和视频处理。通过使用OpenCV,我们可以实现图像识别的功能。 在使用OpenCV进行图像识别时,我们可以首先加载并读取待识别的图像。然后,可以应用不同的技术和算法对图像进行处理和分析。例如,我们可以使用特征提取算法,如SIFT(尺度不变特征变换)或SURF(加速稳健特征),来提取图像中的关键点和特征描述符。然后,可以使用这些特征描述符进行匹配,以识别图像中的物体或场景。 另外,我们还可以使用机器学习算法来训练图像分类器,以识别不同类别的图像。对于训练图像分类器,我们需要准备一组已标记的图像数据集,然后使用OpenCV提供的机器学习算法,如支持向量机(SVM)或卷积神经网络(CNN),进行训练和优化。训练完成后,我们就可以使用这个分类器对新的未知图像进行分类和识别。 此外,OpenCV还提供了其他功能,如人脸识别、目标跟踪、图像分割等。通过使用这些功能,我们可以进一步提高图像识别的准确性和性能。 综上所述,利用OpenCV进行图像识别可以通过特征提取和匹配、机器学习分类器等技术来实现。OpenCV作为一个强大的计算机视觉库,为我们提供了丰富的工具和算法,方便我们进行图像识别和处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值