C++ OpenCV实践:复杂背景下划痕检测


前言

今天在51Halcon网站答疑区看到划痕检测的求助,觉得挺有意思,就用OpenCV实现了下,这里分享给大家。

问题链接:https://www.51halcon.com/thread-941-1-1.html


1. 检测步骤

先上原图:
请添加图片描述
这个问题就是检测上图环上右上角大约45度的一个划痕或者缝隙。

本人实现检测主要步骤:

  1. 图片缩小1倍(图片太大了,OpenCV显示窗口显示不全)
  2. 图像灰度化;
  3. 高斯模糊去除噪声影响;
  4. 对图像做均值化处理,将划痕覆盖;
  5. 均值前后图像差值处理,得到包含划痕的灰度图;
  6. 二值化处理
  7. 提取前景轮廓,分析划痕几何特性,筛选划痕轮廓;
  8. 绘制满足条件的划痕轮廓。

2. C++ OpenCV实现

#include <iostream>
#include <opencv2\imgcodecs.hpp>
#include <opencv2\core.hpp>
#include <opencv2\imgproc.hpp>
#include <opencv2\highgui.hpp>

using namespace cv;

int main()
{
    
    
	std::string strImgFile = "C:\\Temp\\common\\Workspace\\Opencv\\images\\crack_with_complex_bg.bmp";
	Mat mSrc = imread(strImgFile);
	CV_Assert(!mSrc.empty());

	resize(mSrc, mSrc, Size(mSrc.cols/2, mSrc.rows/2));

	Mat mGray;
	cvtColor(mSrc, mGray, COLOR_BGR2GRAY);
	CV_Assert(!mGray.empty());

	GaussianBlur(mGray, mGray, Size(5, 5), -1);

	Mat mMean;
	blur(mGray, mMean, Size(15, 15));
	CV_Assert(!mMean.empty());

	Mat mDiff;
	absdiff(mMean, mGray, mDiff);
	CV_Assert(!mDiff.empty());

	imshow("diff", mDiff);

	Mat mThresh;
	threshold(mDiff, mThresh, 5, 255, THRESH_BINARY);
	CV_Assert(!mThresh.empty());

	imshow("thres", mThresh);

	std::vector<std::vector<Point>> contours;
	findContours(mThresh, contours, RETR_TREE, CHAIN_APPROX_NONE);

	RNG rng;
	
	Mat mSrcCopy = mSrc.clone();
	for (int i = 0; i < contours.size(); i++)
	{
    
    
		RotatedRect rr = minAreaRect(contours[i]);
		float max = rr.size.height > rr.size.width ? rr.size.height : rr.size.width;
		float min = rr.size.height > rr.size.width ? rr.size.width : rr.size.height;

		if (rr.size.area() > 1000 && rr.size.area() < 1000000 && 
			max / min > 3 && max / min < 4)
		{
    
    
			/*int b = rng.uniform(0, 256);
			int g = rng.uniform(0, 256);
			int r = rng.uniform(0, 256);
			drawContours(mSrcCopy, contours, i, Scalar(b, g, r));*/
			drawContours(mSrcCopy, contours, i, Scalar(0, 0, 255));
		}
	}

	imshow("contours", mSrcCopy);

	waitKey(0);
	destroyAllWindows();

	return 0;
}

3. 结果展示

在这里插入图片描述

总结

在轮廓筛选时设置的筛选规则仅适用于原始图缩小1倍大小,换一张图或者使用原始图大小就要更新筛选规则了,通用性方面可能不太好。个人觉得可以对原图做一个Mask图像,仅对圆环区域进行轮廓提取与过滤,这样不论是速度方面还是通用性方面都会更好,本人这里就不实现了,感兴趣的读者可以试试,谢谢大家!

Guess you like

Origin blog.csdn.net/DU_YULIN/article/details/120651380