OpenCV4 电容缺陷检测

#pragma once
#include <iostream>
#include <string>
#include "opencv2/opencv.hpp"
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace std;
using namespace cv;

int morph_elem = 0;
int morph_size = 0;
int morph_operator = 0;

int whiteSpotAreaThreshold = 15; //负极白点面积阈值
int normalAreaThreshold = 6210; //负极轮廓面积阈值

//定义点线距离的函数
double getDistance(Point2f point1, Point2f point2, Point2f point3)
{
	//建立直线方程Ax+By+C=0-->(y2-y1)*x+(x1-x2)*y+(x2*y1-x1*y2)=0
	double A = point2.y - point1.y;
	double B = point1.x - point2.x;
	double C = point2.x * point1.y - point1.x * point2.y;
	double a = A * A;
	double b = B * B;

	//直线距离公式D=|A*x3+B*y3+C|/sqrt(A^2+B^2)
	double w = (A * point3.x + B * point3.y + C);
	if (w < 0) w = 0 - w;//取绝对值

	return double(w / sqrt(a + b));
}

//根据阈值统计像素点
int countSums(Mat src)
{
	int counter = 0;
	//迭代器访问像素点
	Mat_<uchar>::iterator it = src.begin<uchar>();
	Mat_<uchar>::iterator itend = src.end<uchar>();
	for (; it != itend; ++it)
	{
		if ((*it) > 160) counter += 1;//二值化后,像素点是0或者255
	}
	return counter;
}

int main()
{
	//*************** 【正反有无检测】第一步:霍夫圆变换找圆形轮廓(如果有则返回朝上,没有进行第二步) *******************
	cv::Mat unknownSurfaceGry, unknownSurfaceBlur, unknownSurfaceCny, unknownSurfaceThresh;
	const char* unknownSurfaceImagePath = "E:/projects/pyHome/learningPython/day_06_openCV/dianrong/21.bmp";
	cv::Mat unknownSurfaceImgBig = cv::imread(unknownSurfaceImagePath, -1);
	if (unknownSurfaceImgBig.empty()) return -1;

	// 截取ROI区域 x,y,w,h 后灰度化、高斯模糊、阈值、边缘检测
	cv::Rect resultRect = cv::Rect(550, 250, 700, 550);
	cv::Mat unknownSurfaceImg = unknownSurfaceImgBig(resultRect).clone();
	cv::cvtColor(unknownSurfaceImg, unknownSurfaceGry, cv::COLOR_BGR2GRAY);
	cv::GaussianBlur(unknownSurfaceGry, unknownSurfaceBlur, Size(7, 7), 0, 0);
	cv::threshold(unknownSurfaceBlur, unknownSurfaceThresh, 100, 255, THRESH_BINARY + THRESH_OTSU);
	cv::Canny(unknownSurfaceThresh, unknownSurfaceCny, 40, 80, 3, true);

	vector<Vec3f> unknownSurfaceCircles;
	cv::HoughCircles(unknownSurfaceCny, unknownSurfaceCircles, HOUGH_GRADIENT, 1, 80, 100, 35, 70, 180);
	if (unknownSurfaceCircles.size() < 1) {
		cout << "没有圆" << endl;
	}else{
		cout << "检测到圆,当前电容朝上" << endl;
		return -1;
	}

	//*************** 【正反有无检测】第二步:轮廓匹配找底座轮廓(如果有则返回朝下,没有则返回空电容) *******************
	vector<vector<Point> > unknownSurfaceContoursTemp, unknownSurfaceContours;	// 轮廓
	vector<Vec4i> unknownSurfaceHierarchy;
	cv::findContours(unknownSurfaceCny, unknownSurfaceContoursTemp, unknownSurfaceHierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
	
	for (int i = 0; i < unknownSurfaceContoursTemp.size();i++) {
		cout << "轮廓面积为-----:" << contourArea(unknownSurfaceContoursTemp[i]) << endl;
	}

	unknownSurfaceContours.push_back(unknownSurfaceContoursTemp[0]);
	drawContours(unknownSurfaceImg, unknownSurfaceContours, -1, Scalar(255, 0, 0), 1, 8);

	double unknownSurfaceMatch = cv::matchShapes(unknownSurfaceContours[0], unknownSurfaceContours[0], 2, 0.0);
	cout << "底座轮廓匹配差异度为-----:" << unknownSurfaceMatch << endl;

	cv::imshow("unknownSurfaceCny", unknownSurfaceCny);
	cv::imshow("unknownSurfaceImg", unknownSurfaceImg);

	*************** 【正面检测】第一步:矫正电容之找负极右边缘直线和其角度 *******************
	 预声明【字符面】图片输出对象
	//cv::Mat imgTopGry, imgTopCny, imgTopThresh, imgTopEnd, imgTopGryEnd;
	//const char* imageTopPath = "E:/projects/pyHome/learningPython/day_06_openCV/dianrong/16.bmp";
	//cv::Mat imgTopWhole = cv::imread(imageTopPath, -1);
	//if (imgTopWhole.empty()) return -1;

	//cv::Rect resultRect = cv::Rect(555, 370, 410, 360);
	//cv::Mat imgTop = imgTopWhole(resultRect).clone();

	//cv::cvtColor(imgTop, imgTopGry, cv::COLOR_BGR2GRAY);
	//cv::threshold(imgTopGry, imgTopThresh, 100, 255, THRESH_BINARY + THRESH_OTSU);
	//cv::Canny(imgTopThresh, imgTopCny, 40, 80, 3, true);

	//vector<Vec4i> lines;
	//cv::HoughLinesP(imgTopCny, lines, 0.7, CV_PI / 180, 30, 50, 10);

	//Point p1 = Point(lines[0][0], lines[0][1]);
	//Point p2 = Point(lines[0][2], lines[0][3]);
	//float angle = atan2(p1.y - p2.y, p2.x - p1.x) * 57.29577;

	//cout << "直线个数:" << lines.size() << endl
	//	<< "角度:" << angle << endl;

	*************** 【正面检测】第二步:矫正电容之旋转图片矫正角度 *******************
	//int w = imgTop.rows;
	//int h = imgTop.cols;
	//Mat rotate = cv::getRotationMatrix2D(Point(h / 2, w / 2), 90 - angle, 1);
	//cv::warpAffine(imgTop, imgTopEnd, rotate, Point(h, w));
	//cv::warpAffine(imgTopGry, imgTopGryEnd, rotate, Point(h, w));

	//vector<Vec3f> circles;
	//cv::HoughCircles(imgTopGry, circles, HOUGH_GRADIENT, 1, 80, 100, 35, 70, 180);
	//if (circles.size() < 1) return -1;

	//float r = circles[0][2];
	//float x = circles[0][0];
	//float y = circles[0][1];
	//cout << "圆的个数:" << angle << endl
	//	<< "圆心坐标为:(" << x << ", " << y << ")" << endl
	//	<< "圆的半径是:" << r << endl;

	*************** 【正面检测】第三步:矫正电容之根据平移矩阵进行仿射变换 *******************
	定义平移矩阵
	//cv::Mat t_mat = cv::Mat::zeros(2, 3, CV_32FC1);

	//t_mat.at<float>(0, 0) = 1;
	//t_mat.at<float>(0, 2) = 20; //水平平移量
	//t_mat.at<float>(1, 1) = 1;
	//t_mat.at<float>(1, 2) = 10; //竖直平移量

	根据平移矩阵进行仿射变换
	//cv::warpAffine(imgTopEnd, imgTopEnd, t_mat, imgTop.size());
	//cv::warpAffine(imgTopGryEnd, imgTopGryEnd, t_mat, imgTop.size());

	*************** 【正面检测】第四步:负极缺陷检测之检测负极大小 *******************
	//cv::threshold(imgTopGryEnd, imgTopThresh, 100, 255, THRESH_BINARY + THRESH_OTSU); // 阈值化矫正后的图片
	//cv::Canny(imgTopThresh, imgTopCny, 40, 80, 3, true); // 边缘检测

	//vector<Vec4i> linesEnd;
	//cv::HoughLinesP(imgTopCny, linesEnd, 0.7, CV_PI / 180, 30, 50, 10);
	///*for (size_t i = 0; i < linesEnd.size(); i++)
	//{
	//	line(imgTopEnd, Point(linesEnd[i][0], linesEnd[i][1]), Point(linesEnd[i][2], linesEnd[i][3]), Scalar(0, 0, 255), 2, 8);
	//}*/

	//double distance0 = getDistance(Point(linesEnd[0][0], linesEnd[0][1]), Point(linesEnd[0][2], linesEnd[0][3]), Point(linesEnd[0][0], linesEnd[0][1]));
	//cout << "当前负极边缘与模板边缘距离:" << distance0 << endl;
	*************** 【正面检测】第五步:负极缺陷检测之检测负极有无白点 *******************
	//vector<vector<Point> > imgTopCnyContoursTemp;
	//vector<Vec4i> imgTopCnyHierarchy;
	//cv::findContours(imgTopCny, imgTopCnyContoursTemp, imgTopCnyHierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE); // 找轮廓

	 根据面积阈值把白点去掉
	//vector<vector<Point> > imgTopCnyContours;
	//for (int i = 0; i < imgTopCnyContoursTemp.size(); i++) {
	//	int xTemp = imgTopCnyContoursTemp[i][0].x;
	//	if (xTemp > linesEnd[0][0]) { // 负极右边缘线右侧的轮廓去掉
	//		continue;
	//	}
	//	double areaNegativePoleTemp = cv::contourArea(imgTopCnyContoursTemp[i]);
	//	if (areaNegativePoleTemp < normalAreaThreshold) {
	//		if (areaNegativePoleTemp > whiteSpotAreaThreshold) {
	//			cout << "停止遍历,第" << i << "个白点轮廓是破皮,阈值为" <<
	//				whiteSpotAreaThreshold << ",当前白点面积为:" << areaNegativePoleTemp << endl;
	//			break;
	//		}
	//		cout << "第" << i << "个白点轮廓面积在正常范围内,面积为:" << areaNegativePoleTemp << endl;
	//	}
	//	else {
	//		cout << "第" << i << "个非白点轮廓面积为:" << areaNegativePoleTemp << endl;
	//		imgTopCnyContours.clear(); // RETR_TREE这种检索方式负极轮廓出现了两个,保留最后一个
	//		imgTopCnyContours.push_back(imgTopCnyContoursTemp[i]);
	//	}
	//}

	//drawContours(imgTopEnd, imgTopCnyContours, -1, Scalar(0, 255, 0), 2, 8);
	*************** 【正面检测】第六步:字符检测之利用图像灰度图差值、均值、方差、统计像素个数判断相似度 *******************
	 尝试了灰度图后加大津法处理发现效果没有明显改观,因此只对图像做灰度处理,直接相减,设定阈值即可
	//cv::Mat charOneWholeImg, charOneImgGry, charThreeWholeImg, charThreeImgGry, charOneWholeImg2, charOneImgGry2;
	//charOneWholeImg = cv::imread("E:/projects/pyHome/learningPython/day_06_openCV/dianrong/8.bmp", -1);
	//charOneWholeImg2 = cv::imread("E:/projects/pyHome/learningPython/day_06_openCV/dianrong/2.bmp", -1);
	//if (charOneWholeImg.empty() || charOneWholeImg2.empty()) return -1;

	//cv::Mat charOneImg = charOneWholeImg(Rect(655, 465, 15, 20)).clone();
	//cv::Mat charOneImg2 = charOneWholeImg2(Rect(582, 498, 15, 20)).clone();
	//cv::Mat charThreeImg = charOneWholeImg(Rect(655, 484, 15, 20)).clone();
	//cv::cvtColor(charOneImg, charOneImgGry, cv::COLOR_BGR2GRAY);
	//cv::cvtColor(charOneImg2, charOneImgGry2, cv::COLOR_BGR2GRAY);
	//cv::cvtColor(charThreeImg, charThreeImgGry, cv::COLOR_BGR2GRAY);

	灰度差
	//Mat subtractRes, subtractRes1, subtractRes2;
	//Scalar  subtractSumRes, subtractSumRes1, subtractSumRes2;
	//cv::subtract(charOneImgGry2, charOneImgGry, subtractRes);
	//cv::subtract(charThreeImgGry, charOneImgGry, subtractRes1);
	//cv::subtract(charOneImgGry, charOneImgGry, subtractRes2);
	//subtractSumRes = sum(subtractRes);
	//subtractSumRes1 = sum(subtractRes1);
	//subtractSumRes2 = sum(subtractRes2);

	均值和方差
	//Mat mean, stddv, mean1, stddv1, mean2, stddv2;
	//cv::meanStdDev(charOneImgGry, mean, stddv);
	//cv::meanStdDev(charOneImgGry2, mean1, stddv1);
	//cv::meanStdDev(charThreeImgGry, mean2, stddv2);

	设定阈值160统计像素个数
	//int pixelSums = countSums(charOneImgGry);
	//int pixelSums1 = countSums(charOneImgGry2);
	//int pixelSums2 = countSums(charThreeImgGry);

	//cout << "灰度差subtractSumRes,subtractSumRes1,subtractSumRes2分别为------:" << 
	//	subtractSumRes << ", " << subtractSumRes1 << ", " << subtractSumRes2 << endl
	//	<< "均值mean,mean1,mean2分别为------:" <<
	//	mean << ", " << mean1 << ", " << mean2 << endl
	//	<< "方差stddv,stddv1,stddv2分别为------:" <<
	//	stddv << ", " << stddv1 << ", " << stddv2 << endl
	//	<< "阈值160以上像素个数pixelSums,pixelSums1,pixelSums2分别为------:" <<
	//	pixelSums << ", " << pixelSums1 << ", " << pixelSums2 << endl;

	*************** 【正面检测】第七步:字符检测之轮廓相似度 *******************
	//Mat charOneImgThresh, charOneImgThresh2, charThreeImgThresh;
	//cv::threshold(charOneImgGry, charOneImgThresh, 100, 255, THRESH_BINARY + THRESH_OTSU);
	//cv::threshold(charOneImgGry2, charOneImgThresh2, 100, 255, THRESH_BINARY + THRESH_OTSU);
	//cv::threshold(charThreeImgGry, charThreeImgThresh, 100, 255, THRESH_BINARY + THRESH_OTSU);

	//vector<vector<Point> > charOneImgContours, charOneImgContours2, charThreeImgContours;
	//vector<Vec4i> charOneImgHierarchy, charOneImgHierarchy2, charThreeImgHierarchy;
	//cv::findContours(charOneImgThresh, charOneImgContours, charOneImgHierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
	//cv::findContours(charOneImgThresh2, charOneImgContours2, charOneImgHierarchy2, RETR_TREE, CHAIN_APPROX_SIMPLE);
	//cv::findContours(charThreeImgThresh, charThreeImgContours, charThreeImgHierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
	//charOneImgContours.erase(charOneImgContours.begin());
	charOneImgContours2.erase(charOneImgContours2.begin());
	//charThreeImgContours.erase(charThreeImgContours.begin());
	//drawContours(charOneImg, charOneImgContours, -1, Scalar(0, 0, 255), 1, 8);
	//drawContours(charOneImg2, charOneImgContours2, -1, Scalar(0, 0, 255), 1, 8);
	//drawContours(charThreeImg, charThreeImgContours, -1, Scalar(0, 0, 255), 1, 8);
	//cv::imshow("charOneImg", charOneImg);
	//cv::imshow("charOneImg2", charOneImg2);
	//cv::imshow("charThreeImg", charThreeImg);

	//double match = cv::matchShapes(charOneImgContours[0], charOneImgContours[0], 2, 0.0);
	//double match1 = cv::matchShapes(charOneImgContours[0], charThreeImgContours[0], 2, 0.0);
	//double match2 = cv::matchShapes(charOneImgContours[0], charOneImgContours2[0], 2, 0.0);
	//cout << "第一个字符与自己做模板形状匹配差异度为:" << match << endl
	//	<< "第一个字符与第二个字符做模板形状匹配差异度为:" << match1 << endl
	//	<< "第一个字符与第三个字符做模板形状匹配差异度为:" << match2 << endl;

	*************** 【反面检测】第一步:计算底座轮廓面积 *******************
	 预声明【底座】图片输出对象
	//cv::Mat base_gaussianBlur, base_gry, base_cny, base_thresh, base_opening;
	//const char* imagePath = "E:/projects/pyHome/learningPython/day_06_openCV/dianrong/21.bmp";
	//cv::Mat img_big = cv::imread(imagePath, -1);
	//if (img_big.empty()) return -1;

	// 截取ROI区域 x,y,w,h
	cv::Rect resultRect = cv::Rect(550, 250, 700, 550);
	cv::Mat img = img_big(resultRect).clone();
	//cv::Mat img = img_big.clone();

	 灰度化
	//cv::cvtColor(img, base_gry, cv::COLOR_BGR2GRAY);
	cv::imshow("gray", base_gry);

	 先高斯模糊 采用7*7大卷积核,过滤大噪声
	//GaussianBlur(base_gry, base_gaussianBlur, Size(7, 7), 0, 0);

	 大津法阈值分割(因为图片明暗不均)
	//cv::threshold(base_gaussianBlur, base_thresh, 100, 255, THRESH_BINARY + THRESH_OTSU);

	 开运算腐蚀一下阈值图
	//int operation = morph_operator + 2;
	//Mat element = getStructuringElement(morph_elem, Size(2 * morph_size + 7, 2 * morph_size + 7), Point(morph_size, morph_size));
	//morphologyEx(base_thresh, base_opening, operation, element);

	 边缘检测
	//cv::Canny(base_opening, base_cny, 40, 80, 3, true);

	 提取轮廓
	//vector<vector<Point> > base_contours;
	//vector<Vec4i> base_hierarchy;
	//cv::findContours(base_cny, base_contours, base_hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

	 画轮廓
	//Scalar color(rand() & 255, rand() & 255, rand() & 255);
	//drawContours(img, base_contours, -1, color, 2, 8);

	 底座最小外接矩形
	//Point2f vtx[4];
	//RotatedRect box = cv::minAreaRect(base_contours[0]);
	//box.points(vtx); // 底座最小外接矩形的四个角

	 Draw the bounding box
	//for (int i = 0; i < 4; i++)
	//	line(img, vtx[i], vtx[(i + 1) % 4], Scalar(0, 255, 0), 2, LINE_AA);

	 计算面积
	//double area0 = cv::contourArea(base_contours[0]);
	//cout << "轮廓数量:" << base_contours.size() << endl <<
	//	"底座的面积为:" << area0 << endl;

	*************** 【反面检测】第二步:模板匹配底座相似度 *******************

	 轮廓形状匹配
	//double match = cv::matchShapes(base_contours[0], base_contours[0], 1, 0.0);
	//cout << "与底座模板形状匹配差异度为:" << match << endl;

	*************** 【反面检测】第三步:计算针脚角度 *******************
	 预声明【针脚】图片输出对象
	//cv::Mat pin_cny, pin_thresh;
	//cv::threshold(base_gaussianBlur, pin_thresh, 100, 255, THRESH_BINARY_INV);
	//cv::Canny(pin_thresh, pin_cny, 40, 80, 3, true);

	 提取针脚轮廓
	//vector<vector<Point> > pin_contours;
	//vector<Vec4i> pin_hierarchy;
	//cv::findContours(pin_cny, pin_contours, pin_hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

	 根据面积阈值筛选轮廓,记录针脚最小外接矩形角度
	//vector<vector<Point> > pin_contours_end;
	//vector<Point2f> pinVtxs;
	//for (int i = 0; i < pin_contours.size(); i++) {
	//	if (cv::contourArea(pin_contours[i]) > 3000) {
	//		pin_contours_end.push_back(pin_contours[i]);

	//		// 最小外接矩形
	//		Point2f pin_vtx[4];
	//		RotatedRect pin_box = cv::minAreaRect(pin_contours[i]);
	//		cout << "针脚角度为:" << pin_box.angle << endl;
	//		pin_box.points(pin_vtx); // 针脚最小外接矩形的四个角

	//		pinVtxs.push_back(pin_vtx[0]);
	//		pinVtxs.push_back(pin_vtx[3]);

	//		// Draw the bounding box
	//		for (int i = 0; i < 4; i++)
	//			line(img, pin_vtx[i], pin_vtx[(i + 1) % 4], Scalar(0, 255, 0), 2, LINE_AA);
	//	}
	//}
	//cout << "针脚数目为:" << pin_contours_end.size() << endl;

	*************** 【反面检测】第四步:计算点到线距离判断针脚是否错位、针脚是不是过长 *******************
	//Point2f pointA = vtx[0]; // 底座最小外接矩形左上角 A
	//Point2f pointB = vtx[1]; // 底座最小外接矩形右下角 B
	//Point2f pointC = vtx[2]; // 底座最小外接矩形左上角 C
	//Point2f pointD = vtx[3]; // 底座最小外接矩形左下角 D
	//Point2f point_a = pinVtxs[1]; // 下边针脚最小外接矩形左下角 a
	//Point2f point_b = pinVtxs[2]; // 上边针脚最小外接矩形左上角 b
	//circle(img, pointA, 2, Scalar(0, 0, 255), 2);//用小圆标记点
	//circle(img, pointB, 2, Scalar(0, 0, 255), 2);//用小圆标记点
	//circle(img, pointC, 2, Scalar(0, 0, 255), 2);//用小圆标记点
	//circle(img, pointD, 2, Scalar(0, 0, 255), 2);//用小圆标记点
	//circle(img, point_a, 2, Scalar(255, 0, 0), 2);//用小圆标记点
	//circle(img, point_b, 2, Scalar(255, 0, 0), 2);//用小圆标记点
	//cv::putText(img, "A", pointA, FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255), 2, 8);
	//cv::putText(img, "B", pointB, FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255), 2, 8);
	//cv::putText(img, "C", pointC, FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255), 2, 8);
	//cv::putText(img, "D", pointD, FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255), 2, 8);
	//cv::putText(img, "a", point_a, FONT_HERSHEY_SIMPLEX, 1, Scalar(255, 0, 0), 2, 8);
	//cv::putText(img, "b", point_b, FONT_HERSHEY_SIMPLEX, 1, Scalar(255, 0, 0), 2, 8);

	//double distance1 = getDistance(pointA, pointD, point_a);
	//double distance2 = getDistance(pointA, pointD, point_b);
	//double distance3 = getDistance(pointC, pointD, point_a);
	//double distance4 = getDistance(pointA, pointB, point_b);
	//cout << "第一个针脚到底座【左边界】距离为:" << distance1 << endl
	//	<< "第二个针脚到底座【左边界】距离为:" << distance2 << endl
	//	<< "第一个针脚到底座【下边界】距离为:" << distance3 << endl
	//	<< "第二个针脚到底座【上边界】距离为:" << distance4 << endl;

	//cv::imshow("img", img);

	cv::waitKey(0);
	cv::destroyWindow("Example 2-1");
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值