PCB板缺陷檢測是工業(yè)視覺檢測中的重要應(yīng)用。本文將詳細介紹如何使用OpenCvSharp實現(xiàn)PCB板的缺陷檢測,包括缺陷、斷路、短路等問題的識別。
環(huán)境準備
// NuGet包引用
// Install-Package OpenCvSharp4
// Install-Package OpenCvSharp4.runtime.win
using OpenCvSharp;
using System;
完整代碼實現(xiàn)
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. 顯示結(jié)果
ShowResults(diffMask);
}
private Mat PreprocessImage(Mat input)
{
Mat result = new Mat();
// 轉(zhuǎn)換為灰度圖
Cv2.CvtColor(input, result, ColorConversionCodes.BGR2GRAY);
// 高斯模糊去噪
Cv2.GaussianBlur(result, result, new Size(7, 7), 0);
// 自適應(yīng)二值化
Cv2.AdaptiveThreshold(
result,
result,
255,
AdaptiveThresholdTypes.GaussianC,
ThresholdTypes.Binary,
13,
2
);
return result;
}
private Mat AlignImages(Mat template, Mat test)
{
// 特征點檢測和匹配
var orb = ORB.Create();
// 檢測關(guān)鍵點和描述符
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
);
// 應(yīng)用變換
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
);
// 形態(tài)學操作,去除噪點
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
);
// 分析每個缺陷區(qū)域
foreach (var contour in contours)
{
// 計算缺陷面積
double area = Cv2.ContourArea(contour);
// 獲取缺陷邊界框
Rect boundingRect = Cv2.BoundingRect(contour);
// 判斷缺陷類型
if (area >= 20) // 面積閾值可調(diào)整
{
Console.WriteLine($"發(fā)現(xiàn)缺陷:");
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)
{
// 顯示結(jié)果
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: 輸入圖像,經(jīng)過模糊處理的輸出圖像(可覆蓋)。
- new Size(7, 7): 高斯核的大小,必須是正奇數(shù)(例如:3, 5, 7 等)。越大則模糊效果越明顯。
- 0: 標準差 σ。在 X 和 Y 方向上的標準差。如果設(shè)為0,函數(shù)會根據(jù)核大小自動計算。
自適應(yīng)二值化(Adaptive Thresholding)
Cv2.AdaptiveThreshold(
result,
result,
255,
AdaptiveThresholdTypes.GaussianC,
ThresholdTypes.Binary,
13,
2
);
- result: 輸入圖像,經(jīng)過二值化處理的輸出圖像(可覆蓋)。
- 255: 閾值的最大值。當像素值超過該值時,將其賦為最大值。
- AdaptiveThresholdTypes.GaussianC: 自適應(yīng)閾值的計算方法,這里使用“Gaussian”方法來計算局部閾值。
- ThresholdTypes.Binary: 閾值類型。在這里使用的是簡單的二值化(黑和白)。
- 13: 領(lǐng)域大小,即考慮的鄰域像素的尺寸(必須為奇數(shù))。
- 2: 從每個計算得到的閾值中減去的常量C,用于調(diào)整二值化效果。
圖像對齊
使用ORB特征檢測和匹配實現(xiàn)圖像對齊:
- 檢測特征點和描述符
- 特征點匹配
- 計算單應(yīng)性矩陣
- 透視變換實現(xiàn)圖像對齊
差異檢測
二值化差異圖(Thresholding)
Cv2.Threshold(
diff,
diffMask,
30,
255,
ThresholdTypes.Binary
);
- diff: 輸入圖像,通常是差異圖(例如兩張圖像之間的差異)。
- diffMask
- 30: 閾值。像素值高于此值將被賦值為最大值(255),低于此值將被賦值為0。
- 255: 閾值的最大值。當像素值超過30時,輸出結(jié)果將設(shè)為255。
- ThresholdTypes.Binary: 閾值類型。在這里使用的是簡單的二值化,結(jié)果只有兩種值(0和255)。
形態(tài)學操作(Morphological Operations)
Mat kernel = Cv2.GetStructuringElement(
MorphShapes.Rect,
new Size(3, 3)
);
- Cv2.GetStructuringElement: 用于創(chuàng)建結(jié)構(gòu)元素,用于形態(tài)學處理。
- MorphShapes.Rect: 指定結(jié)構(gòu)元素的形狀為矩形(也可使用其他形狀,如橢圓或十字形)。
- new Size(3, 3): 結(jié)構(gòu)元素的大小,這里為3x3像素。
Cv2.MorphologyEx(
diffMask,
diffMask,
MorphTypes.Open,
kernel,
iterations: 2
);
- diffMask: 輸入圖像,通常是經(jīng)過二值化處理的圖像。
- diffMask: 輸出圖像,表示形態(tài)學處理后的結(jié)果(可覆蓋)。
- MorphTypes.Open: 形態(tài)學運算類型為開運算(去除小物體的噪點)。
- kernel: 用于形態(tài)學操作的結(jié)構(gòu)元素。
- iterations: 2: 操作的迭代次數(shù)。設(shè)置為2意味著將在圖像上執(zhí)行兩次開運算。
缺陷分析
分析檢測到的缺陷:
- 輪廓檢測
- 計算缺陷面積
- 獲取缺陷位置
- 在原圖上標記缺陷位置
總結(jié)
本文詳細介紹了使用OpenCvSharp實現(xiàn)PCB板缺陷檢測的完整流程。該方法具有以下特點:
- 自動化程度高
- 檢測精度可靠
- 代碼可擴展性強
- 實現(xiàn)相對簡單
通過調(diào)整參數(shù)和優(yōu)化算法,可以根據(jù)具體應(yīng)用場景提高檢測效果。
閱讀原文:原文鏈接
該文章在 2025/3/3 16:00:11 編輯過