【MATLAB】椭圆检测(Ellipse Detection)算法(含代码)

by 今天不飞了

圆的物体,在实际拍摄中由于种种原因可能会变成椭圆,用圆拟合就不够准确。这里分享一篇文献中椭圆检测的方法(代码使用方法)。
在这里插入图片描述

零、写在前面(2023年4月10日)

我真的……为什么评论和私信还有人问我“求出来的椭圆在哪里呀?”你们到底在看什么。2.3分明写着“输出参数说明——ellipses是目标椭圆”,不知道椭圆数学表达式的就百度”

还有问“你这个代码能计算椭圆圆心吗?”,全篇都在检测椭圆,你猜呢?不懂就问可以,但毫不思考就问,是不是有点……

一、文献与代码

  1. 下载
    Arc support Line Segments Revisited An Efficient High-quality Ellipse Detection[文献下载 ] [源码下载 ]
  2. 编译
    直接复制并修改(根据自己OpenCV和MATLAB路径版本等)
    这里假设你的文件都在D盘,OpenCV使用2.4.9版本,那么编译方式如下
% 编译C++源码供MATLAB调用
mex generateEllipseCandidates.cpp...			
    -ID:\opencv2\build\include...				% 请使用你的OpenCV路径
    -ID:\opencv2\build\include\opencv...		% 请使用你的OpenCV路径
    -ID:\opencv2\build\include\opencv2...		% 请使用你的OpenCV路径
    -LD:\opencv2\build\x64\vc11\lib...			% 请使用你的OpenCV路径
    -ID:\MATLAB\extern\include...				% 请使用你的MATLAB路径
    -LD:\MATLAB\extern\lib\win64\microsoft...	% 请使用你的MATLAB路径
    -lopencv_core249...							% 请使用你的OpenCV版本
    -lopencv_highgui249...						% 请使用你的OpenCV版本
    -lopencv_imgproc249...						% 请使用你的OpenCV版本
    -llibmwlapack.lib  
% 注意:替换的时候,不要把前面的 -I,-L,-l 删了

如果觉得麻烦,可以在文末链接直接下载。(已编译且内置动态库)

二、使用与实例

  1. 基本使用
    编译完之后就可以直接使用论文提供的测试代码LCS_ellipse.m,运行前记得修改文件路径(文件名)。
    主要函数有两个ellipseDetectionByArcSupportLSs.mdrawEllipses.m,也可以使用以下代码测试:
% 这是论文自带的图片(可替换成你自己的)
im = imread('.\pics\43.jpg'); 

% 论文检测椭圆的核心代码
[ellipses, ~, ~] = ellipseDetectionByArcSupportLSs(im, 120, 0.3, 0); % 输入输出后面会讲到

% 论文自带的显示结果的代码
drawEllipses(ellipses',im);
  1. 输入参数说明(除了第一个im,以外的三个)

Tac:椭圆完整度,测试代码如下
(为了更人性化进行了修改,可自定义颜色,如有需要文末有下载地址)

%% 第一个参数 Tac
im = imread('.\pics\test1.png');

Tacs = [90,180,190,270,300,350];
for k = 1:6
% Tr统一用0.1
[ellipses, L, posi] = ellipseDetectionByArcSupportLSs(im, Tacs(k), 0.1, 0); 

subplot(2,3,k)drawEllipses(ellipses',im,[1,0,0]); % 为了使用方便进行了修改,可自定义颜色
title(['\fontsize{14}Tac = ',num2str(Tacs(k))])
end

实验结果如下,所以当你要找的目标是比较完整时,可以将Tac调大,从而达到剔除残缺椭圆的效果;反之你的目标可能被遮挡(只露出一部分时),可以将Tac调小,以确保不漏掉任何可能。
在这里插入图片描述

Tr:椭圆边缘点数量比列系数(用于判断构成一个椭圆的点数是否足够,不代表具体的值)
举例说明,如下图左边的椭圆Tr值就小于右边的椭圆(设置合适的Tr,就能剔除左边保留右边)
在这里插入图片描述
测试代码如下

%% 第二个参数 Tr
 im = imread('.\pics\test2.jpg');
    
 Trs = [0.1,0.2,0.3,0.5,0.7,0.9];
 for k = 1:6
	 % Tac统一用30
     [ellipses, L, posi] = ellipseDetectionByArcSupportLSs(im, 30, Trs(k), 0); 
        
     subplot(2,3,k)
     drawEllipses(ellipses',im,[1,0,0]); % 为了使用方便进行了修改,可自定义颜色
     title(['\fontsize{14}Tr = ',num2str(Trs(k))])
 end

实验结果如下,大致就是Tac取得越小,找到的椭圆越多,但“假目标”也越多。
在这里插入图片描述

sp:椭圆正负性,描述椭圆内外灰度情况(正-内亮外暗,负-外暗内亮),测试代码如下

%% 第三个参数sp
if 1
    im = imread('.\pics\test3.png');
    
    sp = [1,-1,0];
    for k = 1:3
        [ellipses, L, posi] = ellipseDetectionByArcSupportLSs(im, 30, 0.2, sp(k));
        
        subplot(1,3,k)
        drawEllipses(ellipses',im,[1,0,0]); % 为了使用方便进行了修改,可自定义颜色
        title(['\fontsize{14}sp = ',num2str(sp(k))])
    end
end

实验结果如下,取1只搜索比背景亮的椭圆,反之只搜索比背景暗的椭圆,取0则全部搜索。
在这里插入图片描述

  1. 输出参数说明
    ellipses:最终目标椭圆参数
    E:优化后的边缘(仅椭圆目标)
    candidates:初始检测出的所有疑似椭圆目标(即优化前)
% 这是论文自带的图片
im = imread('.\pics\43.jpg'); 

% 论文检测椭圆的核心代码
%% 输出参数
[ellipses, E, candidates] = ellipseDetectionByArcSupportLSs(im, 120, 0.3, 0); 

% 显示结果
figure,imshow(im)
drawEllipses(ellipses',im,[1,0,0]); % 为了使用方便进行了修改,可自定义颜色
figure,imshow(E)
drawEllipses(candidates',im,[0,1,0]); % 为了使用方便进行了修改,可自定义颜色

在这里插入图片描述

三、进阶使用

有时在复杂场景下,通过调节Tac,Tr,sp也不能定位到自己想要的“椭圆”时,可以对输出数据进一步筛选。

  1. 目标尺寸(长短轴绝对大小)
    测试代码如下
    im = imread('.\pics\filt1.jpg');
    minsize = [30,40,50,60];
    for k = 1:4
        % 找到所有椭圆
        [ellipses, L, posi] = ellipseDetectionByArcSupportLSs(im, 180, 0.3, 0);
        % 找到尺寸较小的
        b = ellipses(:,4); % 短轴长
        idx = find(b<minsize(k));
        % 剔除
        ellipses(idx,:) = [];
        % 显示
        subplot(2,2,k)
        drawEllipses(ellipses',im,[1,0,0]); % 为了使用方便进行了修改,可自定义颜色
        title(['\fontsize{14}minsize = ',num2str(minsize(k))])
    end 

实验结果如下
筛选不同尺寸椭圆

  1. 目标椭度(长短轴相对大小)
    测试代码如下
    im = imread('.\pics\filt2.jpg');
    ratio = [3,2,1.2,1.05];
    for k = 1:4
        % 找到所有椭圆
        [ellipses, L, posi] = ellipseDetectionByArcSupportLSs(im, 180, 0.3, 0);
        % 找到椭度过大的
        a = ellipses(:,3);
        b = ellipses(:,4);
        idx = find(a./b>ratio(k));
        % 剔除
        ellipses(idx,:) = [];
        % 显示
        subplot(2,2,k)
        drawEllipses(ellipses',im,[1,0,0]); % 为了使用方便进行了修改,可自定义颜色
        title(['\fontsize{14}minsize = ',num2str(ratio(k))])
    end 

实验结果如下
在这里插入图片描述

  1. 目标姿态(轴位)
    测试代码如下
    im = imread('.\pics\filt3.jpg');
    axs = [pi/2,0,pi/4,-pi/4];
    for k = 1:4
        % 找到所有椭圆
        [ellipses, L, posi] = ellipseDetectionByArcSupportLSs(im, 180, 0.3, 0);
        % 找到超出指定轴位范围的
        ax = ellipses(:,5);
        idx = find(ax<axs(k)-0.3|ax>axs(k)+0.3);
        % 剔除
        ellipses(idx,:) = [];
        % 显示
        subplot(2,2,k)
        drawEllipses(ellipses',im,[1,0,0]); % 为了使用方便进行了修改,可自定义颜色
        title(['\fontsize{14}ax = ',num2str(axs(k)/pi*180),'°'])
    end 

实验结果如下
在这里插入图片描述

四、其他

  1. 所有内容基本都在文中,但最后还是分享一波源代码(与上文一致,如果确实有需要可以下载,不方便下载的可以留言我发给你)。
    含文献源码,编译好的核心代码(绿色框),修改后的绘制函数(黑色框),动态库(红色框),以及本人写的测试代码(青色框)。[CSDN下载地址]
    百度云盘链接:https://pan.baidu.com/s/1Nu0t00PxSxRTXG7BBnO_8w
    提取码:p8s0

在这里插入图片描述

  1. 关于对这个算法的理解大致:1)利用边缘提取算法获得初始边缘;2)利用边缘跟踪算法+圆弧判定条件,去除不好的边;3)根据一些限定条件,选出合适的椭圆弧并生成参数。
  2. 其他一些椭圆检测的参考文献
    A Fast and Robust Ellipse-Detection Method Based on Sorted Merging pdf
    A Fast Ellipse Detector Using Projective Invariant Pruning pdf
    A NEW EFFICIENT ELLIPSE DETECTION METHOD pdf
    Edge curvature and convexity based ellipse detection method
  3. 欢迎点赞收藏,如果有疑问或学术交流,可留言或私聊。谢谢

bilibili相关视频

  1. 椭圆检测为何失效?通过预处理提升准确度电脑端,手机端
  • 76
    点赞
  • 296
    收藏
    觉得还不错? 一键收藏
  • 235
    评论
Matlab中,可以使用图像处理工具箱中的函数来实现椭圆检测。下面简单介绍一下椭圆检测的步骤: 1. 读取待检测的图像 ``` img = imread('test.jpg'); ``` 2. 转换为灰度图像并进行高斯滤波 ``` gray_img = rgb2gray(img); blur_img = imgaussfilt(gray_img, 2); % 根据实际情况选择合适的高斯核大小 ``` 3. 进行边缘检测 ``` edge_img = edge(blur_img, 'canny'); ``` 4. 提取边缘上的点 ``` [y, x] = find(edge_img); ``` 5. 使用RANSAC算法拟合椭圆 ``` % 定义拟合椭圆的函数 fit_ellipse = @(x,y) fit_ellipse_RANSAC(x, y, 0.01); % 进行椭圆拟合 [model, inliers] = ransac([x y], fit_ellipse, 5, 1000); ``` 6. 绘制拟合结果 ``` imshow(img); hold on; plot(x(inliers), y(inliers), 'g.'); ellipse(model.a, model.b, model.phi, model.X0_in, model.Y0_in, 'r'); hold off; ``` 其中,`fit_ellipse_RANSAC`函数是自己编写的用于拟合椭圆的函数,可以参考以下代码实现: ``` function [a, b, phi, X0, Y0] = fit_ellipse_RANSAC(x, y, t) % RANSAC算法拟合椭圆 % x, y: 边缘点的坐标 % t: 拟合误差阈值 % 定义椭圆拟合函数 fit_ellipse = @(x) ellipse_error(x, [x(1) x(2) x(3) x(4) x(5)]); % RANSAC参数 k = 5; % 最小样本数 N = 1000; % 迭代次数 P = 0.99; % 置信度 n = length(x); % 样本总数 % 初始化参数 a = 0; b = 0; phi = 0; X0 = 0; Y0 = 0; best_inliers = []; for i = 1:N % 随机选择最小样本数个点 idx = randperm(n, k); sample = [x(idx) y(idx)]; % 拟合椭圆 [model, ~] = fminsearch(fit_ellipse, [mean(sample(:,1)), mean(sample(:,2)), std(sample(:,1)), std(sample(:,2)), 0]); % 计算误差 err = ellipse_error([x y], model); % 判断是否为内点 inliers = find(err <= t); % 判断是否为最优模型 if length(inliers) > length(best_inliers) best_inliers = inliers; a = model(3); b = model(4); phi = model(5); X0 = model(1); Y0 = model(2); % 更新迭代次数 N = log(1 - P) / log(1 - (length(best_inliers) / n) ^ k); end end end function err = ellipse_error(xy, model) % 计算椭圆拟合误差 % xy: 边缘点的坐标 % model: 椭圆参数 xc = model(1); yc = model(2); a = model(3); b = model(4); phi = model(5); % 坐标旋转 xp = (xy(:,1) - xc) * cos(phi) + (xy(:,2) - yc) * sin(phi); yp = (xy(:,2) - yc) * cos(phi) - (xy(:,1) - xc) * sin(phi); % 计算误差 err = ((xp / a) .^ 2 + (yp / b) .^ 2 - 1) .^ 2; end ``` 以上就是使用Matlab进行椭圆检测的基本步骤,根据具体情况可以调整参数和算法来提高检测效果。
评论 235
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值