一、算法原理与数学模型
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 应用
- 工业检测:调整RANSAC阈值以适应生产线速度
- 医学影像:结合先验知识约束椭圆参数范围
- 自动驾驶:实时性要求高,建议使用GPU加速
- 卫星图像:考虑地球曲率对椭圆形状的影响