opencv hough圆和直线检测

opencv hough圆和直线检测_第1张图片 识别结果

double getAngle(CvPoint cen, CvPoint first, CvPoint second)
{
    double ma_x = first.x - cen.x;
    double ma_y = first.y - cen.y;
    double mb_x = second.x - cen.x;
    double mb_y = second.y - cen.y;
    double v1 = (ma_x*mb_x) + (ma_y*mb_y);
    double ma_val = sqrt(ma_x*ma_x + ma_y*ma_y);
    double mb_val = sqrt(mb_x*mb_x + mb_y*mb_y);
    double cosM = v1 / (ma_val*mb_val);
    double angleAMB = acos(cosM) * 180 / CV_PI;

    return angleAMB;
}


double getMeterValue(CvPoint pointerCenter, CvPoint pointerEnd)
{
    double angle = getAngle(pointerCenter, CvPoint(pointerCenter.x, 0), pointerEnd);
    //double angleStart = 45, angleEnd = 315;
    double angleStart = 30, angleEnd = 330;
    double maxValue = 100;
    cout << "meterAngle:" << angle << endl;

    if (pointerEnd.x     {
        angle = 180 - angle;
    }
    else {
        angle = 180 + angle;
    }

    double meterValue = (abs(angle - angleStart) / (angleEnd - angleStart))*maxValue;
    cout << "meterAngle:" << angle << endl;
    //cout << "meterValue:" << meterValue << " Mpa" << endl;
    cout << "meterValue:" << meterValue << " ℃ " << endl;
    return meterValue;
}


int main()
{
    //----对仪表读数进行识别处理---------------------------------------------------------
    Mat                         srcImage = imread("000003.jpg");
    if (srcImage.empty())
        return -1; //双边滤波
    Mat                         resultImage2;
    bilateralFilter(srcImage, resultImage2, 25, 25 * 2, 25 / 2); //双边滤波,滤除高斯噪声
    //imshow("bilateralFilterImage", resultImage2);
    //灰度化处理
    Mat                         resultImage3;
    cvtColor(resultImage2, resultImage3, CV_RGB2GRAY); //把图片转化为灰度图
    //namedWindow("resultImage2", 2);
    //cvResizeWindow("mask", mask, nHeight);
    //imshow("resultImage2", resultImage2);    //在窗口my中显示image图像  
    //imshow("CV_RGB2GRAYImage", resultImage3);
    //roiSaveImg("./roi-graymeter.jpg", resultImage3); //存储图片到文件,等待识别处理
    imwrite("./roi-graymeter.jpg", resultImage3);

    //namedWindow("resultImage3", 0);
    ////cvResizeWindow("mask", mask, nHeight);
    //imshow("resultImage3", resultImage3);    //在窗口my中显示image图像  
    //二值化处理
    Mat                         resultImage4;
    threshold(resultImage3, resultImage4, 200, 255, CV_THRESH_BINARY_INV); 
    //imshow("cvThresholdImage", resultImage4);
    imwrite("./roi-erzhimeter.jpg", resultImage4); //存储图片到文件,等待识别处理

    //-----hough变换检测圆,获取圆心并绘制圆------------------------------------------------
    const char *        filename = "./roi-graymeter.jpg";
    IplImage *            src = cvLoadImage(filename, 0);
    IplImage *            dst;
    IplImage *            color_dst;
    CvMemStorage *        storage = cvCreateMemStorage(0);
    CvSeq *             lines = 0;

    int                 i;
    CvPoint             meterCenterPoint;
    IplImage *            img = cvLoadImage(filename, 1);
    IplImage *            gray = cvCreateImage(cvGetSize(img), 8, 1);
    cvCvtColor(img, gray, CV_BGR2GRAY);
    cvSmooth(gray, gray, CV_GAUSSIAN, 9, 9);
    //cvHoughCircles(image,storage,method,dp,min_dist,p1 = 100,p2 = 100,min_radius = 0,max_radius = 0);
    //method:CV_HOUGH_GRADIENT H.K于2003年发表的21HT方法
    //dp检测圆心累加器的分辨率,1不变,2累加器尺寸为原图一半
    //min_dist 检测到的圆心之间的最小距离。取值太小,在一个圆被分解为多个圆。太大则漏检
    //p1在CV_HOUGH_GRADIENT情况下,此参数为传递给Canny边缘检测算子的两个阈值较高的那个,低阈值为其一半
    //p2取值越小则误检很多不存在的圆
    //min_radius 被搜索圆得最小半径,小于此半径被忽略
    //max_radius 最大半径,默认为max(width,height);
    CvSeq * circles = cvHoughCircles(gray, storage, CV_HOUGH_GRADIENT, 1, gray->height /4, 160, 160, 150, 310);
    //CvSeq * circles = cvHoughCircles(gray, storage, CV_HOUGH_GRADIENT, 2, gray->height / 3.0, 100, 100, 0, 310);
    float radius_max = 0, radius_tmp;
    for (i = 0; i < circles->total; i++)
    {
        //遍历找到半径最大的圆,即表盘
        float *     p = (float *)cvGetSeqElem(circles, i);
        radius_tmp = cvRound(p[2]);
        cvCircle (img, CvPoint (cvRound (p[0]), cvRound (p[1])), 3, CV_RGB (0, 255, 0), -1, 8, 0); //绘制绿色圆心
        cvCircle (img, CvPoint (cvRound (p[0]), cvRound (p[1])), radius_tmp, CV_RGB (255, 0, 0), 3, 8, 0); //绘制圆
        if (radius_tmp>radius_max)
        {
            radius_max = radius_tmp;
            meterCenterPoint = CvPoint(cvRound(p[0]), cvRound(p[1]));
        }
        //cvCircle(img, meterCenterPoint, radius_tmp, CV_RGB(255, 0, 0), 3, 8, 0); //绘制圆
        cout << "cvCircle:" << radius_tmp << endl;
    } 
    //cvLine(img, meterPointerEndPoint, meterCenterPoint, CV_RGB(255, 0, 0), 1, CV_AA, 0);
    cvCircle(img, meterCenterPoint, radius_max, CV_RGB(255, 0, 0), 3, 8, 0); //绘制半径最大的圆

    //-----------霍夫变换检测线-------------------------------------------------------------

    if (!src)
    {
        printf("Load image error!\n");
        return -1;
    }


    dst = cvCreateImage(cvGetSize(src), 8, 1);
    color_dst = cvCreateImage(cvGetSize(src), 8, 3);
    cvCanny(src, dst, 50, 100, 3);
    //cvThreshold (src, dst, 70, 255, CV_THRESH_BINARY_INV);//二值化处理
    cvCvtColor(dst, color_dst, CV_GRAY2BGR); //累积概率hough变换
    printf("累积概率hough变换\n");

    double distance = 0, distance1, distance2; //两点之间的距离
    CvPoint pointO, pointA, meterPointerEndPoint; //存储仪表指针坐标点

    //通过霍夫变换取得相关直线
    lines = cvHoughLines2(dst, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI / 180, 120, 120, 8);
    //遍历圆心到各直线的距离,将最长的线段作为指针(经验值)

    //计算圆心到直线上各点的距离,选择距离最大的作为指针的外端点
    for (i = 0; itotal; i++)
    {
        CvPoint*line = (CvPoint*)

        cvGetSeqElem(lines, i);
        pointO = meterCenterPoint;                      //圆心的坐标
        pointA = line[0];                               //直线端点1
        distance1 = powf((pointO.x - pointA.x), 2) + powf((pointO.y - pointA.y), 2);
        distance1 = sqrtf(distance1);

        if (distance1>distance&&distance1         {
            distance = distance1;
            meterPointerEndPoint = pointA;
        }

        pointA = line[1];                               //直线端点2
        distance2 = powf((pointO.x - pointA.x), 2) + powf((pointO.y - pointA.y), 2);
        distance2 = sqrtf(distance2);

        if (distance2>distance&&distance2         {
            distance = distance2;
            meterPointerEndPoint = pointA;
        }

        cvLine(img, line[0], line[1], CV_RGB(255, 0, 0), 1, CV_AA, 0);

        //cvLine(color_dst, line[0], line[1], CV_RGB(255, 0, 0), 1, CV_AA, 0);
        //cvLine(img, meterCenterPoint, line[0], CV_RGB(0, 255, 0), 1, CV_AA, 0);
        //cvLine(img, meterCenterPoint, line[1], CV_RGB(0, 0, 255), 1, CV_AA, 0);
    }
    //绘制表针
    cvLine(img, meterCenterPoint, meterPointerEndPoint, CV_RGB(105, 0, 75), 3, CV_AA, 0);


    //cvNamedWindow("Source", 1);
    //cvShowImage("Source", src);
    //cvNamedWindow("Hough", 1);
    //cvShowImage("Hough", color_dst);

    float meterVaule = getMeterValue(meterCenterPoint, meterPointerEndPoint);

    //      cv::putText(
    //        cv::Mat& img, // 待绘制的图像
    //        const string& text, // 待绘制的文字
    //        cv::Point origin, // 文本框的左下角
    //        int fontFace, // 字体 (如cv::FONT_HERSHEY_PLAIN)
    //        double fontScale, // 尺寸因子,值越大文字越大
    //        cv::Scalar color, // 线条的颜色(RGB)
    //        int thickness = 1, // 线条宽度
    //        int lineType = 8, // 线型(4邻域或8邻域,默认8邻域)
    //        bool bottomLeftOrigin = false // true='origin at lower left'
    //        )

    //设置绘制文本的相关参数:meterVaule
    char str[50];
    char *text;
    text = gcvt(meterVaule, 4, str);//浮点数转换为字符串


    string valueText(text);//转换为字符串
    valueText = "value:" + valueText;
    int font_face = cv::FONT_HERSHEY_COMPLEX;
    double font_scale = 1;
    int thickness = 2;
    int baseline;
    //获取文本框的长宽
    cv::Size text_size = cv::getTextSize(valueText, font_face, font_scale, thickness, &baseline);

    //将文本框居中绘制
    cv::Point origin;
    Mat imgMatTmp = cvarrToMat(img);
    origin.x = imgMatTmp.cols / 2 - text_size.width / 2;
    origin.y = imgMatTmp.rows / 4 + text_size.height;
    putText(imgMatTmp, valueText, origin, font_face, font_scale, cv::Scalar(200, 25, 25), thickness, 8, 0);

    cvShowImage("meterPointer-value", img);

    cvNamedWindow("circles", 1);
    cvShowImage("circles", img);

    waitKey(0);

    cvReleaseMemStorage(&storage);
    //cvReleaseImage(&srcImage);
    cvReleaseImage(&dst);
    cvReleaseImage(&img);

    system("pause");
    return 0;
}

你可能感兴趣的:(opencv)