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

using namespace cv;
using namespace std;

int main()
{
    Mat img = imread('circle.jpg');

    if (img.empty())
    {
        cout << 'Could not open or find the image' << endl;
        return -1;
    }

    Mat gray;
    cvtColor(img, gray, COLOR_BGR2GRAY);

    // 阈值化
    Mat thresh;
    threshold(gray, thresh, 0, 255, THRESH_BINARY_INV + THRESH_OTSU);

    // 膨胀操作
    Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(5, 5));
    dilate(thresh, thresh, kernel);

    // 寻找圆形轮廓
    vector<vector<Point>> contours;
    findContours(thresh, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

    // 识别圆形
    vector<Point2f> centers;
    vector<float> radius;
    for (size_t i = 0; i < contours.size(); i++)
    {
        // 计算轮廓的面积
        double area = contourArea(contours[i]);

        // 过滤掉面积太小的轮廓
        if (area < 100)
            continue;

        // 拟合圆形
        Point2f center;
        float r;
        minEnclosingCircle(contours[i], center, r);

        // 判断圆心是否为黑色
        Vec3b color = img.at<Vec3b>(center);
        if (color[0] == 0 && color[1] == 0 && color[2] == 0)
        {
            centers.push_back(center);
            radius.push_back(r);
        }
    }

    // 绘制圆形和圆心
    for (size_t i = 0; i < centers.size(); i++)
    {
        circle(img, centers[i], radius[i], Scalar(0, 0, 255), 2);
        circle(img, centers[i], 3, Scalar(0, 255, 0), -1);
    }

    // 计算刻度线的长度
    double scale = 0;
    for (size_t i = 0; i < centers.size(); i++)
    {
        for (size_t j = i + 1; j < centers.size(); j++)
        {
            double dist = norm(centers[i] - centers[j]);
            if (dist > scale)
                scale = dist;
        }
    }
    scale /= 5;

    // 绘制刻度线
    for (size_t i = 0; i < centers.size(); i++)
    {
        for (size_t j = i + 1; j < centers.size(); j++)
        {
            double dist = norm(centers[i] - centers[j]);
            if (dist > scale * 0.9 && dist < scale * 1.1)
            {
                line(img, centers[i], centers[j], Scalar(255, 0, 0), 2);
                double length = dist / scale;
                putText(img, to_string(length) + 'cm', (centers[i] + centers[j]) / 2, FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 0), 2);
            }
        }
    }

    // 计算面积最大的圆的心到其他每一个圆的圆心的距离
    double max_area = 0;
    Point2f max_center;
    for (size_t i = 0; i < centers.size(); i++)
    {
        double area = CV_PI * pow(radius[i], 2);
        if (area > max_area)
        {
            max_area = area;
            max_center = centers[i];
        }
    }
    for (size_t i = 0; i < centers.size(); i++)
    {
        if (centers[i] != max_center)
        {
            double dist = norm(max_center - centers[i]) / scale;
            line(img, max_center, centers[i], Scalar(0, 255, 255), 2);
            putText(img, to_string(dist) + 'cm', (max_center + centers[i]) / 2, FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 255), 2);
        }
    }

    // 输出圆心位置和半径大小
    for (size_t i = 0; i < centers.size(); i++)
    {
        double r = radius[i] / scale;
        cout << '圆心位置:' << centers[i] << ' 半径大小:' << r << 'cm' << endl;
    }

    imshow('Result', img);
    waitKey(0);
    return 0;
}
C++ OpenCV图像处理:圆形识别、刻度测量与距离计算

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

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