螺母外轮廓为正六边形,最小外接矩形为正方形,该程序较为简单,判断其外接矩形近似于正方形即为螺母。
#include
#include
#include
using namespace cv;
using namespace std;
int main()
{
Mat img = imread("D:/PyCharm/pythonProject/OpenCV-py/parts/17.png");
if (img.empty())
{
cout << "请确认图像文件名称是否正确" << endl;
return -1;
}
Mat img2;
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(10, 10));
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++)
{
// 最小外接矩形
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 << "min 长" << x << " " << "宽" << y << endl;
if ((rrect.size.width > 0.8 * rrect.size.height) && (rrect.size.width < 1.2 * rrect.size.height)) //长宽比 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));
}
}
//输出绘制外接矩形的结果
imshow("min", img2);
waitKey(0);
return 0;
}
实现方式简单明了,但问题也暴露很明显,例如改变拍照角度影响很大。另外,图像处理方法有待改善,例如背景复杂会导致误识别。
该方法最大的问题就是:只要能识别出近似正方形,该对象就会被认定为螺母。
后面用其他方法继续改进。