法兰盘CSDN------11-21yuankong

能跑

CSDN法兰盘圆孔检测

 

#include "iostream"
#include "opencv2\opencv.hpp"
#include "function.h"
using namespace std;
using namespace cv;

int main()
{
	//读取图像
	Mat img = imread("E:\\img\\img1129-04.bmp", IMREAD_GRAYSCALE);

	//canny运算
	Mat cannyImg;
	int low_Val = 100, high_Val = 2 * low_Val;
	Canny(img, cannyImg, low_Val, high_Val, 3);
	namedWindow("canny", WINDOW_NORMAL);
	imshow("canny", cannyImg);


	
    /*****************************闭运算******************************/
    /****************************************************************/
   	Mat closeSmallImg;
	Mat elementSmall = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
	morphologyEx(cannyImg, closeSmallImg, MORPH_CLOSE, elementSmall);
	//morphologyEx(cannyImg, closeSmallImg, MORPH_CLOSE, kernel);
	namedWindow("close", WINDOW_NORMAL);
	imshow("CLOSE", closeSmallImg);

    /***********************轮廓跟踪寻找轮廓***************************/
    /****************************************************************/
	vector<Vec4i> hierarchy;
	vector<vector<Point>> contours;
	findContours(closeSmallImg, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE, Point(0, 0));
	Mat drawImg = Mat::zeros(cannyImg.size(), CV_8UC3);
	RNG rng(12345);//用来产生随机数的伪随机序列
	for (int i = 0; i < contours.size(); i++)
	{
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));  //Scalar()函数在OpenCV中是用来设置颜色的如Scalar(B,G,R)
		drawContours(drawImg, contours, i, color, 2, 8, hierarchy, 0, Point());
	}
	//imshow("s3 Contours Image", drawImg);

	
    /*************************预设置参数******************************/
    /****************************************************************/
	//轮廓长度与轮廓间距离设置
	int minCDis = 50;		  //筛选轮廓时,允许的最小轮廓间距离
	int minCircleLen = 65;   //筛选轮廓时定位圆孔的最小轮廓长度
	int maxCircleLen = 75;  //筛选轮廓时定位圆孔的最大轮廓长度
	//圆环半径设置
	float RH_mm = 140;    //检测圆盘圆孔的半径 单位:毫米
	float R0_mm = 115;   //检测圆盘的内径    单位:毫米
	float R1_mm = 160;  //检测圆环的外径    单位:毫米
	//标记ROI预览显示ROI
	Point estimateCenter = Point(750, 500);               //估计的ROI区域的中心坐标
	int estimateRadius = 500;                            //估计的ROI区域的半径
	Mat subImg = Mat::zeros(img.size(), CV_8UC1);       //初始化一个mat,其大小与srcImg一样,类型为8位单通道类型    
	img.copyTo(subImg);                                //把src里的图像复制到subimg中
	cvtColor(subImg, subImg, COLOR_GRAY2RGB);         //把subimg转变为彩色图像                                               
	circle(subImg, estimateCenter, estimateRadius, Scalar(0, 0, 255), 1, 8, 0);    //在subimg上画圆
     //thickness为1,lineType为8,shift为对应给定点的小数位数(0对结果不产生影响)
	//imshow("s0 ROI Img", subImg);


    /****************************************************************/
	/**************************轮廓筛选******************************/
    const Scalar RED = Scalar(0, 0, 255);
    const Scalar GREEN = Scalar(0, 255, 0);
    const Scalar BLUE = Scalar(255, 0, 0);
    const Scalar YELLOW = Scalar(0, 255, 255);
    
    
    //1.不在估计区域范围内的轮廓去掉,相同重心的轮廓只保留一个contours2
    // Get the moments,得到轮廓矩
    vector<Moments> mu(contours.size());
    for (int j = 0; j < contours.size(); j++)
    {
        mu[j] = moments(contours[j], false);
    }

    // Get the mass centers,重心
    vector<Point2f> mc(contours.size());
    for (int j = 0; j < contours.size(); j++)
    {
        mc[j] = Point2f(mu[j].m10 / mu[j].m00, mu[j].m01 / mu[j].m00);
        cout << "xpos = " << mc[j].x << " ypos = " << mc[j].y << std::endl;
    }
    //开始筛选
    vector<vector<Point>> contours2;
    vector<Point2f> mc_finded;
    for (int i = 0; i < contours.size(); ++i)
    {
        Point r_pos = mc[i];
        bool disFlag = true;
        //先检查轮廓出现的位置,计算轮廓矩重心的距离与估计圆心的距离
        float disR = calDistance2D(r_pos.x, r_pos.y, estimateCenter.x, estimateCenter.y);
        if (disR > estimateRadius)
        {    //在ROI区域外 则无需比较
            disFlag = false;
        }
        else
        {    //检查这个轮廓与已找到的轮廓中心是否很接近,如果是则排除 跳出循环
            for (int j = 0; j < mc_finded.size(); ++j)
            {
                Point f_pos = mc_finded[j];
                float dis = calDistance2D(r_pos.x, r_pos.y, f_pos.x, f_pos.y);
                if (dis <= minCDis)        //轮廓中心之间的距离
                {
                    disFlag = false;
                    break;
                }
            }
        }
        if (disFlag)
        {    //此轮廓的中心点位置与前都不同
            mc_finded.push_back(mc[i]);
            contours2.push_back(contours[i]);
        }
    }
    drawImg = Mat::zeros(cannyImg.size(), CV_8UC3);
    for (int i = 0; i < contours2.size(); i++)
    {
        Scalar color = cv::Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
        drawContours(drawImg, contours2, i, color, 2);
    }
    imshow("s4 reSelected Contours2 Image", drawImg);
    cout << " * Contour2 Size = " << contours2.size() << std::endl;


    //2.检查轮廓的长度contours3
    vector<float> contourLens;
    for (int i = 0; i < contours2.size(); ++i)
    {
        float conLen = arcLength(contours2[i], true);
        contourLens.push_back(conLen);
        cout << " * Contours Length = " << conLen << std::endl;
    }
    vector<vector<Point>> contours3;
    for (int i = 0; i < contourLens.size(); ++i)
    {
        if ((contourLens[i] > 260) &&
            (contourLens[i] < 400))            //检查轮廓的周长参数
        {
            contours3.push_back(contours2[i]);
            //std::printf("Contours Idx = %d Length = %f\n", i, contourLens[i], true);
        }
    }
    drawImg = Mat::zeros(cannyImg.size(), CV_8UC3);
    for (int i = 0; i < contours3.size(); i++)
    {
        Scalar color = cv::Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
        drawContours(drawImg, contours3, i, color, 2);
    }
    imshow("s5 reSelected Contours3 Image", drawImg);
    cout << " * Contour3 Size = " << contours3.size() << std::endl;


    //3.检查外接矩形 如果外接矩形的长和宽相差超过阈值 则删除contours4
    vector<vector<Point>> contours4;
    {
        for (int i = 0; i < contours3.size(); i++)
        {
            RotatedRect one_rRect = minAreaRect(contours3[i]);
            float jRes = abs(one_rRect.size.width - one_rRect.size.height);
            if (jRes < 10)    //检查轮廓外接矩形的长和宽
            {
                contours4.push_back(contours3[i]);
            }
        }
        drawImg = Mat::zeros(cannyImg.size(), CV_8UC3);
        for (int i = 0; i < contours4.size(); i++)
        {
            Scalar color = cv::Scalar(rng.uniform(0, 255), rng.uniform(0, 255),
                rng.uniform(0, 255));
            drawContours(drawImg, contours4, i, color, 2);
        }
        imshow("s6 check RECT Contours4 Image", drawImg);
        cout << " * Contour4 Size = " << contours4.size() << std::endl;
    }


    //4.检查轮廓上各点到矩形中心的距离 计算每个轮廓距离的方差 选择方差最小的N个
    vector<Point2f> holeCenter;
    vector<float> holeRadius;
    int sCnt = 10;
    if (contours4.size() >= sCnt)
    {    //如果contours4的轮廓数大于N,则再从距离方差的角度筛选
        //依次计算各轮廓上各点到轮廓中心距离序列的方差
        vector<float> contours_variance(contours4.size());
        for (int i = 0; i < contours4.size(); i++)
        {
            //计算轮廓的最小外接圆中心点
            Point2f circle_center;
            float circle_radius;
            minEnclosingCircle(contours4[i], circle_center, circle_radius);

            //计算最小外接圆中心点到轮廓上各点的距离
            vector<float> disList(contours4[i].size());
            for (int j = 0; j < contours4[i].size(); j++)
            {
                Point pos = contours4[i][j];
                float dis = calDistance2D(pos.x, pos.y, circle_center.x, circle_center.y);
                disList[j] = dis;
            }

            //计算距离序列的方差
            float varianceDis = calVariance_1DLine(disList);
            contours_variance[i] = varianceDis;
            cout << contours_variance[i] << std::endl;
        }

        //选择方差最小的N个轮廓
        vector<vector<Point>> contours4Clone(contours4);
        contours4.clear();
        for (int i = 0; i < sCnt; i++)
        {
            int minIdx = min_element(contours_variance.begin(), contours_variance.end()) - contours_variance.begin();    //在方差序列中找到最小值位置
            std::vector<float>::iterator idxIt = contours_variance.begin() + minIdx;    //方差序列中的迭代器
            std::vector<vector<Point>>::iterator contoursIt = contours4Clone.begin() + minIdx;    //轮廓序列中的迭代器
            contours4.push_back(*contoursIt);      //把对应的轮廓存储到contours4中
            contours_variance.erase(idxIt);       //删除
            contours4Clone.erase(contoursIt);    //删除
        }
    }

    //contours4中的轮廓依次计算外接矩形 轮廓中心和半径并存储contours5
    vector<Rect> boundRect;
    vector<vector<Point>> contours5;
    holeCenter.clear();
    holeRadius.clear();

    for (int i = 0; i < contours4.size(); i++)
    {
        Rect one_bRect;
        one_bRect = boundingRect(Mat(contours4[i]));
        Point2f circle_center;
        float circle_radius;
        minEnclosingCircle(contours4[i], circle_center, circle_radius);
        boundRect.push_back(one_bRect);    //vector<cv::Rect> boundRect
        holeCenter.push_back(circle_center);
        holeRadius.push_back(circle_radius);
        contours5.push_back(contours4[i]);
    }
    // Draw polygonal contour + bonding rects + circles
    drawImg = Mat::zeros(cannyImg.size(), CV_8UC3);

    for (int i = 0; i < contours5.size(); i++) {
        cv::Scalar color = GREEN;
        drawContours(drawImg, contours5, i, color, 1, 8, vector<cv::Vec4i>(), 0, cv::Point());
        rectangle(drawImg, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0);
        cv::circle(drawImg, holeCenter[i], 2, GREEN, 1, 8, 0);
        cv::putText(drawImg, std::to_string(i), holeCenter[i], cv::FONT_HERSHEY_SCRIPT_SIMPLEX, 1, cv::Scalar(0, 0, 255), 1);
    }
    cv::imshow("s7 selected Contours5 Image", drawImg);
    std::cout << " * Contour5 Size = " << contours5.size() << std::endl;

   
    /*cout << "a: " << a << endl;
    cout << "b: " << b << endl;*/

	waitKey(0);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值