前言 

目前地铁上检修螺丝后,会涂抹一种红色标记线,来代表检测完成,日后检修员就可以通过肉眼来观察螺丝是否松动,这样可以大大提高检修的效率问题。所以我们参照这个思路,通过opencv来实现螺丝是否松动检测。

      

iOS opencv检测活体 opencv实时检测_opencv

   

iOS opencv检测活体 opencv实时检测_iOS opencv检测活体_02

   

正文

  1. 首先我们通过目标检测算法,识别出图像中螺丝的区域。这里不实现了就,自行通过yolo等算法实现。
  2. 识别出目标区域后,我们首先提取图像中的红色区域(假设我们用红色标记)
void extract_red_area(const cv::Mat &image, cv::Mat &redMat) {
	int width = image.cols;
	int height = image.rows;
	int x, y;
	double B = 0.0, G = 0.0, R = 0.0, H = 0.0, S = 0.0, V = 0.0;
	redMat = Mat::zeros(image.size(), CV_8UC1);
	for (x = 0; x < height; x++)
	{
		for (y = 0; y < width; y++)
		{
			B = image.at<Vec3b>(x, y)[0];
			G = image.at<Vec3b>(x, y)[1];
			R = image.at<Vec3b>(x, y)[2];
			RGB2HSV(R, G, B, H, S, V);
			//红色范围,范围参考的网上。可以自己调
			if ((H >= 312 && H <= 360) && (S >= 17 && S <= 100) && (V > 18 && V < 100))
				redMat.at<uchar>(x, y) = 255;
		}
	}
}

iOS opencv检测活体 opencv实时检测_iOS opencv检测活体_03

      

iOS opencv检测活体 opencv实时检测_opencv_04

  1. 提取红色区域轮廓信息,这里我们需要过滤一些,因为有一些轮廓是我们不需要的。(根据实际情况来过滤)
// 2.提取轮廓
	std::vector<std::vector<cv::Point>> contours;
	std::vector<cv::Vec4i> hierarchy;
	cv::findContours(
		redMat,               // 输入二值图
		contours,             // 存储轮廓的向量
		hierarchy,            // 轮廓层次信息
		RETR_TREE,            // 检索所有轮廓并重建嵌套轮廓的完整层次结构
		CHAIN_APPROX_NONE);   // 每个轮廓的全部像素
	printf("find %d contours \n", contours.size());
// 过滤轮廓
void filter_contours(std::vector<cv::Vec4i> &hierarchy, std::vector<std::vector<cv::Point>> &contours) {
	std::vector<std::vector<cv::Point>>::iterator itc = contours.begin();
	std::vector<cv::Vec4i>::iterator itc_hierarchy = hierarchy.begin();
	int i = 0;
	int min_size = 20;
	int max_size = 500;
	while (itc_hierarchy != hierarchy.end())
	{
		//验证轮廓大小
		//if (!(hierarchy[i][2] < 0 && hierarchy[i][3] < 0)) // 存在子轮廓/父轮廓
		if (hierarchy[i][3] > 0) // 存在父轮廓
		{
			itc = contours.erase(itc);
			itc_hierarchy = hierarchy.erase(itc_hierarchy);
		}
		else
		{
			//验证轮廓大小
			if (itc->size() < min_size || itc->size() > max_size)
			{
				itc = contours.erase(itc);
				itc_hierarchy = hierarchy.erase(itc_hierarchy);
			}
			else
			{
				++itc;
				++itc_hierarchy;
			}

			++i;
		}
	}
}
  1.  提取每一个轮廓的最小外接矩形,并绘制最小外接矩形的每条边和中心点,并计算每一个区域的角度,最后通过每一个区域的角度来判断是否对齐。
void draw_center(cv::Mat &dstImg, std::vector<std::vector<cv::Point>> &contours, std::vector<cv::Point> &vec) {
	std::vector<RotatedRect> box(contours.size()); //定义最小外接矩形集合
	Point2f rect[4];
	for (int i = 0; i < contours.size(); i++)
	{
		box[i] = minAreaRect(Mat(contours[i])); 
		cv::circle(dstImg, Point(box[i].center.x, box[i].center.y), 2, cv::Scalar(0, 255, 255), cv::FILLED);
		box[i].points(rect);
		for (int j = 0; j < 4; j++)
		{
			line(dstImg, rect[j], rect[(j + 1) % 4], Scalar(255, 0, 255), 1, 8);  //绘制最小外接矩形每条边
		}
		std::cout << "angel:" << box[i].angle << std::endl;
	}
}

 

iOS opencv检测活体 opencv实时检测_嵌套_05

     5. 以上差不多就是大概实现过程。主要实现思路就是: 识别螺丝 -> 提取红色区域 -> 识别轮廓 -> 筛选轮廓 -> 计算最小外接矩形、中心点、角度 -> 通过角度来判断是否对齐,从而来判断螺丝是否松动。

         

iOS opencv检测活体 opencv实时检测_目标检测_06

  

iOS opencv检测活体 opencv实时检测_ci_07

 

iOS opencv检测活体 opencv实时检测_iOS opencv检测活体_08

 

iOS opencv检测活体 opencv实时检测_iOS opencv检测活体_09