PCB板缺陷检测是工业视觉检测中的重要应用。本文将详细介绍如何使用OpenCvSharp实现PCB板的缺陷检测,包括缺陷、断路、短路等问题的识别。
环境准备
// NuGet包引用
// Install-Package OpenCvSharp4
// Install-Package OpenCvSharp4.runtime.win
using OpenCvSharp;
using System;
完整代码实现
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;
namespace AppPcb
{
publicclass PCBDefectDetection
{
private Mat templateImage; // 模板图像
private Mat testImage; // 待测试图像
public PCBDefectDetection(string templatePath, string testPath)
{
// 读取图像
templateImage = Cv2.ImRead(templatePath, ImreadModes.Color);
testImage = Cv2.ImRead(testPath, ImreadModes.Color);
// 确保图像加载成功
if (templateImage.Empty() || testImage.Empty())
{
thrownew Exception("图像加载失败!");
}
}
public void DetectDefects()
{
// 1. 图像预处理
Mat templateGray = PreprocessImage(templateImage);
Mat testGray = PreprocessImage(testImage);
// 2. 图像对齐
Mat alignedTest = AlignImages(templateGray, testGray);
// 3. 差异检测
Mat diffMask = DetectDifferences(templateGray, alignedTest);
// 4. 缺陷分析
AnalyzeDefects(diffMask);
// 5. 显示结果
ShowResults(diffMask);
}
private Mat PreprocessImage(Mat input)
{
Mat result = new Mat();
// 转换为灰度图
Cv2.CvtColor(input, result, ColorConversionCodes.BGR2GRAY);
// 高斯模糊去噪
Cv2.GaussianBlur(result, result, new Size(7, 7), 0);
// 自适应二值化
Cv2.AdaptiveThreshold(
result,
result,
255,
AdaptiveThresholdTypes.GaussianC,
ThresholdTypes.Binary,
13,
2
);
return result;
}
private Mat AlignImages(Mat template, Mat test)
{
// 特征点检测和匹配
var orb = ORB.Create();
// 检测关键点和描述符
KeyPoint[] templateKeyPoints, testKeyPoints;
Mat templateDescriptors = new Mat();
Mat testDescriptors = new Mat();
orb.DetectAndCompute(
template,
null,
out templateKeyPoints,
templateDescriptors
);
orb.DetectAndCompute(
test,
null,
out testKeyPoints,
testDescriptors
);
// 特征匹配
var matcher = new BFMatcher(NormTypes.Hamming, crossCheck: true);
DMatch[] matches = matcher.Match(templateDescriptors, testDescriptors);
// 提取匹配点对
Point2f[] templatePoints = matches.Select(m => templateKeyPoints[m.QueryIdx].Pt).ToArray();
Point2f[] testPoints = matches.Select(m => testKeyPoints[m.TrainIdx].Pt).ToArray();
// 计算变换矩阵
Mat homography = Cv2.FindHomography(
InputArray.Create(testPoints),
InputArray.Create(templatePoints),
HomographyMethods.Ransac
);
// 应用变换
Mat alignedTest = new Mat();
Cv2.WarpPerspective(
test,
alignedTest,
homography,
template.Size()
);
return alignedTest;
}
private Mat DetectDifferences(Mat template, Mat test)
{
Mat diff = new Mat();
Mat diffMask = new Mat();
// 计算差异
Cv2.Absdiff(template, test, diff);
// 二值化差异图
Cv2.Threshold(
diff,
diffMask,
30,
255,
ThresholdTypes.Binary
);
// 形态学操作,去除噪点
Mat kernel = Cv2.GetStructuringElement(
MorphShapes.Rect,
new Size(3, 3)
);
Cv2.MorphologyEx(
diffMask,
diffMask,
MorphTypes.Open,
kernel,
iterations: 2
);
return diffMask;
}
private void AnalyzeDefects(Mat diffMask)
{
// 查找轮廓
Point[][] contours;
HierarchyIndex[] hierarchy;
Cv2.FindContours(
diffMask,
out contours,
out hierarchy,
RetrievalModes.External,
ContourApproximationModes.ApproxSimple
);
// 分析每个缺陷区域
foreach (var contour in contours)
{
// 计算缺陷面积
double area = Cv2.ContourArea(contour);
// 获取缺陷边界框
Rect boundingRect = Cv2.BoundingRect(contour);
// 判断缺陷类型
if (area >= 20) // 面积阈值可调整
{
Console.WriteLine($"发现缺陷:");
Console.WriteLine($"位置: X={boundingRect.X}, Y={boundingRect.Y}");
Console.WriteLine($"大小: {area:F2}平方像素");
// 在原图上标记缺陷
Cv2.Rectangle(
testImage,
boundingRect,
Scalar.Red,
2
);
Cv2.PutText(
testImage,
$"Defect: {area:F0}px",
new Point(boundingRect.X, boundingRect.Y - 5),
HersheyFonts.HersheySimplex,
0.5,
Scalar.Red,
1
);
}
}
}
private void ShowResults(Mat diffMask)
{
// 显示结果
using (new Window("Template", templateImage))
using (new Window("Test Image", testImage))
using (new Window("Differences", diffMask))
{
Cv2.WaitKey();
}
}
}
}
代码详解
图像预处理
高斯模糊(Gaussian Blur)
Cv2.GaussianBlur(result, result, new Size(7, 7), 0);
- result
- new Size(7, 7): 高斯核的大小,必须是正奇数(例如:3, 5, 7 等)。越大则模糊效果越明显。
- 0: 标准差 σ。在 X 和 Y 方向上的标准差。如果设为0,函数会根据核大小自动计算。
自适应二值化(Adaptive Thresholding)
Cv2.AdaptiveThreshold(
result,
result,
255,
AdaptiveThresholdTypes.GaussianC,
ThresholdTypes.Binary,
13,
2
);
- result: 输入图像,经过二值化处理的输出图像(可覆盖)。
- 255: 阈值的最大值。当像素值超过该值时,将其赋为最大值。
- AdaptiveThresholdTypes.GaussianC: 自适应阈值的计算方法,这里使用“Gaussian”方法来计算局部阈值。
- ThresholdTypes.Binary: 阈值类型。在这里使用的是简单的二值化(黑和白)。
- 13: 领域大小,即考虑的邻域像素的尺寸(必须为奇数)。
- 2: 从每个计算得到的阈值中减去的常量C,用于调整二值化效果。
图像对齐
使用ORB特征检测和匹配实现图像对齐:
- 检测特征点和描述符
- 特征点匹配
- 计算单应性矩阵
- 透视变换实现图像对齐
差异检测
二值化差异图(Thresholding)
Cv2.Threshold(
diff,
diffMask,
30,
255,
ThresholdTypes.Binary
);
- diff: 输入图像,通常是差异图(例如两张图像之间的差异)。
- diffMask
- 30: 阈值。像素值高于此值将被赋值为最大值(255),低于此值将被赋值为0。
- 255: 阈值的最大值。当像素值超过30时,输出结果将设为255。
- ThresholdTypes.Binary: 阈值类型。在这里使用的是简单的二值化,结果只有两种值(0和255)。
形态学操作(Morphological Operations)
Mat kernel = Cv2.GetStructuringElement(
MorphShapes.Rect,
new Size(3, 3)
);
- Cv2.GetStructuringElement
- MorphShapes.Rect: 指定结构元素的形状为矩形(也可使用其他形状,如椭圆或十字形)。
- new Size(3, 3)
Cv2.MorphologyEx(
diffMask,
diffMask,
MorphTypes.Open,
kernel,
iterations: 2
);
- diffMask
- diffMask
- MorphTypes.Open
- kernel
- iterations: 2: 操作的迭代次数。设置为2意味着将在图像上执行两次开运算。
缺陷分析
分析检测到的缺陷:
- 轮廓检测
- 计算缺陷面积
- 获取缺陷位置
- 在原图上标记缺陷位置
总结
本文详细介绍了使用OpenCvSharp实现PCB板缺陷检测的完整流程。该方法具有以下特点:
- 自动化程度高
- 检测精度可靠
- 代码可扩展性强
- 实现相对简单
通过调整参数和优化算法,可以根据具体应用场景提高检测效果。
阅读原文:原文链接
该文章在 2025/3/3 16:00:11 编辑过