基于OpenCV的圆形孔检测与尺寸测量

本文介绍如何使用OpenCV库编写程序,实现对图像中圆形孔的自动检测,并计算孔的数量、孔径以及外围孔圆心组成的圆的直径等尺寸信息。

代码示例:

#include <iostream>
#include <opencv2/opencv.hpp>
#include <vector>
#include <cmath>

using namespace cv;
using namespace std;


static void mouse_callback(int event, int x, int y, int flags, void* param)
{
    if (event == EVENT_LBUTTONDOWN)
    {
        vector<Point>* points = (vector<Point>*)param;
        points->push_back(Point(x, y));
    }
}

int main()
{
    Mat image = imread('1.jpg'); // 读取图片
    if (image.empty())
    {
        cout << 'Could not open or find the image' << endl;
        return -1;
    }

    Mat hsv;
    cvtColor(image, hsv, COLOR_BGR2HSV); // 转换为HSV颜色空间

    // 定义红色范围
    Scalar lower_red = Scalar(0, 100, 100);
    Scalar upper_red = Scalar(10, 255, 255);
    Scalar lower_red2 = Scalar(160, 100, 100);
    Scalar upper_red2 = Scalar(179, 255, 255);

    Mat mask1, mask2, mask;
    inRange(hsv, lower_red, upper_red, mask1); // 获取红色区域掩码
    inRange(hsv, lower_red2, upper_red2, mask2);
    bitwise_or(mask1, mask2, mask);

    vector<Point> red_pixels; // 存储红色像素点坐标
    for (int i = 0; i < mask.rows; i++)
    {
        for (int j = 0; j < mask.cols; j++)
        {
            if (mask.at<uchar>(i, j) > 0) // 判断是否为红色像素点
            {
                red_pixels.push_back(Point(j, i)); // 存储红色像素点坐标
            }
        }
    }

    // 统计红色区块数量
    vector<vector<Point>> red_blocks; // 存储红色区块
    for (int i = 0; i < red_pixels.size(); i++)
    {
        bool found = false;
        for (int j = 0; j < red_blocks.size(); j++)
        {
            // 判断当前像素点是否属于某个已有的红色区块
            if (norm(red_pixels[i] - red_blocks[j][0]) < 50) // 假设红色区块之间的距离小于50个像素
            {
                red_blocks[j].push_back(red_pixels[i]);
                found = true;
                break;
            }
        }
        if (!found) // 如果当前像素点不属于任何已有的红色区块,则新建一个红色区块
        {
            red_blocks.push_back(vector<Point>{red_pixels[i]});
        }
    }

    double average_pixel_distance_between_red;

    // 输出每个红色区块和距离最近的红色区块之间距离的平均值
    for (int i = 0; i < red_blocks.size(); i++)
    {
        cout << 'Red block ' << i + 1 << ' has ' << red_blocks[i].size() << ' pixels' << endl;
        double min_dist = DBL_MAX;
        for (int j = 0; j < red_blocks.size(); j++)
        {
            if (i != j)
            {
                double dist = norm(red_blocks[i][0] - red_blocks[j][0]);
                if (dist < min_dist)
                {
                    min_dist = dist;
                }
            }
        }
        cout << 'Distance to nearest red block: ' << min_dist << ' pixels' << endl;
        average_pixel_distance_between_red = min_dist;
    }

    //cout << average_pixel_distance_between_red << endl;
    
    // 加载图像并将其转换为灰度图像
    Mat img = imread('1.jpg');
    Mat gray;
    cvtColor(img, gray, COLOR_BGR2GRAY);
    //imshow('Gray Image', gray);
    //waitKey(0);

    // 使用高斯滤波器对图像进行平滑处理
    Mat blur;
    GaussianBlur(gray, blur, Size(5, 5), 0);
    //imshow('Blurred Image', blur);
    //waitKey(0);

    // 对图像进行形态学操作
    Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));
    Mat closing;
    morphologyEx(blur, closing, MORPH_CLOSE, kernel);
    //imshow('closing', closing);
    //waitKey(0);

    // 对图像进行边缘检测
    Mat edges;
    Canny(closing, edges, 10, 50);
    //imshow('Edges', edges);
    waitKey(0);


   

    // 计算像素当量
    double pixel_to_mm_ratio = average_pixel_distance_between_red / 10;  // 10 mm
    double pixel_equivalent = 1 / pixel_to_mm_ratio;
    cout << '像素当量为1像素对应 ' << pixel_equivalent << endl;

    // 应用Hough圆变换算法,以检测图像中的圆形
    vector<Vec3f> circles;
    HoughCircles(edges, circles, HOUGH_GRADIENT, 1, 20, 10, 24, 20, 100);
    Mat output = gray.clone();
    cvtColor(output, output, COLOR_GRAY2BGR);
    for (size_t i = 0; i < circles.size(); i++) {
        Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
        int radius = cvRound(circles[i][2]);
        circle(output, center, radius, Scalar(0, 0, 255), 2, LINE_AA);
    }
    imshow('Output', output);


    // 计算检测到的圆的数量
    if (!circles.empty())
    {
        int num_circles = circles.size();
        cout << '孔的数量: ' << num_circles << endl;

        double max_distance = 0;
        for (size_t i = 0; i < circles.size(); i++)
        {
            Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
            int radius = cvRound(circles[i][2]);
            circle(img, center, radius, Scalar(0, 255, 0), 2);

            int diameter = 2 * radius;
            double diameter_mm = diameter / pixel_to_mm_ratio;
            cout << '孔径: ' << diameter_mm << endl;

            for (size_t j = i + 1; j < circles.size(); j++)
            {
                Point center2(cvRound(circles[j][0]), cvRound(circles[j][1]));
                double distance = sqrt(pow(center.x - center2.x, 2) + pow(center.y - center2.y, 2));
                max_distance = max(max_distance, distance);
            }
        }

        double max_distance_mm = max_distance / pixel_to_mm_ratio;
        cout << '外围孔圆心组成的圆的直径: ' << max_distance_mm << endl;
    }

    // 显示结果
    namedWindow('Circle detection');
    imshow('Circle detection', img);
    waitKey(0);
    destroyAllWindows();

    return 0;
}

程序说明:

该程序实现了以下功能:

  1. 读取图像并预处理: 读取输入图像,并将其转换为HSV颜色空间,以便进行颜色分割。
  2. 提取红色区域: 定义红色范围,使用inRange函数获取红色区域的掩码,并存储红色像素点的坐标。
  3. 统计红色区块: 根据红色像素点的距离,将它们分组为不同的红色区块,并计算每个区块的大小和距离最近区块的距离。
  4. 图像预处理: 将原始图像转换为灰度图像,进行高斯滤波去噪,并使用形态学操作(闭运算)连接断开的边缘。
  5. 边缘检测: 使用Canny算子进行边缘检测,提取图像中的边缘信息。
  6. 计算像素当量: 根据红色区块之间的距离和实际距离,计算出像素当量,即每个像素代表的实际长度。
  7. 霍夫圆变换: 使用HoughCircles函数进行霍夫圆变换,检测图像中的圆形孔。
  8. 计算尺寸信息: 计算检测到的圆的数量、每个圆的直径(孔径)以及外围孔圆心组成的圆的直径。
  9. 结果输出: 在图像中绘制检测到的圆,并输出计算得到的尺寸信息。

注意事项:

  • 程序中的某些参数(例如红色范围、霍夫圆变换的参数)可能需要根据实际情况进行调整。
  • 该程序假设图像中存在红色标记,用于计算像素当量。如果图像中没有红色标记,则需要使用其他方法来确定像素当量。

总结:

本文介绍了如何使用OpenCV库编写程序,实现对图像中圆形孔的自动检测和尺寸测量。该程序可以应用于各种需要进行圆形目标检测和测量的场景,例如工业自动化、医学影像分析等。

基于OpenCV的圆形孔检测与尺寸测量

原文地址: https://www.cveoy.top/t/topic/jxMa 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录