#include <iostream>
#include "badDetect.h"
using namespace std;
//測試的主函數
int main()
{
PreParams params;//定義預設置參數的結構體
Mat img = imread("D:\\測試結果圖片\\1.bmp",0);
Mat img1 = imread("D:\\測試結果圖片\\2.bmp",0);
/*Mat img = imread("樣品圖4\\4.bmp",0);
Mat img1 = imread("兩面打光圖\\壓印\\2.bmp",0);*/
char* imgData = (char*)img.data;
char* imgData1 = (char*)img1.data;
int height = img.rows;
int width = img.cols;
int result[4][10] = {0};
int detectError[4] = {0};
//進行參數設置
params.rubDetectParams.holeNum = 1; //樣本穿洞數
params.memBwArea = 250; //膜內黑白點與膜皺面積分界值
params.rubDetectParams.memOffset = 14; //膜最大偏移值,偏心檢測
params.rubDetectParams.memUdOffset = 26; //膜上下偏心閾值
params.memPixelDif = 17; //膜內最大像素差,黑白點、膜皺檢測
params.rubDetectParams.memRubDist = 245; //膜與膠的左/右標準距離
params.sampleNum = 4; //一張圖中的樣本數
params.slikThreold = 8; //毛絲閾值
params.rubDetectParams.rubPixelArea = 70; //膠上最小髒點面積
params.rubDetectParams.rubPixelDif = 50; //膠上髒點最小像素差
params.minBwArea = 50; //膜內黑白點最小面積
params.hole = 2; //缺孔檢測
params.levcover = 16; //左右移位檢測閾值
params.udLeave = 16; //上下移位閾值
params.bwDist = 7; //黑點離邊緣距離
params.rubDetectParams.rubThreold = 80; //膠上髒點閾值
params.fpArea = 350;
double t = (double)getTickCount();
badDetect(imgData,imgData1,height,width,params,result,detectError); //進行檢測
t = ((double)getTickCount() - t)/getTickFrequency();
cout<<"耗時:"<<t<<endl;
for(int i = 0;i<4;i++)
{
cout<<"錯誤碼:"<<detectError[i]<<endl;
cout<<"result"<<i+1<<": ";
for(int j = 0;j<10;j++)
{
cout<<result[i][j]<<" ";
}
cout<<"\n";
}
namedWindow("change",0);
imshow("change",img);
waitKey(0);
namedWindow("change1",0);
imshow("change1",img1);
waitKey(0);
cin.get();
return 0;
}
//總接口函數
void badDetect(char* img,char* img1,int imgWidth,int imgHeight,const PreParams params,int result[][10],int detectError[])
{
vector<Mat> roiImgs;
vector<Mat> MG;
vector<Mat> dstImg;
RubDetectParams rubParams;
dst_width = imgWidth;
dst_height = imgHeight;
int roi_num = params.sampleNum;//提取的感興趣區域數量
int minMemBwArea = params.memBwArea;//膜內允許的像素偏差面積
int slikThreold = params.slikThreold;//毛絲離輪廓距離,用於檢測毛絲
int pianxin = params.rubDetectParams.memOffset;//偏心檢測
int memRubDist = params.rubDetectParams.memRubDist;//膜離左右的標準距離,偏心檢測
int memOffset = params.memPixelDif;//膜內允許的像素偏差
int minBwArea = params.minBwArea; // 膜內黑白點最小面積
int hole = params.hole; //缺孔檢測數據
int levcover = params.levcover; //移位檢測閾值
int udLeave = params.udLeave;
int sampleNum = params.sampleNum; //移位檢測閾值
int memUdOffset = params.rubDetectParams.memUdOffset;
int bwdist = params.bwDist;
int rubThreold = params.rubDetectParams.rubThreold;
int fpArea = params.fpArea;
rubParams.holeNum = params.rubDetectParams.holeNum;
rubParams.memOffset = params.rubDetectParams.memOffset;
rubParams.memRubDist = params.rubDetectParams.memRubDist;
rubParams.minSampleArea = params.rubDetectParams.minSampleArea;
rubParams.rubPixelArea = params.rubDetectParams.rubPixelArea;
rubParams.rubPixelDif = params.rubDetectParams.rubPixelDif;
rubParams.rubThreold = params.rubDetectParams.rubThreold;
Mat pSrcImg(Size(imgHeight,imgWidth),CV_8UC1,img);
Mat pSrcImg1(Size(imgHeight,imgWidth),CV_8UC1,img1);
Mat srcImg,srcImg1;
pSrcImg.copyTo(srcImg);
pSrcImg1.copyTo(srcImg1);
if(!(srcImg.data && srcImg1.data))
{
for(int i = 0;i < 4;i++)
{
for(int j = 0;j<10;j++)
{
result[i][j] = -1;//兩張圖中任意一張爲空
}
}
for(int i = 0;i < 4;i++)
{
detectError[i] = -1;
}
return;
}
int flag = getRoiImg(srcImg,sampleNum,dstImg,result);
if(flag == -1)
{
for(int i = 0;i < 4;i++)
{
detectError[i] = -2;
}
return;
}
//showImg(dstImg);
Mat roi1 = srcImg(Rect(0,0,srcImg.cols/2,srcImg.rows/2));
Mat roi2 = srcImg(Rect(srcImg.cols/2,0,srcImg.cols/2,srcImg.rows/2));
Mat roi3 = srcImg(Rect(0,srcImg.rows/2,srcImg.cols/2,srcImg.rows/2));
Mat roi4 = srcImg(Rect(srcImg.cols/2,srcImg.rows/2,srcImg.cols/2,srcImg.rows/2));
Mat mianguang1 = srcImg1(Rect(0,0,srcImg.cols/2,srcImg.rows/2));
Mat mianguang2 = srcImg1(Rect(srcImg.cols/2,0,srcImg.cols/2,srcImg.rows/2));
Mat mianguang3 = srcImg1(Rect(0,srcImg.rows/2,srcImg.cols/2,srcImg.rows/2));
Mat mianguang4 = srcImg1(Rect(srcImg.cols/2,srcImg.rows/2,srcImg.cols/2,srcImg.rows/2));
roiImgs.push_back(roi1);
roiImgs.push_back(roi2);
roiImgs.push_back(roi3);
roiImgs.push_back(roi4);
MG.push_back(mianguang1);
MG.push_back(mianguang2);
MG.push_back(mianguang3);
MG.push_back(mianguang4);
MemDetectResult memdr;//膜內檢測結果傳回
vector<vector<Point>> badspots;//膠上壞點傳回
int leavCenter[3] = {0};//偏心結果傳回
vector<vector<Point2f>> roRect;
Point circlepoint[4] = {(0,0),(0,0),(0,0),(0,0)};//用於檢測偏心的圓心
vector<vector<Point>> T(4);
circleEdges = T;
//#pragma omp parallel for
for(int i = 0;i<roiImgs.size();i++)//循環檢測每一個樣本
{
deError[i] = 0;
int memres = centerMemDetect(roiImgs[i],i,&memdr,circlepoint,memOffset,minMemBwArea,slikThreold,minBwArea,result,bwdist,fpArea);//開始中心膜檢測
if(result[i][0] == -1 || result[i][0] == -2 || result[i][0] == -3 || memres == -1)
{
detectError[i] = deError[i];
continue;
}
int locres = localDetect(roiImgs[i],result,hole,i,levcover,udLeave,circlepoint);
if(locres < 0)
{
detectError[i] = deError[i];
continue;
}
int bads = badSpot(MG[i],badspots,circlepoint,leavCenter,rubParams,i,roRect,result);//開始外輪廓檢
if(bads < 0)
{
detectError[i] = deError[i];
continue;
}
int lackm = lackMaterial(result,dstImg[i],i);
if(lackm < 0)
{
detectError[i] = deError[i];
continue;
}
int centeroff = centerOffset(circlepoint[i],memRubDist,pianxin,memUdOffset,result,i);
if(centeroff < 0)
{
detectError[i] = deError[i];
continue;
}
detectError[i] = deError[i];
}
paintProcessedImg(img,img1,memdr,badspots,leavCenter,result,roRect);//畫出檢測結果
localEdges.clear();
circleEdges.clear();
/*mask_right.release();
mask_left.release();*/
//imwrite("D:\\bc1.bmp",pSrcImg);
//imwrite("D:\\bc2.bmp",pSrcImg1);
//namedWindow("change",0);
//imshow("change",srcImg);
//waitKey(0);
//namedWindow("change1",0);
//imshow("change1",srcImg1);
//waitKey(0);
/*char str1[10]={};
char str2[10] = {};
char str3[10] = {};
char str4[50] = {};
char str5[10] = {};
itoa(rubParams.holeNum,str1,10);
itoa(rubParams.memOffset,str2,10);
itoa(rubParams.memRubDist,str3,10);
itoa(rubParams.minSampleArea,str4,10);
itoa(rubParams.rubPixelArea,str5,10);
putText(srcImg1,str1,Point(100,100),CV_FONT_ITALIC,1,Scalar(0,0,0));
putText(srcImg1,str2,Point(150,100),CV_FONT_ITALIC,1,Scalar(0,0,0));
putText(srcImg1,str3,Point(200,100),CV_FONT_ITALIC,1,Scalar(0,0,0));
putText(srcImg1,str4,Point(250,100),CV_FONT_ITALIC,1,Scalar(0,0,0));
putText(srcImg1,str5,Point(300,100),CV_FONT_ITALIC,1,Scalar(0,0,0));*/
}
//膜中心檢測函數
//memResult:結果存放結構體
//minMenBwArea:最小黑點白點面積
int centerMemDetect(const Mat srcImg,int imgIndex, MemDetectResult* memResult,Point circlepoint[],int memOffset,int minMemBwArea,int slikThreold,int memBwArea,int result[][10],int bwdist,int fpArea)
{
int addX = 0;
int addY = 0;
if(imgIndex == 1)
{
addX = dst_height/2;
}
if(imgIndex == 2)
{
addY = dst_width/2;
}
if(imgIndex == 3)
{
addX = dst_height/2;
addY = dst_width/2;
}
Mat img,gray,bw;
srcImg.copyTo(img);
if(img.channels() == 3)
cvtColor(srcImg,gray,CV_RGB2GRAY);
else
gray = img;
double rubPixel_level[256] = {0};
double rubAvePixel = 0.0;
double rubPixelNum = 0.0;
double rubPixelSum = 0.0;
for(int i = 0;i<gray.rows;i++)
{
uchar* data = gray.ptr<uchar>(i);
for(int j = 0;j<gray.cols;j++)
{
int temp = data[j];
rubPixel_level[temp]++;
}
}
for(int i = 0;i<30;i++)
{
if(rubPixel_level[i]>1000)
{
rubPixelNum = rubPixelNum + rubPixel_level[i]*i;
rubPixelSum = rubPixelSum + rubPixel_level[i];
}
}
rubAvePixel = rubPixelNum/rubPixelSum;
int memThreold = 50; //提取中心膜時二值化閾值
int threold_low = rubAvePixel+7; //低閾值與高閾值區分復
int slikthreold = rubAvePixel+11;
int threold_high = threold_low+15; //低閾值與高閾值區分復偏
//--------------------提取出中心膜-----------------------------//
threshold(gray,bw,memThreold,255,CV_THRESH_BINARY);
GaussianBlur(bw,bw,Size(5,5),2,2);
/*imshow("houfu",bw);
waitKey(0);*/
Mat bwcon;
bw.copyTo(bwcon);
vector<vector<Point>> cirConCount;
vector<Vec4i> cirHierarchy;
findContours(bwcon,cirConCount,cirHierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE);
if(cirConCount.size()>20)
{
for(int i = 0;i<10;i++)
{
result[imgIndex][i] = -3;//沒有檢測到圓,無樣本,返回-1
}
deError[imgIndex] = 1;
return -1;
}
vector<Vec3f> hough_circles;
//霍夫圓變換粗定位圓,累加器爲原圖像2/3,最小圓心距離5,canny高閾值,圓檢測閾值60,越小越能檢測到不規則的圓
HoughCircles(bw,hough_circles,CV_HOUGH_GRADIENT,1.5,5,200,100,50,0);
if(hough_circles.empty())
{
for(int i = 0;i<10;i++)
{
result[imgIndex][i] = -4;//沒有檢測到圓,無樣本,返回-1
}
deError[imgIndex] = 2;
return -1;
}
for(int i = 0;i<hough_circles.size();i++)
{
Point center((int)(hough_circles[i][0]),(int)(hough_circles[i][1]));
int radius = (int)(hough_circles[i][2]);
}
int maxCircle = -1;//找出合適大小的圓
for(int i = 0;i<hough_circles.size();i++)
{
if(hough_circles[i][2] < 140 && hough_circles[i][2]>100)
{
maxCircle = i;
}
}
int R;//霍夫變換產生的圓半徑
Mat roi,roiblur,roi_bw_low,roi_bw_high,edges;
double roi_centerX,roi_centerY,roi_radius;//最小二乘法擬合出的圓半徑和圓心
vector<Point> edges_point;
vector<vector<Point>> edges_contour;
vector<Vec4i> edges_hieratchy;
Point center;
int addroi = 37;
if(maxCircle != -1)
{
center.x = (int)(hough_circles[maxCircle][0]);
center.y = (int)(hough_circles[maxCircle][1]);
R = (int)(hough_circles[maxCircle][2]);
int x = center.x-R-addroi;
int y = center.y-R-addroi;
int width = 2*(R+addroi);
if(x<0 || y<0 || (x+width)>img.cols || (y+width)>img.rows)
{
for(int i = 0;i<10;i++)
{
result[imgIndex][i] = -5;//沒有檢測到圓,無樣本,返回-1
}
deError[imgIndex] = 3;
return -1;
}
Rect roi_rect = Rect(x,y,width,width);
roi = gray(roi_rect);
medianBlur(roi,roiblur,3);
medianBlur(roi,roi,3);
threshold(roi,roi_bw_low,slikthreold,255,CV_THRESH_BINARY);
Canny(roi_bw_low,edges,100,200);
findContours(edges,edges_contour,edges_hieratchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_NONE);
if(edges_contour.size() == 0)
{
for(int i = 0;i<10;i++)
{
result[imgIndex][i] = -6;//沒有檢測到圓,無樣本,返回-1
}
deError[imgIndex] = 4;
return -1;
}
contourSort(edges_contour);
edges_point = edges_contour[0];
}
else
{
for(int i = 0;i<10;i++)
{
result[imgIndex][i] = -7;//檢測到圓大小不合適,無樣本,返回-1
}
deError[imgIndex] = 5;
return -1;
}
//最小二乘法計算圓心和半徑
if(edges.data)
{
circleLeastFit(edges_point,roi_centerX,roi_centerY,roi_radius);
circle(roi,Point(roi_centerX,roi_centerY),roi_radius,Scalar(255,255,255),1,8,0);
circlepoint[imgIndex].x = roi_centerX + center.x - R -addroi;//精確圓心傳遞到後面檢測需要的方法
circlepoint[imgIndex].y = roi_centerY + center.y - R -addroi;
}
imshow("擬合圓",roi);
waitKey(0);
int pixel_level[256] = {0};
double avePixel = 0.0;
double pixelNum = 0.0;
double pixelSum = 0.0;
for(int i = 0;i<roi.rows;++i)
{
uchar* data = roi.ptr<uchar>(i);
for(int j = 0;j<roi.cols;++j)
{
int temp = data[j];
pixel_level[temp]++;
}
}
for(int i = 255;i>60;i--)
{
if(pixel_level[i]>100)
{
pixelSum = pixelSum + pixel_level[i]*i;
pixelNum = pixelNum + pixel_level[i];
}
}
if(pixelNum < 35000)
{
for(int i = 0;i<10;i++)
{
result[imgIndex][i] = -8;//透氣膜移位,返回-1
}
deError[imgIndex] = 6;
return -1;
}
avePixel = pixelSum/pixelNum; //背景像素值
if(avePixel > 240)
{
for(int i = 0;i<10;i++)
{
result[imgIndex][i] = -9;//無透氣膜,返回-3
}
deError[imgIndex] = 7;
return -1;
}
//-------------毛絲檢測------------//
Mat slikbw,slikAdp,slikResult,slik_edges;
threshold(roi,slikbw,50,255,CV_THRESH_BINARY_INV);
adaptiveThreshold(roi,slikAdp,255,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY_INV,7,15);
//threshold(roi,slikbw,avePixel-memOffset,255,CV_THRESH_BINARY);
addWeighted(slikbw,1.0,slikAdp,1.0,0,slikResult);//統計兩次的結果
/*imshow("maosi",slikAdp);
waitKey(0);*/
/*imshow("guding",slikbw);
waitKey(0);
imshow("result",slikResult);
waitKey(0);*/
Canny(slikResult,slik_edges,100,200);
vector<vector<Point>> slik_contour;
vector<Vec4i> slik_hieratchy;
findContours(slik_edges,slik_contour,slik_hieratchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_NONE);
contourSort(slik_contour);
/*imshow("bianyuan",slik_edges);
waitKey(0);*/
for(int i = 0;i<slik_contour.size();i++)
{
if(slik_contour[i].size()>10)
{
for(int j = 0;j<slik_contour[i].size();j++)
{
double x2 = (slik_contour[i][j].x-roi_centerX)*(slik_contour[i][j].x-roi_centerX);
double y2 = (slik_contour[i][j].y-roi_centerY)*(slik_contour[i][j].y-roi_centerY);
double dist = roi_radius - sqrt(x2+y2);
if(dist>slikThreold && dist<slikThreold+10)
{
int tempX = slik_contour[i][j].x + center.x - R -addroi+addX;
int tempY = slik_contour[i][j].y + center.y - R -addroi+addY;
memResult->slik.push_back(Point(tempX,tempY));
result[imgIndex][0] = 1;
}
}
}
}
if(!circleEdges[imgIndex].empty())
{
circleEdges[imgIndex].clear();
}
for(int i = 0;i<edges_point.size();i++)
{
Point temp(edges_point[i].x + center.x - R -addroi,edges_point[i].y + center.y - R -addroi);
circleEdges[imgIndex].push_back(temp);
}
//-------------------雙閾值找復偏---------------------//
Mat roi_rub_low;
threshold(roiblur,roi_rub_low,threold_low,255,CV_THRESH_BINARY);
threshold(roiblur,roi_bw_high,threold_high,255,CV_THRESH_BINARY);
Mat rubArea = Mat::zeros(roi_bw_low.size(),CV_8UC1);
Mat rub_edges,rubConImg;
absdiff(roi_bw_high,roi_bw_low,rubArea);
//rubArea = roi_bw_high - roi_bw_low;
/*imshow("復偏",rubArea);
waitKey(0);*/
/*for(int i = 0;i<roi_rub_low.rows;i++)
{
for(int j = 0;j<roi_rub_low.cols;j++)
{
if(roi_rub_low.at<uchar>(i,j) != roi_bw_high.at<uchar>(i,j))
{
rubArea.at<uchar>(i,j) = 255;
}
}
}
imshow("復偏",rubArea);
waitKey(0);*/
dilate(rubArea,rubArea,getStructuringElement(MORPH_ELLIPSE,Size(3,3),Point(1,1)));
erode(rubArea,rubArea,getStructuringElement(MORPH_ELLIPSE,Size(5,5),Point(2,2)));//腐蝕,允許小偏差存在
/*imshow("復偏",rubArea);
waitKey(0);*/
//將復偏檢測結果存放到結果結構體
vector<vector<Point>> rub_contours;
vector<Point> maxContours;
vector<Vec4i> rub_hierarchy;
int maxIndex = 0;
rubConImg = Mat::zeros(rubArea.size(),CV_8UC1);
findContours(rubArea,rub_contours,rub_hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_NONE);
for(int i = 0;i<rub_contours.size();i++)
{
if(rub_contours[i].size()>rub_contours[maxIndex].size())
maxIndex = i;
}
if(!rub_contours.empty())
{
maxContours = rub_contours[maxIndex];
double dist = sqrt((double)(maxContours[0].x-roi_centerX)*(maxContours[0].x-roi_centerX)+(maxContours[0].y-roi_centerY)*(maxContours[0].y-roi_centerY));
if(maxContours.size()>fpArea && dist<(roi_radius+20))
{
#pragma omp parallel for
for(int i = 0;i<maxContours.size();++i)//找到復偏
{
maxContours[i].x = maxContours[i].x + center.x - R -addroi+addX;
maxContours[i].y = maxContours[i].y + center.y - R -addroi+addY;
}
memResult->drub.push_back(maxContours);//檢出復偏,賦值給結果結構體
result[imgIndex][1] = 1;
}
}
//cvtColor(roi,roiRGB,CV_GRAY2BGR);
//circle(roi,Point(cvRound(roi_centerX),cvRound(roi_centerY)),R,Scalar(155,50,255),1,8,0);
//----------------------膜內黑白點、膜皺檢測---------------------//
//黑點白點判斷依據:與背景的對比度、大小、與圓心的距離
//膜皺判斷依據:與背景的對比度、大小、與圓心的距離
Mat roi_threold_bk,roi_threold_wt,roi_threold_result;
vector<vector<Point>> spot_contours;
vector<Vec4i> spot_hierarchy;
medianBlur(roi,roi,3);
threshold(roi,roi_threold_wt,avePixel+15,255,THRESH_BINARY);
threshold(roi,roi_threold_bk,avePixel-15,255,THRESH_BINARY_INV);
for(int i = 0;i<roi.rows;i++)
{
for(int j = 0;j<roi.cols;j++)
{
double x2 = (j-roi_centerX)*(j-roi_centerX);
double y2 = (i-roi_centerY)*(i-roi_centerY);
double dist = sqrt(x2+y2)-roi_radius;
if(dist>-25)
{
roi_threold_wt.at<uchar>(i,j) = 0;
roi_threold_bk.at<uchar>(i,j) = 0;
}
}
}
//imshow("kaishihou1",roi_threold_wt);
//waitKey(0);
//imshow("kaishihou2",roi_threold_bk);
//waitKey(0);
addWeighted(roi_threold_bk,1.0,roi_threold_wt,1.0,0,roi_threold_result);//統計兩次的結果
//adaptiveThreshold(roi,roiblur,255,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY_INV,11,5);
/*adaptiveThreshold(roi,roiblur,255,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY_INV,15,10);
erode(roiblur,roiblur,getStructuringElement(MORPH_RECT,Size(3,3)));
dilate(roiblur,roiblur,getStructuringElement(MORPH_RECT,Size(3,3)));*/
/*for(int i = 0;i<roiblur.rows;i++)
{
for(int j = 0;j<roiblur.cols;j++)
{
double dist = sqrt((double)(i-roi_centerX)*(i-roi_centerX)+(j-roi_centerY)*(j-roi_centerY))-roi_radius;
if(dist > -30)
{
roiblur.at<char>(i,j) = 0;
}
}
}*/
/*imshow("tu",roiblur);
waitKey(0);*/
//addWeighted(roiblur,1.0,roi_threold_result1,1.0,0,roi_threold_result);//統計兩次的結果
//imshow("tu",roi_threold_result);
//waitKey(0);
Mat roi_contours = Mat::zeros(roi_threold_result.size(),CV_8UC1);//初始化輪廓圖
Mat old_roi_threold_result;
roi_threold_result.copyTo(old_roi_threold_result);
findContours(roi_threold_result,spot_contours,spot_hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_NONE);
contourSort(spot_contours);
/*for(int i = 0;i<spot_contours[6].size();i++)
{
circle(roi_contours,spot_contours[6][i],0,Scalar(255,255,255),-1);
}*/
/*imshow("roi",roi_contours);
waitKey(0);*/
for(int i = 0;i<spot_contours.size();i++)
{
if(spot_contours[i].size()>500)
continue;
int contourPixel_local = spot_contours[i].size()/2;
Point contourPixel = spot_contours[i][contourPixel_local];
double x2 = (contourPixel.x-roi_centerX)*(contourPixel.x-roi_centerX);
double y2 = (contourPixel.y-roi_centerY)*(contourPixel.y-roi_centerY);
double dist = sqrt(x2+y2);
if(dist < (roi_radius-bwdist))//距離判斷
{
int localPixelAve = 0;
int localPixelCount = 0;
int localPixelSum = 0;
int localContrast = 0;
Rect contourRect;
contourRect = boundingRect(spot_contours[i]);
for(int j = contourRect.x;j<contourRect.x+contourRect.width;j++)
{
//uchar* data = roi.ptr<uchar>(j);
for(int k = contourRect.y;k<contourRect.y+contourRect.height;k++)
{
double iscontour = pointPolygonTest(spot_contours[i],Point(j,k),false);
if(iscontour == 1 || iscontour == 0)
{
localPixelCount++;
localPixelSum = localPixelSum + roi.at<uchar>(k,j);
}
}
}
if(localPixelCount!=0)//排除除0異常
{
localPixelAve = (int)(localPixelSum/localPixelCount);
}
localContrast = abs(localPixelAve - avePixel);
if(localContrast > memOffset && localPixelCount <= minMemBwArea &&localPixelCount > memBwArea)//背景對比度+面積判斷
{
vector<Point> bwContours = spot_contours[i];
for(int m = 0;m<spot_contours[i].size();m++)//找到黑點或白點
{
bwContours[m].x = bwContours[m].x + center.x - R -addroi+addX;
bwContours[m].y = bwContours[m].y + center.y - R -addroi+addY;
}
memResult->bwspot.push_back(bwContours);//檢出黑白點,賦值給結果結構體
result[imgIndex][2] = 1;
}
if(localContrast > memOffset && localPixelCount > minMemBwArea)//背景對比度+面積判斷
{
vector<Point> memContours = spot_contours[i];
for(int m = 0;m<spot_contours[i].size();m++)//找到膜皺
{
memContours[m].x = memContours[m].x + center.x - R -addroi+addX;
memContours[m].y = memContours[m].y + center.y - R -addroi+addY;
}
memResult->crease.push_back(memContours);//檢出膜皺,賦值給結果結構體
result[imgIndex][3] = 1;
}
}
}
return 0;
}
//缺孔、移位
int localDetect(const Mat srcImg,int result[][10],int hole,int imgIndex,int levcover,int udLeave,Point circlePoint[])
{
Mat img,gray,bw1,bw2;
img = srcImg;
int xP = circlePoint[imgIndex].x;
int yP = circlePoint[imgIndex].y;
Point bigCircle = circlePoint[imgIndex];
if(localEdges[imgIndex].empty() || circleEdges[imgIndex].empty() || bigCircle.x == 0)
{
for(int i = 0;i<10;i++)
{
result[imgIndex][i] = -10;
}
deError[imgIndex] = 8;
return -1;
}
if(img.channels() == 3)
cvtColor(srcImg,gray,CV_RGB2GRAY);
else
gray = img;
GaussianBlur(gray,gray,Size(5,5),2,2);
int pixel_level = 0;
//int pixel_level[256] = {0};//256個水平
//double threold_kong = 0.0;
//double pixelNum = 0.0;
//double pixelSum = 0.0;
for(int i = 0;i<gray.rows;i++)
{
uchar* data = gray.ptr<uchar>(i);
for(int j = 0;j<gray.cols;j++)
{
int temp = data[j];
if(temp > 220)
pixel_level++;//相應的像素水平加1
}
}
if(pixel_level<800000)
{
for(int i = 0;i<10;i++)
{
result[imgIndex][i] = -11;
}
deError[imgIndex] = 9;
return -2;
}
//for(int i = 245;i>180;i--)
//{
// if(pixel_level[i]>100)
// {
// pixelSum = pixelSum + pixel_level[i]*i;
// pixelNum = pixelNum + pixel_level[i];
// }
//}
//threold_kong = pixelSum/pixelNum-20; //背景像素值
threshold(gray,bw1,220,255,CV_THRESH_BINARY);
//threshold(gray,bw2,100,255,CV_THRESH_BINARY);
GaussianBlur(bw1,bw1,Size(5,5),2,2);
//GaussianBlur(bw2,bw2,Size(5,5),2,2);
Mat bw1con;
bw1.copyTo(bw1con);
vector<vector<Point>> bw1ConCount;
vector<Vec4i> bw1Hierarchy;
findContours(bw1con,bw1ConCount,bw1Hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE);
if(bw1ConCount.size()>500)
{
for(int i = 0;i<10;i++)
{
result[imgIndex][i] = -12;//沒有檢測到圓,無樣本,返回-1
}
deError[imgIndex] = 10;
return -1;
}
vector<Vec3f> hough_circles;
//vector<Vec3f> hough_circles1;
/*namedWindow("二值圖1",0);
imshow("二值圖1",bw1);
waitKey(0);*/
/*namedWindow("二值圖",0);
imshow("二值圖",bw2);
waitKey(0);*/
//霍夫圓變換粗定位圓,累加器爲原圖像2/3,最小圓心距離5,canny高閾值,圓檢測閾值60,越小越能檢測到不規則的圓
HoughCircles(bw1,hough_circles,CV_HOUGH_GRADIENT,1.5,80,200,90,0,0);
//HoughCircles(bw2,hough_circles1,CV_HOUGH_GRADIENT,1.5,5,200,110,0,0);
int circleNum = 0;
Point smaCircle(0,0);
if(!hough_circles.empty())
{
smaCircle.x = hough_circles[0][0];
smaCircle.y = hough_circles[0][1];
}
else
{
for(int i = 0;i<10;i++)
{
result[imgIndex][i] = -13;
}
deError[imgIndex] = 11;
return -3;
}
/*if(!hough_circles1.empty())
{
for(int i = 0;i<hough_circles1.size();i++)
{
if(hough_circles1[i][2]>100 && hough_circles1[i][2]<130)
{
bigCircle.x = hough_circles1[i][0];
bigCircle.y = hough_circles1[i][1];
}
}
}*/
int dif = 0;
if(bigCircle.y!=0)
dif = abs(bigCircle.y - hough_circles[0][1]);
for(size_t i = 0;i<hough_circles.size();i++)
{
Point center(cvRound(hough_circles[i][0]),cvRound(hough_circles[i][1]));
int radius = cvRound(hough_circles[i][2]);
if(radius<120 && radius>65)
{
//circle(bw1,center,radius,Scalar(155,50,255),1,8,0);
circleNum++;
if(bigCircle.y!=0)
{
int temp = abs(bigCircle.y - center.y);
if(dif!=0 && temp<dif)
{
dif = temp;
smaCircle = center;
}
}
}
}
/*double dist = 0;
if(bigCircle.y!=0 && smaCircle.y!=0)
{
double x2 = (bigCircle.x - smaCircle.x)*(bigCircle.x - smaCircle.x);
double y2 = (bigCircle.y - smaCircle.y)*(bigCircle.y - smaCircle.y);
dist = sqrt(x2+y2);
}*/
//circle(bw1,bigCircle,3,Scalar(155,50,255),-1);
//circle(bw1,smaCircle,3,Scalar(155,50,255),-1);
/*imshow("huofu",bw1);
waitKey(0);*/
//dist = dist - 425;
Point up(0,0);
Point down(0,0);
Point leftP(0,0);
Point rightP(0,0);
double gradientUp = 0;
double gradientDown = 0;
double gradientLOrR = 0;
#pragma omp parallel for
for(int i = 0;i<localEdges[imgIndex].size();i++)
{
if(localEdges[imgIndex][i].x == xP)
{
if(localEdges[imgIndex][i].y < circlePoint[imgIndex].y)
up = localEdges[imgIndex][i];
else
down = localEdges[imgIndex][i];
}
if(localEdges[imgIndex][i].y == yP)
{
if(localEdges[imgIndex][i].x < circlePoint[imgIndex].x)
leftP = localEdges[imgIndex][i];
else
rightP = localEdges[imgIndex][i];
}
}
if(up.x != 0 && down.x != 0 && rightP.x!=0 && leftP.x!=0)
{
for(int i = udLeave;i<100;i++)
{
Point pt1(up.x,up.y-i);
Point pt2(down.x,down.y+i);
Point pt3(up.x,up.y-i-1);
Point pt4(down.x,down.y+i+1);
if( pt3.y<0 || pt4.y>srcImg.rows-1)
continue;
double pixel1 = srcImg.at<uchar>(pt1);
double pixel2 = srcImg.at<uchar>(pt3);
double pixel3 = srcImg.at<uchar>(pt2);
double pixel4 = srcImg.at<uchar>(pt4);
double temp1 = abs(pixel1-pixel2);
double temp2 = abs(pixel3-pixel4);
gradientUp = gradientUp + temp1;
gradientDown = gradientDown + temp2;
}
if(imgIndex==0 || imgIndex==2)
{
for(int i = levcover;i<100;i++)
{
Point pt1(rightP.x+i,rightP.y);
Point pt3(rightP.x+i+1,rightP.y);
if( pt3.x>srcImg.cols-1)
break;
double pixel1 = srcImg.at<uchar>(pt1);
double pixel2 = srcImg.at<uchar>(pt3);
double temp1 = abs(pixel1-pixel2);
gradientLOrR = gradientLOrR + temp1;
}
}
if(imgIndex==1 || imgIndex==3)
{
for(int i = levcover;i<100;i++)
{
Point pt1(leftP.x-i,rightP.y);
Point pt3(leftP.x-i-1,rightP.y);
if( pt3.x<0)
break;
double pixel1 = srcImg.at<uchar>(pt1);
double pixel2 = srcImg.at<uchar>(pt3);
double temp1 = abs(pixel1-pixel2);
gradientLOrR = gradientLOrR + temp1;
}
}
}
if(circleNum<hole)
{
result[imgIndex][4] = 1;//缺孔
}
if(gradientUp>100 && result[imgIndex][5]==0)
result[imgIndex][5] = 3;//下移位
if(gradientLOrR>100 && result[imgIndex][5]==0)
{
result[imgIndex][5] = 2;//左右移位
}
if(gradientDown>100 && result[imgIndex][5]==0)
result[imgIndex][5] = 1;//上移位
}
int lackMaterial(int result[][10],Mat srcImage,int imgIndex)
{
Mat img,bw,combw;
int memThreold = 50; //提取中心膜時二值化閾值
img = srcImage;
Mat tempL,tempR;
mask_left.copyTo(tempL);
mask_right.copyTo(tempR);
threshold(tempL,tempL,memThreold,255,CV_THRESH_BINARY);//模版轉爲二值圖
threshold(tempR,tempR,memThreold,255,CV_THRESH_BINARY);
int resultImage_cols = img.cols - mask_left.cols + 1;
int resultImage_rows = img.rows - mask_left.rows + 1;
if(resultImage_cols<=0 || resultImage_rows<=0)
{
for(int i = 0;i < 4;i++)
{
for(int j = 0;j<10;j++)
{
result[i][j] = -17;//結果圖爲空
}
}
deError[imgIndex] = 15;
return -1;
}
Mat resultImage;
resultImage.create(resultImage_cols,resultImage_rows,CV_32FC1);
threshold(img,bw,memThreold,255,CV_THRESH_BINARY);
GaussianBlur(bw,bw,Size(5,5),2,2);
/*imshow("huofu",bw);
waitKey(0);*/
vector<Vec3f> hough_circles;
//霍夫圓變換粗定位圓,累加器爲原圖像2/3,最小圓心距離5,canny高閾值,圓檢測閾值60,越小越能檢測到不規則的圓
HoughCircles(bw,hough_circles,CV_HOUGH_GRADIENT,1.5,10,200,100,50,0);
if(hough_circles.empty())
return -1;
int maxCircle = -1;//找出合適大小的圓
for(int i = 0;i<hough_circles.size();i++)
{
if(hough_circles[i][2] < 140 && hough_circles[i][2]>100)
{
maxCircle = i;
}
}
if(maxCircle == -1)
return -1;
int flag = hough_circles[maxCircle][0] - srcImage.cols/2;
threshold(srcImage,combw,memThreold,255,CV_THRESH_BINARY);
/*imshow("left",tempL);
waitKey(0);
imshow("right",tempR);
waitKey(0);
imshow("2",combw);
waitKey(0);*/
if(flag > 0)
{
matchTemplate(combw,tempR,resultImage,TM_SQDIFF);
}
else
{
matchTemplate(combw,tempL,resultImage,TM_SQDIFF);
}
//normalize(resultImage,resultImage,0,1,NORM_MINMAX,-1,Mat());
double minValue;double maxValue;
Point minlocation;Point maxLocation;Point matchLocation;
minMaxLoc(resultImage,&minValue,&maxValue,&minlocation,&maxLocation,Mat());
int queliao = (int)(minValue/1000000);
if(queliao>950)
result[imgIndex][7] = 1;//檢測到缺料
return 0;
}
//感興趣區域提取
int getRoiImg(const Mat srcImg,int sampleNum,vector<Mat>& roiImgs,int result[][10])
{
Mat grayImg,bwImg,blurImg;
int roi_threold = 23; //提取感興趣區域時的閾值
if(srcImg.channels() == 3)
cvtColor(srcImg,grayImg,CV_RGB2GRAY);
else if(srcImg.channels() == 1)
{
grayImg = srcImg;
}
medianBlur(grayImg,blurImg,3);
threshold(blurImg,bwImg,roi_threold,255,THRESH_BINARY_INV);
/*namedWindow("二值圖",CV_WINDOW_NORMAL);
imshow("二值圖",bwImg);
waitKey(0);*/
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(bwImg,contours,hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_NONE,Point(0,0));
if(contours.size()<sampleNum)
{
for(int i = 0;i < 4;i++)
{
for(int j = 0;j<10;j++)
{
result[i][j] = -2;//檢測到的輪廓小於樣本輪廓
}
}
return -1;
}
contourSort(contours);
if(contours.size()<sampleNum)
sampleNum = contours.size();
vector<vector<Point>> getcontours;
vector<Point> CT1;
vector<Point> CT2;
vector<Point> CT3;
vector<Point> CT4;
for(int i = 0;i<sampleNum && i<contours.size()-1;i++)
{
int x = contours[i][0].x;
int y = contours[i][0].y;
if(x<1226&&y<1028&&contours[i].size()>1200&&contours[i].size()<1720)
{
CT1 = contours[i];
}
if(x>1226&&y<1028&&contours[i].size()>1200&&contours[i].size()<1720)
{
CT2 = contours[i];
}
if(x<1226&&y>1028&&contours[i].size()>1200&&contours[i].size()<1720)
{
CT3 = contours[i];
}
if(x>1226&&y>1028&&contours[i].size()>1200&&contours[i].size()<1720)
{
CT4 = contours[i];
}
}
contours[0] = CT1;
contours[1] = CT2;
contours[2] = CT3;
contours[3] = CT4;
for(int i = 0;i<sampleNum;i++)
{
getcontours.push_back(contours[i]);
if(i==0)
{
localEdges.push_back(contours[i]);
}
if(i==1)
{
vector<Point> temp;
for(int j = 0;j<contours[i].size();++j)
{
Point temp1(contours[i][j].x-1226,contours[i][j].y);
temp.push_back(temp1);
}
localEdges.push_back(temp);
}
if(i==2)
{
vector<Point> temp;
for(int j = 0;j<contours[i].size();++j)
{
Point temp1(contours[i][j].x,contours[i][j].y-1028);
temp.push_back(temp1);
}
localEdges.push_back(temp);
}
if(i==3)
{
vector<Point> temp;
for(int j = 0;j<contours[i].size();++j)
{
Point temp1(contours[i][j].x-1226,contours[i][j].y-1028);
temp.push_back(temp1);
}
localEdges.push_back(temp);
}
}
//imshow("輪廓圖",ctrImage);
for(int i = 0;i<getcontours.size();i++)
{
if(getcontours[i].empty())
{
Mat Idst = Mat::zeros(515,680,CV_8UC1);
roiImgs.push_back(Idst);
continue;
}
RotatedRect rRect;
rRect=minAreaRect(getcontours[i]);
int dstw,dsth;
Point2f vertices[4];
Point2f verdst[4];
int minBorder = min(rRect.size.height,rRect.size.width);
int addRect = 100;
rRect.size.width = rRect.size.width + addRect;
rRect.size.height = rRect.size.height + addRect;
if(rRect.size.width>rRect.size.height)
{
rRect.points(vertices);//取得四個頂點
dstw = rRect.size.width;
dsth = rRect.size.height;
verdst[0] = Point2f(0,dsth);
verdst[1] = Point2f(0,0);
verdst[2] = Point2f(dstw,0);
verdst[3] = Point2f(dstw,dsth);
}
else
{
rRect.points(vertices);
dstw = rRect.size.height;
dsth = rRect.size.width;
verdst[0] = Point2f(dstw,dsth);
verdst[1] = Point2f(0,dsth);
verdst[2] = Point2f(0,0);
verdst[3] = Point2f(dstw,0);
}
Mat Idst = Mat(dsth,dstw,CV_8UC1);
//Mat dstImg;
Mat warpMatrix = getPerspectiveTransform(vertices, verdst);
warpPerspective(srcImg, Idst, warpMatrix, Idst.size(), INTER_LINEAR, BORDER_CONSTANT);
//resize(Idst,dstImg,Size(640,380));
roiImgs.push_back(Idst);
}
/*Mat a = roiImgs[0];
Mat b = roiImgs[3];
int rowN = (a.rows+b.rows)/2;
int colN = (a.cols+b.cols)/2;
resize(a,a,Size(colN,rowN));
resize(b,b,Size(colN,rowN));
imshow("1",a);
waitKey(0);
imshow("4",b);
waitKey(0);
imwrite("mask_left.bmp",a);
imwrite("mask_right.bmp",b);*/
return 0;
}
//------------外輪廓髒點、壓印檢測------------//
int badSpot(Mat srcImg,vector<vector<Point>>& ctspot,const Point circlepoint[],int leavCenter[],const RubDetectParams rubParams,int imgIndex,vector<vector<Point2f>>& roRect,int result[][10])
{
int addX = 0;
int addY = 0;
if(imgIndex == 1)
{
addX = dst_height/2;
}
if(imgIndex == 2)
{
addY = dst_width/2;
}
if(imgIndex == 3)
{
addX = dst_height/2;
addY = dst_width/2;
}
Mat Img;
srcImg.copyTo(Img);
if(localEdges[imgIndex].empty() || circleEdges[imgIndex].empty())
{
for(int i = 0;i < 4;i++)
{
for(int j = 0;j<10;j++)
{
result[i][j] = -14;//檢測到的輪廓小於樣本輪廓
}
}
deError[imgIndex] = 12;
return -1;
}
int minY = localEdges[imgIndex][0].y;
int maxY = localEdges[imgIndex][0].y;
#pragma omp parallel for
for(int i = 0;i<localEdges[imgIndex].size();i+=14)
{
if(localEdges[imgIndex][i].y<minY)
minY = localEdges[imgIndex][i].y;
if(localEdges[imgIndex][i].y>maxY)
maxY = localEdges[imgIndex][i].y;
for(int j = -12;j<13;j++)
for(int k = -12;k<13;k++)
{
int x = localEdges[imgIndex][i].y+j;
int y = localEdges[imgIndex][i].x+k;
if(x<0)
x = 0;
if(y<0)
y = 0;
if(x>=Img.rows)
x = Img.rows-1;
if(y>=Img.cols)
y = Img.cols-1;
Img.at<char>(x,y) = 32;
}
}
#pragma omp parallel for
for(int i = 0;i<circleEdges[imgIndex].size();i+=8)
{
for(int j = -6;j<7;j++)
for(int k = -6;k<7;k++)
{
int x = circleEdges[imgIndex][i].y+j;
int y = circleEdges[imgIndex][i].x+k;
if(x<0)
x = 0;
if(y<0)
y = 0;
if(x>=Img.rows)
x = Img.rows-1;
if(y>=Img.cols)
y = Img.cols-1;
Img.at<char>(x,y) = 32;
}
}
Mat gray,bw;
int memffset = rubParams.memOffset;
int memRubDist = rubParams.memRubDist;
int rubPixel = rubParams.rubPixelDif;
int rubPixelArea = rubParams.rubPixelArea;
int reaHoleNum = rubParams.holeNum + 2;
int rubThreold = rubParams.rubThreold;
//GaussianBlur(Img,gray,Size(3,3),2,2);
threshold(Img,bw,rubThreold,255,CV_THRESH_BINARY);
/*namedWindow("erzhitu",0);
imshow("erzhitu",bw);
waitKey(0);*/
vector<vector<Point>> bwContours;
vector<Vec4i> bwHierarchy;
Mat bwContoursImg = Mat::zeros(bw.size(),CV_8UC1);
Mat oldBw;
bw.copyTo(oldBw);
findContours(oldBw,bwContours,bwHierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_NONE);
if(bwContours.size()>300)
{
for(int i = 0;i < 4;++i)
{
for(int j = 0;j<10;++j)
{
result[i][j] = -15;//檢測到的輪廓太多
}
}
deError[imgIndex] = 13;
return -1;
}
//findContours(bw,bwContours,bwHierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE);
/*for(int index = 0;index<bwContours.size();index++)
{
drawContours(bwContoursImg,bwContours,index,Scalar(255,255,255),1,8,bwHierarchy);
}*/
contourSort(bwContours);
for(int i = reaHoleNum;i<bwContours.size();i++)
{
int contSize = bwContours[i].size();
if(contSize>500)
continue;
double flag1 = pointPolygonTest(bwContours[1],bwContours[i][0],false);
double flag2 = pointPolygonTest(bwContours[2],bwContours[i][0],false);
int localPixelAve = 0;
int localPixelCount = 0;
int localPixelSum = 0;
int localContrast = 0;
Rect contourRect;
contourRect = boundingRect(bwContours[i]);
for(int j = contourRect.x;j<contourRect.x+contourRect.width;j++)
{
//uchar* data = roi.ptr<uchar>(j);
for(int k = contourRect.y;k<contourRect.y+contourRect.height;k++)
{
double iscontour = pointPolygonTest(bwContours[i],Point(j,k),false);
if(iscontour == 1 || iscontour == 0)
{
if(k<0 || j<0 || k>srcImg.rows || j>srcImg.cols)
{
for(int i = 0;i < 4;i++)
{
for(int j = 0;j<10;j++)
{
result[i][j] = -16;//檢測到的輪廓小於樣本輪廓
}
}
deError[imgIndex] = 14;
return -1;
}
localPixelCount++;
localPixelSum = localPixelSum + srcImg.at<uchar>(k,j);
}
}
}
if(localPixelCount!=0)//排除除0異常
{
localPixelAve = (int)(localPixelSum/localPixelCount);
}
localContrast = localPixelAve - 32;
if(bwContours[i].size() > rubPixelArea && flag1 == 1 && flag2 == -1)
{
int difY1 = abs(bwContours[i][0].y - minY);
int difY2 = abs(bwContours[i][0].y - maxY);
if(localContrast > rubPixel && difY1>25 && difY2>25)
{
vector<Point2f> trot;
Point2f DT[4] = {0};
RotatedRect roR = minAreaRect(bwContours[i]);
roR.points(DT);
for(int k = 0;k<4;k++)
{
DT[k].x = DT[k].x + addX;
DT[k].y = DT[k].y + addY;
trot.push_back(DT[k]);
}
roRect.push_back(trot);
result[imgIndex][6] = 1;
}
}
if(bwContours[i].size() < rubPixelArea)
break;
}
return 0;
//imshow("lunkuo",bwContoursImg);
//waitKey(0);
/*contourSort(bwContours);
drawContours(bwContoursImg,bwContours,1,Scalar(255,255,255),1,8);
double ctArea = contourArea(bwContours[1]);
int blackpoint = 0;
for(int i = 0;i<gray.rows;i++)
{
for(int j = 0;j<gray.cols;j++)
{
Point temp(i,j);
if(gray.at<uchar>(i,j)<15 && pointPolygonTest(bwContours[1],temp,false))
{
blackpoint++;
}
}
}
int a = 0;*/
//centerOffset(bwContours[1],leavCenter,circlepoint,memRubDist,memffset);
//if(bwContours.size()>reaHoleNum) //如果輪廓大於reaHoleNum個開始判斷
//{
// for(int i = reaHoleNum;i<bwContours.size();i++)//
// {
// Rect contourRect;
// contourRect = boundingRect(bwContours[i]);
// int c = bwContours[i].size()/2;
// Point contPixel = bwContours[i][c];
// int pixelNum = 0;
// int pixelSum = 0;
// int avePixel = 0;
// if(pointPolygonTest(bwContours[1],contPixel,false) != 1)
// {
// continue;
// }
// for(int j = contourRect.x;j<=(contourRect.x+contourRect.width);j++)
// {
// for(int k = contourRect.y;k<=(contourRect.y+contourRect.height);k++)
// {
// if(pointPolygonTest(bwContours[i],Point(j,k),false) == 1)
// {
// pixelNum++;
// pixelSum = pixelSum + gray.at<uchar>(k,j);
// }
// }
// }
// if(pixelNum!=0)
// {
// avePixel = (int)(pixelSum/pixelNum);
// }
// if(avePixel>rubPixel && pixelNum>rubPixelArea)//根據面積和像素值判斷
// {
// bool flag = false;
// if(avePixel>80)
// {
// ctspot.push_back(bwContours[i]);
// flag = true;
// }
// if(pixelNum>rubPixelArea+5)
// {
// if(!flag)
// ctspot.push_back(bwContours[i]);
// }
// }
// if(i<bwContours.size()-1)
// {
// if(bwContours[i-1].size()< 20)
// break;
// }
// }
//}
//imshow("外輪廓圖",bwContoursImg);
//imshow("原始圖",img);
//imshow("二值圖",oldBw);
}
//-------------偏心檢測-----------//
int centerOffset(const Point circlepoint,const int dist,const int maxleav,int memUdOffset,int result[][10],int imgIndex)
{
int updist = 0;
int downdist = 0;
int leftdist = 0;
int rightdist = 0;
int updowndist = 0;
int rldif = 0;
Point upW(0,0);
Point upN(0,0);
Point downW(0,0);
Point downN(0,0);
Point rightW(0,0);
Point rightN(0,0);
Point leftW(0,0);
Point leftN(0,0);
for(int i = 0;i<circleEdges[imgIndex].size();i++)
{
if(circleEdges[imgIndex][i].y == circlepoint.y)
{
if(circleEdges[imgIndex][i].x<circlepoint.x)
{
leftN = circleEdges[imgIndex][i];
}
else
rightN = circleEdges[imgIndex][i];
continue;
}
if(circleEdges[imgIndex][i].x == circlepoint.x)
{
if(circleEdges[imgIndex][i].y > circlepoint.y)
{
downN = circleEdges[imgIndex][i];
}
if(circleEdges[imgIndex][i].y < circlepoint.y)
{
upN = circleEdges[imgIndex][i];
}
}
}
for(int i = 0;i<localEdges[imgIndex].size();++i)
{
if(localEdges[imgIndex][i].x == circlepoint.x)
{
if(localEdges[imgIndex][i].y<circlepoint.y)
{
upW = localEdges[imgIndex][i];
}
else
downW = localEdges[imgIndex][i];
continue;
}
if(localEdges[imgIndex][i].y == circlepoint.y)
{
if(localEdges[imgIndex][i].x > circlepoint.x)
{
rightW = localEdges[imgIndex][i];
}
if(localEdges[imgIndex][i].x < circlepoint.x)
{
leftW = localEdges[imgIndex][i];
}
}
}
if(upW.x!=0 && downW.x!=0&&upN.x!=0 && downN.x!=0 && rightN.x!=0 && rightW.x!=0 && leftN.x!=0 && leftW.x!=0)
{
updist = abs(upN.y - upW.y);
downdist = abs(downW.y - downN.y);
rightdist = abs(rightW.x - rightN.x);
leftdist = abs(leftN.x - leftW.x);
updowndist = abs(updist-downdist);
updowndist = abs(updowndist-158);
if(imgIndex == 0 || imgIndex == 2)
rldif = abs(rightdist - 91);
if(imgIndex == 1 || imgIndex == 3)
rldif = abs(leftdist - 91);
}
if(updowndist>memUdOffset)
{
result[imgIndex][8] = 1;
}
if(rldif>maxleav)
{
result[imgIndex][8] = 2;
}
return 0;
}
//最小二乘法擬合圓
bool circleLeastFit(const vector<Point> &points, double ¢er_x, double ¢er_y, double &radius)
{
center_x = 0.0f;
center_y = 0.0f;
radius = 0.0f;
if (points.size() < 3)
{
return false;
}
double sum_x = 0.0f, sum_y = 0.0f;
double sum_x2 = 0.0f, sum_y2 = 0.0f;
double sum_x3 = 0.0f, sum_y3 = 0.0f;
double sum_xy = 0.0f, sum_x1y2 = 0.0f, sum_x2y1 = 0.0f;
int N = points.size();
for (int i = 0; i < N; i++)
{
double x = points[i].x;
double y = points[i].y;
double x2 = x * x;
double y2 = y * y;
sum_x += x;
sum_y += y;
sum_x2 += x2;
sum_y2 += y2;
sum_x3 += x2 * x;
sum_y3 += y2 * y;
sum_xy += x * y;
sum_x1y2 += x * y2;
sum_x2y1 += x2 * y;
}
double C, D, E, G, H;
double a, b, c;
C = N * sum_x2 - sum_x * sum_x;
D = N * sum_xy - sum_x * sum_y;
E = N * sum_x3 + N * sum_x1y2 - (sum_x2 + sum_y2) * sum_x;
G = N * sum_y2 - sum_y * sum_y;
H = N * sum_x2y1 + N * sum_y3 - (sum_x2 + sum_y2) * sum_y;
a = (H * D - E * G) / (C * G - D * D);
b = (H * C - E * D) / (D * D - G * C);
c = -(a * sum_x + b * sum_y + sum_x2 + sum_y2) / N;
center_x = a / (-2);
center_y = b / (-2);
radius = sqrt(a * a + b * b - 4 * c) / 2;
return true;
}
//-----輪廓排序-----------//
void contourSort(vector<vector<Point>>& contours)
{
vector<Point> temp;
if(!contours.empty())
{
temp = contours[0];
for(int i = 0;i < contours.size();i++)
{
for(int j = contours.size()-1;j > i;j--)
{
if(contours[j].size() > contours[j-1].size())
{
temp = contours[j-1];
contours[j-1] = contours[j];
contours[j] = temp;
}
}
}
}
}
//顯示提取的感興趣區域原始圖
void showImg(const vector<Mat>& Img)
{
if(Img.empty())
return;
for(int i = 0;i<Img.size();i++)
{
String str;
String str1 = "透氣膜";
char str2[2] = "";
itoa(i+1,str2,10);
str = str1 + str2;
imshow(str,Img[i]);
}
}
//畫出處理後的結果圖
void paintProcessedImg(char* img,char* img1,MemDetectResult memdr,const vector<vector<Point>> badspots,const int leavCenter[],int result[][10],vector<vector<Point2f>> roRect)
{
Mat srcImg(Size(dst_height,dst_width),CV_8UC1,img);
Mat srcImg1(Size(dst_height,dst_width),CV_8UC1,img1);
/*imshow("原圖",srcImg);
waitKey(0);*/
if(!memdr.bwspot.empty())//如果有黑白點
{
for(int i = 0;i<memdr.bwspot.size();i++)
{
for(int j = 0;j<memdr.bwspot[i].size();j++)
{
circle(srcImg,memdr.bwspot[i][j],0,Scalar(255,255,255),-1);
}
}
}
if(!badspots.empty())//如果有外輪廓髒點
{
for(int i = 0;i<badspots.size();i++)
{
for(int j = 0;j<badspots[i].size();j++)
{
circle(srcImg,badspots[i][j],0,Scalar(255,255,255),-1);
}
}
}
if(!memdr.slik.empty())//如果有毛絲
{
for(int i = 0;i<memdr.slik.size();i++)
{
circle(srcImg,memdr.slik[i],0,Scalar(255,255,255),-1);
}
}
if(!memdr.crease.empty())//如果有黑白點
{
for(int i = 0;i<memdr.crease.size();i++)
{
for(int j = 0;j<memdr.crease[i].size();j++)
{
circle(srcImg,memdr.crease[i][j],0,Scalar(255,255,255),-1);
}
}
}
if(!memdr.drub.empty())//如果有復偏
{
for(int i = 0;i<memdr.drub.size();i++)
{
for(int j = 0;j<memdr.drub[i].size();j++)
{
circle(srcImg,memdr.drub[i][j],0,Scalar(255,255,255),-1);
}
}
}
int height = 0;
if(leavCenter[0] == 1)//向上偏心
{
height+=50;
putText(srcImg,"up leave",Point(250,height),CV_FONT_ITALIC,1,Scalar(255,255,255));
}
if(leavCenter[1] == 1)//向左或向右偏心
{
height+=50;
putText(srcImg,"left or right leave",Point(250,height),CV_FONT_ITALIC,1,Scalar(255,255,255));
}
if(leavCenter[2] == 1)//向下偏心
{
height+=50;
putText(srcImg,"down leave",Point(250,height),CV_FONT_ITALIC,1,Scalar(255,255,255));
}
for(int i = 0;i<4;i++)
{
if(i == 0)
{
if(result[i][0] == -1)
{
height+=50;
putText(srcImg,"wuyangben",Point(250,height),CV_FONT_ITALIC,1,Scalar(0,0,0));
continue;
}
if(result[i][0] == -2)
{
height+=50;
putText(srcImg,"touqimoyiwei",Point(250,height),CV_FONT_ITALIC,1,Scalar(0,0,0));
continue;
}
if(result[i][0] == -3)
{
height+=50;
putText(srcImg,"wutouqimo",Point(250,height),CV_FONT_ITALIC,1,Scalar(0,0,0));
continue;
}
if(result[i][4] == 1)
{
height+=50;
putText(srcImg,"quekong",Point(250,height),CV_FONT_ITALIC,1,Scalar(0,0,0));
}
}
if(i == 1)
{
height = 0;
if(result[i][0] == -1)
{
height+=50;
putText(srcImg,"wuyangben",Point(1476,height),CV_FONT_ITALIC,1,Scalar(0,0,0));
continue;
}
if(result[i][0] == -2)
{
height+=50;
putText(srcImg,"touqimoyiwei",Point(1476,height),CV_FONT_ITALIC,1,Scalar(0,0,0));
continue;
}
if(result[i][0] == -3)
{
height+=50;
putText(srcImg,"wutouqimo",Point(1476,height),CV_FONT_ITALIC,1,Scalar(0,0,0));
continue;
}
if(result[i][4] == 1)
{
height+=50;
putText(srcImg,"quekong",Point(1476,height),CV_FONT_ITALIC,1,Scalar(0,0,0));
}
}
if(i == 2)
{
height = 1028;
if(result[i][0] == -1)
{
height+=50;
putText(srcImg,"wuyangben",Point(250,height),CV_FONT_ITALIC,1,Scalar(0,0,0));
continue;
}
if(result[i][0] == -2)
{
height+=50;
putText(srcImg,"touqimoyiwei",Point(250,height),CV_FONT_ITALIC,1,Scalar(0,0,0));
continue;
}
if(result[i][0] == -3)
{
height+=50;
putText(srcImg,"wutouqimo",Point(250,height),CV_FONT_ITALIC,1,Scalar(0,0,0));
continue;
}
if(result[i][4] == 1)
{
height+=50;
putText(srcImg,"quekong",Point(250,height),CV_FONT_ITALIC,1,Scalar(0,0,0));
}
}
if(i == 3)
{
height = 1028;
if(result[i][0] == -1)
{
height+=50;
putText(srcImg,"wuyangben",Point(1476,height),CV_FONT_ITALIC,1,Scalar(0,0,0));
continue;
}
if(result[i][0] == -2)
{
height+=50;
putText(srcImg,"touqimoyiwei",Point(1476,height),CV_FONT_ITALIC,1,Scalar(0,0,0));
continue;
}
if(result[i][0] == -3)
{
height+=50;
putText(srcImg,"wutouqimo",Point(1476,height),CV_FONT_ITALIC,1,Scalar(0,0,0));
continue;
}
if(result[i][4] == 1)
{
height+=50;
putText(srcImg,"quekong",Point(1476,height),CV_FONT_ITALIC,1,Scalar(0,0,0));
}
}
}
for(int i = 0;i<roRect.size();i++)
{
Point pt1 = roRect[i][0];
Point pt2 = roRect[i][1];
Point pt3 = roRect[i][2];
Point pt4 = roRect[i][3];
line(srcImg1,pt1,pt2,Scalar(255,255,255));
line(srcImg1,pt2,pt3,Scalar(255,255,255));
line(srcImg1,pt3,pt4,Scalar(255,255,255));
line(srcImg1,pt4,pt1,Scalar(255,255,255));
}
for(int i = 0;i<4;i++)
{
int addX = 0,addY = 0;
if(i == 1)
{
addX = dst_height/2;
}
if(i == 2)
{
addY = dst_width/2;
}
if(i == 3)
{
addX = dst_height/2;
addY = dst_width/2;
}
int flag = result[i][5];
if(flag == 1) //上移
{
Point pt1(150+addX,50+addY);
Point pt2(100+addX,100+addY);
Point pt3(200+addX,100+addY);
Point pt4(150+addX,240+addY);
line(srcImg,pt1,pt2,Scalar(0,0,0),3);
line(srcImg,pt1,pt3,Scalar(0,0,0),3);
line(srcImg,pt1,pt4,Scalar(0,0,0),3);
}
if(flag == 2 && (i == 1 || i == 3)) //右移
{
Point pt1(300+addX,150+addY);
Point pt2(200+addX,50+addY);
Point pt3(200+addX,250+addY);
Point pt4(50+addX,150+addY);
line(srcImg,pt1,pt2,Scalar(0,0,0),3);
line(srcImg,pt1,pt3,Scalar(0,0,0),3);
line(srcImg,pt1,pt4,Scalar(0,0,0),3);
}
if(flag == 2 && (i == 0 || i == 2)) //左移
{
Point pt1(200+addX,300+addY);
Point pt2(50+addX,200+addY);
Point pt3(350+addX,200+addY);
Point pt4(200+addX,50+addY);
line(srcImg,pt1,pt2,Scalar(0,0,0),3);
line(srcImg,pt1,pt3,Scalar(0,0,0),3);
line(srcImg,pt1,pt4,Scalar(0,0,0),3);
}
if(flag == 3) //下移
{
Point pt1(50+addX,200+addY);
Point pt2(150+addX,150+addY);
Point pt3(150+addX,250+addY);
Point pt4(400+addX,200+addY);
line(srcImg,pt1,pt2,Scalar(0,0,0),3);
line(srcImg,pt1,pt3,Scalar(0,0,0),3);
line(srcImg,pt1,pt4,Scalar(0,0,0),3);
}
}
/*namedWindow("原圖1",0);
imshow("原圖1",srcImg);
waitKey(0);
namedWindow("原圖2",0);
imshow("原圖2",srcImg1);
waitKey(0);*/
}