【DIY贴片机】基于opencv识别定位电子元件

【DIY贴片机】基于opencv识别定位电子元件

识别效果:在这里插入图片描述
操作步骤:
一、识别图像中目标数量
1.1加载图片
1.2滤波
1.3转灰度
1.4边缘检测
1.5二值化
1.6形态学操作
1.7画轮廓、最小外接矩形
二、确定每个目标位置与角度
2.1缩放最小外接矩形
2.2计算四个目标位置平均灰度值,平均灰度值最大的为1脚位置
2.3标记出1脚
2.4计算旋转角度(0-360度)

代码如下:

#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>

using namespace cv;
using namespace std;

float seekFirstFoot(Mat image, RotatedRect box_min, Size size);
int compare_min(double val1, double val2, double val3, double val4);
int compare_max(double val1, double val2, double val3, double val4);
Point cp(Point pos1, Point pos2, Point pos3, Point pos4);

void main()
{
	Mat src = imread("F:\\opencv_program\\IC检测素材\\微信图片_20210315144948.jpg");

	//高斯滤波
	Mat gaussian;
	GaussianBlur(src, gaussian, Size(3, 3), 0);
	//imshow("gaussian", gaussian);

	//转灰度图
	Mat gray;
	cvtColor(gaussian, gray, CV_BGR2GRAY);
	//imshow("gray", gray);

	//边缘检测
	Mat canny;
	Canny(gray, canny, 50, 255);
	//imshow("canny", canny);

	//二值化
	Mat binImag;
	threshold(gray, binImag, 100, 255, THRESH_BINARY);
	//inRange(gray, Scalar(0, 70, 70), Scalar(10, 255, 255), binImag);
	bitwise_not(binImag, binImag);
	//imshow("binImag", binImag);

	//形态学操作
	Mat morphology;
	Mat kernel = getStructuringElement(CV_SHAPE_RECT, Size(3, 3));
	morphologyEx(binImag, morphology, MORPH_OPEN, kernel, Point(-1, -1), 4);
	//imshow("morphology", morphology);

	//发现轮廓
	vector<vector<Point>> contours;
	findContours(morphology, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
	cout << "目标数量:" << contours.size() << endl;
	vector<Rect> bounding(contours.size());  //外接矩形
	vector<RotatedRect> box(contours.size()); //定义最小外接矩形集合
	Point2f rect[4];
	Point2f recr_min[4];

	//画轮廓、计算角度
	for (int i = 0; i < contours.size(); i++)
	{
		bounding[i] = boundingRect(Mat(contours[i]));  //计算外接矩形
		box[i] = minAreaRect(Mat(contours[i])); //计算每个轮廓的最小外接矩形
		//printf("最小外接圆旋转角度:%f \r\n", box[i].angle);
		rectangle(src, bounding[i], Scalar(255, 0, 0));  //绘制外接矩形
		circle(src, Point(box[i].center.x, box[i].center.y), 4, Scalar(0, 0, 255), -1);  //绘制最小外接矩形中心
		box[i].points(rect);
		for (int j = 0; j < 4; j++)
		{
			line(src, rect[j], rect[(j + 1) % 4], Scalar(255, 0, 255), 3); //绘制最小外接矩形的四条直线
		}
		//drawContours(src,contours,i,Scalar(255,0,0)); //绘制轮廓
		//cout << box[i].size << endl;
		cout << "目标【" << i << "】";
		cout << "坐标:" << box[i].center;
		string str = to_string(i);
		putText(src, str, Point(int(box[i].center.x), int(box[i].center.y)), FONT_HERSHEY_SIMPLEX, 2, Scalar(0, 255, 0));


		//计算旋转角度
		float zoom = 0.63;  //缩放比例
		RotatedRect box_min(Point(box[i].center.x, box[i].center.y), Size(box[i].size.width * zoom, box[i].size.height * zoom), box[i].angle); //缩放最小外接旋转矩形

		seekFirstFoot(src, box_min, Size(35, 35));  //根据传入的旋转矩形,计算矩形四个点在size范围内的平均灰度,返回最大平均灰度值所在点与X轴的角度,(0-360度)
	}

	imshow("src", src);
	waitKey(0);
}



float seekFirstFoot(Mat image, RotatedRect box_min, Size size)
{
	Point2f rect_min[4];
	box_min.points(rect_min);


	Point2f rect_micro[4];
	double m[4];  //可能为丝印四个点的灰度均值
	Point pos[4]; //可能为丝印的四个点左上角坐标
	int target_index;  //丝印点下标
	for (int k = 0; k < 4; k++)
	{
		//line(image, rect_min[k], rect_min[(k + 1) % 4], Scalar(255, 100, 255), 1); //绘制矩形的四条直线
		//cout << "坐标【" << k << "】x=" << rect_min[k].x << "y=" << rect_min[k].y << endl;
	}

	for (int i = 0; i < 4; i++)
	{
		RotatedRect rect_micro(Point(rect_min[i].x, rect_min[i].y), size, 0);
		Point2f rect_micro_pos[4];
		rect_micro.points(rect_micro_pos);
		for (int j = 0; j < 4; j++)
		{
			//line(image, rect_micro_pos[j], rect_micro_pos[(j + 1) % 4], Scalar(0, 255, 0), 1); //绘制矩形的四条直线
			//putText(image, "1", (rect_micro_pos[j], rect_micro_pos[(j + 1) % 4]), (0, 255, 0));
			//putText(image, "q", Point(int(rect_micro_pos[j].x), int(rect_micro_pos[j].y)), FONT_HERSHEY_SIMPLEX,2, Scalar(0, 255, 0));
			//cout << "【1】 X=" << int(rect_micro_pos[j].x) << "  Y=" << int(rect_micro_pos[j].y) << endl;

		}
		pos[i] = cp(rect_micro_pos[0], rect_micro_pos[1], rect_micro_pos[2], rect_micro_pos[3]);  //返回最小矩形左上方坐标,
		Rect rect_temp(int(pos[i].x), int(pos[i].y), size.width, size.height);
		Mat InputImage = image(rect_temp);
		//imshow("InputImage", InputImage); 
		Mat  mat_mean, mat_stddev;
		meanStdDev(InputImage, mat_mean, mat_stddev);//求灰度图像的均值、均方差
		m[i] = mat_mean.at<double>(0, 0);

	}
	target_index = compare_max(m[0], m[1], m[2], m[3]);
	Rect mask(int(pos[target_index].x), int(pos[target_index].y), size.width, size.height);
	rectangle(image, mask, Scalar(100, 100, 255));

	//计算旋转角度
	Point p1(box_min.center.x, box_min.center.y);
	Point p2(pos[target_index]);
	double numble = 180 / CV_PI * (atan2(p2.y - p1.y, p2.x - p1.x));

	if (numble > 0)
	{
		numble = 360 - abs(numble);
	}
	if (numble < 0)
	{
		numble = abs(numble);
	}
	cout << "角度 = " << numble << endl;
	return 0;
}

//比较四个数,返回最小数的下标
int compare_min(double val1, double val2, double val3, double val4)
{
	if (val1 <= val2 && val1 <= val3 && val1 <= val4)
	{
		return 0;
	}
	if (val2 <= val1 && val2 <= val3 && val2 <= val4)
	{
		return 1;
	}
	if (val3 <= val2 && val3 <= val1 && val3 <= val4)
	{
		return 2;
	}
	if (val4 <= val1 && val4 <= val3 && val4 <= val2)
	{
		return 3;
	}
}

//比较四个数,返回最大数的下标
int compare_max(double val1, double val2, double val3, double val4)
{
	if (val1 >= val2 && val1 >= val3 && val1 >= val4)
	{
		return 0;
	}
	if (val2 >= val1 && val2 >= val3 && val2 >= val4)
	{
		return 1;
	}
	if (val3 >= val2 && val3 >= val1 && val3 >= val4)
	{
		return 2;
	}
	if (val4 >= val1 && val4 >= val3 && val4 >= val2)
	{
		return 3;
	}
}

//比较矩形的四个点,返回矩形左上方的点坐标
Point cp(Point pos1, Point pos2, Point pos3, Point pos4)
{
	int add1 = pos1.x + pos1.y;
	int add2 = pos2.x + pos2.y;
	int add3 = pos3.x + pos3.y;
	int add4 = pos4.x + pos4.y;
	int temp = compare_min(add1, add2, add3, add4);
	if (temp == 0)
		return pos1;
	if (temp == 1)
		return pos2;
	if (temp == 2)
		return pos3;
	if (temp == 3)
		return pos4;
}

原图像:
在这里插入图片描述

前言: 开源的opencv真是一件伟大的产品,那么多个函数跟变量(具体多少还没数过)。要是结合起来综合运用几乎可以胜任任何有关图像识别和处理方面的工作。如果能更深入一点根据具体需要修改或优化里面的源码那更是如虎添翼。 花了点时间浏览了www.opencv.org.cn论坛里的所有贴子,还好不多才200多页。总体上对opencv里的一些常用函数功能作用大致有点了解,筛选一些跟元件识别有关的运用内容,但它论坛里的贴子回复的内容点到即止的居多。从网上下载了能搜到的教程跟代码全学习了解测试了一下,图像处理流程通常先开始都是要进行滤波,除燥,灰度,二值化后再轮廓识别等。 开始动手 经过多次好多次运行测试组合,终于有一次显示出意外的惊人效果,而且相当简单只是调用了几个函数而以,就可以有这样效果实在出人意料。第一个是进行元件中心点获取,也是直接调用函数再加点东西就可以得出元件的四个矩形顶点坐标,有这几个坐标就可以直接算出元件中间点所在的坐标了。如果要检测元件摆放角度是否是垂直90度,只要判断边宽的长度为最小或最大时就是垂直90度。 但这个矩形框无法测出元件具体角度。如截图: 测试视频地址:https://v.youku.com/v_show/id_XMjU5NzY5NTI0.html 不过,还有另外一个函数可以提供这个功能,调用后可以直接求出最小外接矩形和角度 如截图: 测试视频地址:https://v.youku.com/v_show/id_XMjYwMDMzMDc2.html 说明:里面的光源不行,临时用手电筒,和在光盘上插几个LED做环形灯做照明,无法做到无阴影显示。如果光源做的好,效果应该是非常精确稳定。 识别包含下面2种做法: opencv里需要的头文件跟库文件都已编译好放在和设置在当前程序目录下,就可不用安装opencv 也能直接编译。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值