本人模式识别小硕一枚,目前帝都某校研一在读。寒假自己用opencv做了一个对PCB板的好坏的检测,拿出来和大家一起学习讨论,这篇博文也是我在CSDN上发表的第一篇文章,欢迎各路大神指导。
基本思想是通过定焦的工业摄像头,对放置于卡槽中的PCB进行拍摄并取ROI,与标准的PCB图片进行模板匹配,两者二值化后相减并中值滤波,在缺损处用红 {MOD}矩形标出,最后只命名输出缺损PCB图片。
为了给大家更好的演示,我将
程序改为直接读取图片。
程序如下:
(可能有些杂乱,本人水平还需提高)
#include
#include
using namespace cv;
Mat frame, grayimage, StandardPhoto, WaitJudgePhoto, g_resultImage, srcImage;
Mat img,dst,edge,out,mask,out1,out2,out3,out4;
Mat img_result,img_result1,img_result2,Wback,WbackClone,WbackClone1;
int ConditionJudgment;
int g_nMatchMethod = 5;
#define pic01 "AFTER2.jpg"
#define pic02 "PRO5.jpg"
#define WINDOW_NAME1 "【原始图片】"
#define WINDOW_NAME2 "【匹配窗口】"
void Binarization()
{
threshold(grayimage, out, 90, 255, 0);
threshold(StandardPhoto, out1, 90, 255, 0);
threshold(WaitJudgePhoto, out2, 90, 255, 0);
}
void ReadPic()
{
StandardPhoto = imread( pic02, 0 );
WaitJudgePhoto = imread( pic01, 0 );
out3 = imread( pic01, 1 );
mask = imread( pic01, 0 );
Wback = imread("WhiteBack02.jpg",1);
WbackClone = Wback.clone();
WbackClone1 = Wback.clone();
}
void TempMatch()
{
out1.copyTo( srcImage );
int resultImage_cols = out1.cols - out2.cols + 1;
int resultImage_rows = out1.rows - out2.rows + 1;
g_resultImage.create( resultImage_cols, resultImage_rows, CV_32FC1 );
matchTemplate( out1, out2, g_resultImage, g_nMatchMethod );
normalize( g_resultImage, g_resultImage, 0, 1, NORM_MINMAX, -1, Mat() );
double minValue; double maxValue; Point minLocation; Point maxLocation;
Point matchLocation;
minMaxLoc( g_resultImage, &minValue, &maxValue, &minLocation, &maxLocation, Mat() );
if( g_nMatchMethod == CV_TM_SQDIFF || g_nMatchMethod == CV_TM_SQDIFF_NORMED )
{ matchLocation = minLocation; }
else
{ matchLocation = maxLocation; }
rectangle( out1, matchLocation, Point( matchLocation.x + out2.cols , matchLocation.y + out2.rows ), Scalar(0,0,255), 2, 8, 0 );
rectangle( g_resultImage, matchLocation, Point( matchLocation.x + out2.cols , matchLocation.y + out2.rows ), Scalar(0,0,255), 2, 8, 0 );
Mat imageROI = out1(Rect(matchLocation.x,matchLocation.y,out2.cols,out2.rows));
out2.copyTo(imageROI,mask);
Mat imageROI1 = WbackClone(Rect(matchLocation.x,matchLocation.y,out3.cols,out3.rows));
out3.copyTo(imageROI1,mask);
cvtColor(WbackClone,out4,CV_BGR2GRAY);
threshold(out4, WbackClone, 90, 255, 0);
Mat img2 = imread(pic01);
Mat imageROI2 = WbackClone1(Rect(matchLocation.x,matchLocation.y,out3.cols,out3.rows));
out3.copyTo(imageROI2,mask);
imshow("【彩 {MOD}ROI位置待判断图】",WbackClone1);
}
void DefectJudgment()
{
int rowNumber = img_result.rows;
int colcolNumber = img_result.cols;
int colNumber = img_result.cols*img_result.channels();
ConditionJudgment=1;
for(int i = 0; i < rowNumber && ConditionJudgment; i++)
{
uchar* data = img_result.ptr(i);
for(int j = 0;j < colNumber;j++)
{
if(data[j]==255)
{
imwrite("有问题的PCB.jpg",WbackClone1);
ConditionJudgment=0;
break;
}
}
}
}
int main()
{
namedWindow("【滤波前二值化效果】", 2);
namedWindow("【滤波后缺损二值化显示】", 2);
namedWindow("【对拍摄图缺损位置进行标注】", 2);
namedWindow("【彩 {MOD}ROI位置待判断图】", 2);
ReadPic();
Binarization();
TempMatch();
subtract(srcImage,WbackClone,img_result1);
subtract(WbackClone,srcImage,img_result2);
medianBlur(img_result1,img_result,3);
medianBlur(img_result2,img_result2,3);
add(img_result,img_result2,img_result);
Mat ele = getStructuringElement(MORPH_RECT, Size(5,5));
dilate(img_result,img_result,ele);
Mat threshold_output;
vector<vector> contours;
vector hierarchy;
threshold( img_result, threshold_output, 50, 255, THRESH_BINARY );
findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
vector<vector > contours_poly( contours.size() );
vector boundRect( contours.size() );
for( unsigned int i = 0; i < contours.size(); i++ )
{
approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
boundRect[i] = boundingRect( Mat(contours_poly[i]) );
}
for( int unsigned i = 0; i0, 0, 255 );
rectangle( WbackClone1, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 );
}
DefectJudgment();
imshow( "【滤波前二值化效果】", img_result1 );
imshow( "【滤波后缺损二值化显示】", img_result );
imshow( "【对拍摄图缺损位置进行标注】", WbackClone1 );
waitKey(0);
}
效果如下图所示:
【完好无损的PCB】
【有缺损的PCB】(焊盘缺失或缺损)
【处理后未滤波的图片】
【滤波后图像】
【缺损判断标记】(图上红 {MOD}矩形框)
程序中Wback是读入的一张纯白 {MOD}底板图片,这个底板分辨率和标准模板图片一致,为了在模板匹配后相减时防止检测图片因拍摄或放PCB板入卡槽时,位置的改变而处理的。
还有太多的东西需要学习,欢迎大神前辈们指教。