透氣膜項目代碼

#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 &center_x, double &center_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);*/
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章