MATLAB椭圆参数检测算法实现

一、算法原理与数学模型

1.1 椭圆的一般方程

椭圆的代数表示为:
Ax2+Bxy+Cy2+Dx+Ey+F=0Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0Ax2+Bxy+Cy2+Dx+Ey+F=0

其中约束条件:B2−4AC<0B^2 - 4AC < 0B2−4AC<0

1.2 几何参数与代数参数的转换

从代数参数 [A,B,C,D,E,F][A, B, C, D, E, F][A,B,C,D,E,F] 转换为几何参数 [xc,yc,a,b,θ][x_c, y_c, a, b, \theta][xc,yc,a,b,θ]:

xc=2CD−BEB2−4ACyc=2AE−BDB2−4ACa=2(Axc2+Cyc2+Bxcyc−F)A+C+(A−C)2+B2b=2(Axc2+Cyc2+Bxcyc−F)A+C−(A−C)2+B2θ=arctan⁡(BA−C)(注意象限)\begin{aligned} x_c &= \frac{2CD - BE}{B^2 - 4AC} \\ y_c &= \frac{2AE - BD}{B^2 - 4AC} \\ a &= \sqrt{\frac{2(Ax_c^2 + Cy_c^2 + Bx_cy_c - F)}{A + C + \sqrt{(A-C)^2 + B^2}}} \\ b &= \sqrt{\frac{2(Ax_c^2 + Cy_c^2 + Bx_cy_c - F)}{A + C - \sqrt{(A-C)^2 + B^2}}} \\ \theta &= \arctan\left(\frac{B}{A - C}\right) \quad (\text{注意象限}) \end{aligned}xcycabθ=B2−4AC2CD−BE=B2−4AC2AE−BD=A+C+(A−C)2+B2 2(Axc2+Cyc2+Bxcyc−F) =A+C−(A−C)2+B2 2(Axc2+Cyc2+Bxcyc−F) =arctan(A−CB)(注意象限)


二、MATLAB实现代码

2.1 主程序:detect_ellipse.m

matlab 复制代码
%% 椭圆参数检测主程序
% 功能:从图像中检测椭圆并返回几何参数

clear; clc; close all;

%% 1. 读取图像
img = imread('ellipse_test.jpg');  % 替换为你的图像路径
if size(img, 3) == 3
    gray_img = rgb2gray(img);
else
    gray_img = img;
end

%% 2. 预处理
processed_img = preprocess_image(gray_img);

%% 3. 边缘检测
edge_img = edge_detection(processed_img);

%% 4. 提取边缘点
[edge_points, ~] = find(edge_img);
if size(edge_points, 1) < 5
    error('边缘点不足,无法拟合椭圆!');
end

%% 5. 使用RANSAC剔除离群点
[inlier_points, outlier_points] = ransac_ellipse_fitting(edge_points, 0.1, 1000);

%% 6. 最小二乘法拟合椭圆
ellipse_params = fit_ellipse_lsq(inlier_points);

%% 7. 可视化结果
visualize_results(img, edge_img, inlier_points, outlier_points, ellipse_params);

%% 8. 输出椭圆参数
display_ellipse_parameters(ellipse_params);

2.2 图像预处理:preprocess_image.m

matlab 复制代码
function processed_img = preprocess_image(gray_img)
    % 图像预处理:去噪、增强对比度
    
    % 1. 高斯滤波去噪
    filtered_img = imgaussfilt(gray_img, 1.5);
    
    % 2. 对比度增强
    enhanced_img = imadjust(filtered_img, stretchlim(filtered_img), []);
    
    % 3. 形态学操作去除小噪声
    se = strel('disk', 2);
    cleaned_img = imopen(enhanced_img, se);
    cleaned_img = imclose(cleaned_img, se);
    
    % 4. 自适应直方图均衡化
    processed_img = adapthisteq(cleaned_img, 'ClipLimit', 0.02, 'Distribution', 'rayleigh');
end

2.3 边缘检测:edge_detection.m

matlab 复制代码
function edge_img = edge_detection(processed_img)
    % 多方法边缘检测融合
    
    % 1. Canny边缘检测
    canny_edges = edge(processed_img, 'canny', [0.1, 0.3]);
    
    % 2. Sobel边缘检测
    sobel_edges = edge(processed_img, 'sobel');
    
    % 3. Prewitt边缘检测
    prewitt_edges = edge(processed_img, 'prewitt');
    
    % 4. 融合边缘(取并集)
    edge_img = canny_edges | sobel_edges | prewitt_edges;
    
    % 5. 细化边缘
    edge_img = bwmorph(edge_img, 'thin', Inf);
    
    % 6. 去除孤立像素
    edge_img = bwareaopen(edge_img, 10);
end

2.4 RANSAC椭圆拟合:ransac_ellipse_fitting.m

matlab 复制代码
function [inlier_points, outlier_points] = ransac_ellipse_fitting(edge_points, threshold, max_iterations)
    % 使用RANSAC算法剔除离群点
    
    n_points = size(edge_points, 1);
    best_inliers = [];
    best_ellipse_params = [];
    max_inlier_count = 0;
    
    % RANSAC主循环
    for iter = 1:max_iterations
        % 1. 随机选择5个点(椭圆拟合至少需要5个点)
        if n_points < 5
            inlier_points = edge_points;
            outlier_points = [];
            return;
        end
        
        rand_indices = randperm(n_points, 5);
        sample_points = edge_points(rand_indices, :);
        
        % 2. 用这5个点拟合椭圆
        try
            ellipse_params = fit_ellipse_from_points(sample_points);
        catch
            continue;  % 拟合失败,跳过
        end
        
        % 3. 计算所有点到椭圆的距离
        distances = compute_point_to_ellipse_distance(edge_points, ellipse_params);
        
        % 4. 统计内点(距离小于阈值的点)
        inlier_mask = distances < threshold;
        inlier_count = sum(inlier_mask);
        
        % 5. 更新最佳模型
        if inlier_count > max_inlier_count
            max_inlier_count = inlier_count;
            best_inliers = edge_points(inlier_mask, :);
            best_ellipse_params = ellipse_params;
        end
    end
    
    % 如果没有找到足够的内点,返回所有点
    if isempty(best_inliers)
        best_inliers = edge_points;
        best_ellipse_params = fit_ellipse_from_points(edge_points);
    end
    
    % 分离内点和外点
    distances = compute_point_to_ellipse_distance(edge_points, best_ellipse_params);
    inlier_mask = distances < threshold;
    inlier_points = edge_points(inlier_mask, :);
    outlier_points = edge_points(~inlier_mask, :);
end

2.5 椭圆拟合核心算法:fit_ellipse_lsq.m

matlab 复制代码
function ellipse_params = fit_ellipse_lsq(points)
    % 使用最小二乘法拟合椭圆参数
    
    % 提取坐标
    x = points(:, 1);
    y = points(:, 2);
    n = length(x);
    
    % 构造设计矩阵 D = [x^2, xy, y^2, x, y, 1]
    D = [x.^2, x.*y, y.^2, x, y, ones(n, 1)];
    
    % 构造约束矩阵 C = diag([0, 0, 2, 0, 0, 0; 0, -1, 0, 0, 0, 0; 2, 0, 0, 0, 0, 0; ...
    %                       0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0]);
    C = zeros(6, 6);
    C(1, 3) = 2; C(2, 2) = -1; C(3, 1) = 2;
    
    % 求解广义特征值问题
    [~, ~, V] = svd(D' * D);
    A = V(:, end);  % 最小特征值对应的特征向量
    
    % 归一化参数
    A = A / norm(A);
    
    % 提取椭圆参数
    ellipse_params.A = A(1);
    ellipse_params.B = A(2);
    ellipse_params.C = A(3);
    ellipse_params.D = A(4);
    ellipse_params.E = A(5);
    ellipse_params.F = A(6);
    
    % 验证是否为椭圆
    discriminant = ellipse_params.B^2 - 4 * ellipse_params.A * ellipse_params.C;
    if discriminant >= 0
        error('拟合结果不是椭圆!');
    end
end

2.6 点到椭圆距离计算:compute_point_to_ellipse_distance.m

matlab 复制代码
function distances = compute_point_to_ellipse_distance(points, ellipse_params)
    % 计算点到椭圆的代数距离
    
    x = points(:, 1);
    y = points(:, 2);
    
    % 代数距离:|Ax^2 + Bxy + Cy^2 + Dx + Ey + F|
    algebraic_distance = abs(ellipse_params.A * x.^2 + ...
                           ellipse_params.B * x .* y + ...
                           ellipse_params.C * y.^2 + ...
                           ellipse_params.D * x + ...
                           ellipse_params.E * y + ...
                           ellipse_params.F);
    
    % 归一化距离
    norm_factor = sqrt(ellipse_params.A^2 + ellipse_params.B^2 + ellipse_params.C^2);
    distances = algebraic_distance / norm_factor;
end

2.7 椭圆参数转换:convert_to_geometric_params.m

matlab 复制代码
function geo_params = convert_to_geometric_params(algebraic_params)
    % 将代数参数转换为几何参数
    
    A = algebraic_params.A;
    B = algebraic_params.B;
    C = algebraic_params.C;
    D = algebraic_params.D;
    E = algebraic_params.E;
    F = algebraic_params.F;
    
    % 计算判别式
    discriminant = B^2 - 4*A*C;
    if discriminant >= 0
        error('不是椭圆!');
    end
    
    % 计算中心点
    x_center = (2*C*D - B*E) / discriminant;
    y_center = (2*A*E - B*D) / discriminant;
    
    % 计算半轴长度
    numerator = 2*(A*x_center^2 + C*y_center^2 + B*x_center*y_center - F);
    denominator1 = A + C + sqrt((A - C)^2 + B^2);
    denominator2 = A + C - sqrt((A - C)^2 + B^2);
    
    a = sqrt(numerator / denominator1);
    b = sqrt(numerator / denominator2);
    
    % 计算旋转角度
    if B == 0 && A > C
        theta = 0;
    elseif B == 0 && A < C
        theta = pi/2;
    else
        theta = atan(B / (A - C)) / 2;
        if (A - C) < 0
            theta = theta + pi/2;
        end
    end
    
    % 确保a >= b
    if a < b
        temp = a;
        a = b;
        b = temp;
        theta = theta + pi/2;
    end
    
    % 组织几何参数
    geo_params.x_center = x_center;
    geo_params.y_center = y_center;
    geo_params.major_axis = a;
    geo_params.minor_axis = b;
    geo_params.rotation_angle = theta * 180 / pi;  % 转换为度
    geo_params.area = pi * a * b;
    geo_params.eccentricity = sqrt(1 - (b/a)^2);
end

2.8 结果可视化:visualize_results.m

matlab 复制代码
function visualize_results(original_img, edge_img, inlier_points, outlier_points, ellipse_params)
    % 可视化检测结果
    
    figure('Position', [100, 100, 1400, 800]);
    
    % 1. 原始图像
    subplot(2, 3, 1);
    imshow(original_img);
    title('原始图像');
    
    % 2. 边缘图像
    subplot(2, 3, 2);
    imshow(edge_img);
    title('边缘检测结果');
    
    % 3. RANSAC结果
    subplot(2, 3, 3);
    imshow(edge_img);
    hold on;
    if ~isempty(inlier_points)
        plot(inlier_points(:, 1), inlier_points(:, 2), '.g', 'MarkerSize', 2);
    end
    if ~isempty(outlier_points)
        plot(outlier_points(:, 1), outlier_points(:, 2), '.r', 'MarkerSize', 2);
    end
    title('RANSAC结果(绿:内点,红:外点)');
    hold off;
    
    % 4. 椭圆拟合结果
    subplot(2, 3, 4);
    imshow(original_img);
    hold on;
    
    % 绘制椭圆
    draw_ellipse(ellipse_params, 'g', 2);
    
    % 绘制中心点
    plot(ellipse_params.x_center, ellipse_params.y_center, 'ro', 'MarkerSize', 10, 'LineWidth', 2);
    
    % 绘制主轴
    draw_ellipse_axes(ellipse_params, 'b--', 1);
    
    title('椭圆拟合结果');
    hold off;
    
    % 5. 参数信息
    subplot(2, 3, 5);
    axis off;
    text(0.1, 0.9, '椭圆几何参数:', 'FontSize', 12, 'FontWeight', 'bold');
    text(0.1, 0.8, sprintf('中心点: (%.1f, %.1f)', ellipse_params.x_center, ellipse_params.y_center), 'FontSize', 10);
    text(0.1, 0.7, sprintf('长轴: %.1f 像素', ellipse_params.major_axis), 'FontSize', 10);
    text(0.1, 0.6, sprintf('短轴: %.1f 像素', ellipse_params.minor_axis), 'FontSize', 10);
    text(0.1, 0.5, sprintf('旋转角: %.1f°', ellipse_params.rotation_angle), 'FontSize', 10);
    text(0.1, 0.4, sprintf('面积: %.1f 像素²', ellipse_params.area), 'FontSize', 10);
    text(0.1, 0.3, sprintf('离心率: %.3f', ellipse_params.eccentricity), 'FontSize', 10);
    title('椭圆参数信息');
    
    % 6. 误差分析
    subplot(2, 3, 6);
    if ~isempty(inlier_points)
        distances = compute_point_to_ellipse_distance(inlier_points, ellipse_params);
        histogram(distances, 20, 'FaceColor', 'blue', 'EdgeColor', 'black');
        xlabel('点到椭圆距离');
        ylabel('频数');
        title('拟合误差分布');
        grid on;
    end
end

function draw_ellipse(params, color, linewidth)
    % 绘制椭圆
    theta = linspace(0, 2*pi, 100);
    x = params.x_center + params.major_axis * cos(theta) * cosd(params.rotation_angle) ...
        - params.minor_axis * sin(theta) * sind(params.rotation_angle);
    y = params.y_center + params.major_axis * cos(theta) * sind(params.rotation_angle) ...
        + params.minor_axis * sin(theta) * cosd(params.rotation_angle);
    plot(x, y, color, 'LineWidth', linewidth);
end

function draw_ellipse_axes(params, style, linewidth)
    % 绘制椭圆主轴
    angles = [0, params.rotation_angle, 90+params.rotation_angle] * pi/180;
    lengths = [params.major_axis, params.minor_axis];
    
    for i = 1:2
        x_end = params.x_center + lengths(i) * cos(angles(i));
        y_end = params.y_center + lengths(i) * sin(angles(i));
        plot([params.x_center, x_end], [params.y_center, y_end], style, 'LineWidth', linewidth);
    end
end

2.9 参数显示:display_ellipse_parameters.m

matlab 复制代码
function display_ellipse_parameters(ellipse_params)
    % 显示椭圆参数详细信息
    
    fprintf('\n========== 椭圆检测参数报告 ==========\n');
    fprintf('检测时间: %s\n\n', datestr(now));
    
    fprintf('1. 代数参数 (Ax² + Bxy + Cy² + Dx + Ey + F = 0):\n');
    fprintf('   A = %.6f\n', ellipse_params.A);
    fprintf('   B = %.6f\n', ellipse_params.B);
    fprintf('   C = %.6f\n', ellipse_params.C);
    fprintf('   D = %.6f\n', ellipse_params.D);
    fprintf('   E = %.6f\n', ellipse_params.E);
    fprintf('   F = %.6f\n', ellipse_params.F);
    fprintf('   判别式 B²-4AC = %.6f (<0 ✓)\n\n', ellipse_params.B^2 - 4*ellipse_params.A*ellipse_params.C);
    
    fprintf('2. 几何参数:\n');
    fprintf('   中心点: (%.2f, %.2f) 像素\n', ellipse_params.x_center, ellipse_params.y_center);
    fprintf('   长轴长度: %.2f 像素\n', ellipse_params.major_axis);
    fprintf('   短轴长度: %.2f 像素\n', ellipse_params.minor_axis);
    fprintf('   旋转角度: %.2f°\n', ellipse_params.rotation_angle);
    fprintf('   椭圆面积: %.2f 像素²\n', ellipse_params.area);
    fprintf('   离心率: %.4f\n', ellipse_params.eccentricity);
    fprintf('   扁率: %.4f\n\n', 1 - ellipse_params.minor_axis/ellipse_params.major_axis);
    
    fprintf('3. 形状分析:\n');
    if ellipse_params.eccentricity < 0.1
        fprintf('   形状: 接近圆形\n');
    elseif ellipse_params.eccentricity < 0.5
        fprintf('   形状: 较圆\n');
    elseif ellipse_params.eccentricity < 0.8
        fprintf('   形状: 较扁\n');
    else
        fprintf('   形状: 很扁\n');
    end
    
    if ellipse_params.rotation_angle > 45
        fprintf('   方向: 纵向为主\n');
    else
        fprintf('   方向: 横向为主\n');
    end
    
    fprintf('========================================\n');
end

三、测试与验证

3.1 生成测试图像:create_test_image.m

matlab 复制代码
function create_test_image()
    % 创建包含椭圆的测试图像
    
    % 创建空白图像
    img = zeros(400, 600, 3, 'uint8');
    img(:,:,1) = 100;  % 灰色背景
    img(:,:,2) = 100;
    img(:,:,3) = 100;
    
    % 绘制椭圆
    center_x = 300;
    center_y = 200;
    major_axis = 150;
    minor_axis = 80;
    rotation_angle = 30;  % 度
    
    % 生成椭圆轮廓
    theta = linspace(0, 2*pi, 1000);
    x = center_x + major_axis * cos(theta) * cosd(rotation_angle) ...
        - minor_axis * sin(theta) * sind(rotation_angle);
    y = center_y + major_axis * cos(theta) * sind(rotation_angle) ...
        + minor_axis * sin(theta) * cosd(rotation_angle);
    
    % 绘制椭圆
    for i = 1:length(x)
        xi = round(x(i));
        yi = round(y(i));
        if xi > 0 && xi <= 600 && yi > 0 && yi <= 400
            img(yi, xi, :) = 255;  % 白色椭圆
        end
    end
    
    % 添加噪声
    noise = randn(400, 600, 3) * 10;
    img = uint8(double(img) + noise);
    
    % 保存图像
    imwrite(img, 'ellipse_test.jpg', 'jpg');
    fprintf('测试图像已生成: ellipse_test.jpg\n');
end

3.2 批量测试脚本:batch_test.m

matlab 复制代码
function batch_test()
    % 批量测试不同条件下的椭圆检测
    
    fprintf('开始批量椭圆检测测试...\n\n');
    
    % 测试不同噪声水平
    noise_levels = [0.01, 0.05, 0.1, 0.2];
    results = zeros(length(noise_levels), 6);
    
    for i = 1:length(noise_levels)
        fprintf('测试噪声水平: %.2f\n', noise_levels(i));
        
        % 创建带噪声的测试图像
        img = create_noisy_ellipse_image(noise_levels(i));
        
        % 运行检测
        tic;
        [ellipse_params, success] = detect_single_ellipse(img);
        elapsed_time = toc;
        
        if success
            % 计算检测精度
            true_params = [300, 200, 150, 80, 30];  % 真实参数
            detected_params = [ellipse_params.x_center, ellipse_params.y_center, ...
                             ellipse_params.major_axis, ellipse_params.minor_axis, ...
                             ellipse_params.rotation_angle];
            
            errors = abs(true_params - detected_params) ./ true_params;
            mean_error = mean(errors);
            
            results(i, :) = [noise_levels(i), elapsed_time, mean_error, ...
                           ellipse_params.major_axis, ellipse_params.minor_axis, ...
                           ellipse_params.rotation_angle];
            
            fprintf('  检测成功!平均误差: %.2f%%, 耗时: %.3f秒\n', mean_error*100, elapsed_time);
        else
            fprintf('  检测失败!\n');
            results(i, :) = [noise_levels(i), elapsed_time, 1, 0, 0, 0];
        end
    end
    
    % 显示汇总结果
    fprintf('\n========== 批量测试结果汇总 ==========\n');
    fprintf('%-12s %-12s %-12s %-12s %-12s %-12s\n', ...
            '噪声水平', '检测时间(s)', '平均误差', '长轴', '短轴', '旋转角');
    fprintf('%-12s %-12s %-12s %-12s %-12s %-12s\n', ...
            '--------', '----------', '--------', '----', '----', '------');
    
    for i = 1:size(results, 1)
        fprintf('%-12.2f %-12.3f %-11.2f%% %-12.1f %-12.1f %-12.1f\n', ...
                results(i, 1), results(i, 2), results(i, 3)*100, ...
                results(i, 4), results(i, 5), results(i, 6));
    end
end

参考代码 利用matlab写的检测椭圆参数的算法 www.youwenfan.com/contentcsu/60084.html

四、优化

4.1 算法优化

matlab 复制代码
% 1. 使用快速椭圆拟合(直接最小二乘)
function ellipse_params = fast_ellipse_fit(points)
    % 使用改进的代数距离最小化
    % 避免奇异矩阵问题
end

% 2. 多尺度检测
function multi_scale_detection(img)
    % 在不同尺度下检测椭圆
    scales = [0.5, 1.0, 2.0];
    for s = scales
        resized_img = imresize(img, s);
        detect_ellipse(resized_img);
    end
end

% 3. 并行处理
function parallel_detection(img_list)
    parfor i = 1:length(img_list)
        detect_ellipse(img_list{i});
    end
end

4.2 应用

  1. 工业检测:调整RANSAC阈值以适应生产线速度
  2. 医学影像:结合先验知识约束椭圆参数范围
  3. 自动驾驶:实时性要求高,建议使用GPU加速
  4. 卫星图像:考虑地球曲率对椭圆形状的影响
相关推荐
secondyoung1 小时前
Markdown数学公式语法速查手册
算法·编辑器·markdown·latex
福娃筱欢1 小时前
金仓数据库同步延迟告警处理步骤
数据库
君义_noip1 小时前
CSP-S 2025 提高级 第一轮(初赛) 阅读程序(1)
算法·深度优先·信息学奥赛·初赛
小O的算法实验室1 小时前
2026年IEEE TEVC,知识引导的竞争进化算法用于多解传感器-武器-目标分配问题,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
khalil10202 小时前
代码随想录算法训练营Day-46 动态规划13 | 647. 回文子串、516.最长回文子序列、动态规划总结
数据结构·c++·算法·leetcode·动态规划·回文子串·回文子序列
2301_781571422 小时前
JavaScript中Object-getOwnPropertySymbols获取方法
jvm·数据库·python
学习3人组2 小时前
柔性排产时序算法+中间过程+阶段目标 细化表格
算法·mes
he___H2 小时前
算法快与慢--哈希+双指针
算法·leetcode·哈希算法
呃呃本2 小时前
算法题(回溯)
算法