matlab離散點擬合二維橢圓的時候,主要有兩種方法,一種是使用boundary函數拾取邊界點,直接擬合,一共五個參數,使用matlab的regress就可以,公式如下:
但是這種方法有一些缺點,就是在由於參數過多,擬合垂直情況和系數相差過大的異常橢圓情況會誤差會比較大,因此一般使用第二種方法,即將原始的離散點通過使用旋轉和平移變化移動到長軸和x軸重合,以原點為中心,最后通過平面變換回去,由於少了b,d,e三項,擬合的精度會好很多,可以解決一些過於扁平的離散點的橢圓擬合,但是這里面會遇到一個很重要的問題就是如何計算旋轉角,即通過離散點計算橢圓軸的傾角,由於不是一個一一對應的函數,所以計算起來會有些困難,這里參考http://mathworld.wolfram.com/Ellipse.html的計算方法,公式如下
代碼如下:
%% 測試驗證橢圓形的隨機離散方法 % 按照文獻中所給算法,但是感覺不准 for anglex=0:pi/90:2*pi % 常規方法生成 a=20;b=5; num=400; x1=-a+2*a*rand(num,1); y1=-b+2*b*rand(num,1); xs=[];ys=[]; for i=1:length(x1) if (x1(i)^2/a^2+y1(i)^2/b^2)<=1 xs=[xs;x1(i)];ys=[ys;y1(i)]; hold on end end plot(xs,ys,'y*'); %% 生成經過平移和旋轉的離散點 deltax=3;deltay=6;tx=anglex; pingyi=[1 0 deltax;0 1 deltay;0 0 1]; xuanzhuan=[cos(tx) -sin(tx) 0;sin(tx) cos(tx) 0;0 0 1]; %逆時針旋轉一定的角度 rota_xsys=pingyi*xuanzhuan*[xs';ys';ones(size(xs'))]; xs=rota_xsys(1,:);ys=rota_xsys(2,:); % scatter(x1,y1,'filled'); plot(xs,ys,'b*'); axis equal hold on %% 橢圓點邊界點擬合--顯然更加准確 kp=boundary(xs',ys',0.1); xs1=[xs(kp)]';ys1=[ys(kp)]'; plot(xs1,ys1,'r'); [pxf,~,rp]=regress(-ones(size(xs1)),[xs1.^2 xs1.*ys1 ys1.^2 xs1 ys1]); a=pxf(1);b=pxf(2);c=pxf(3);d=pxf(4);e=pxf(5); xc=(b*e-2*c*d)/(4*a*c-b^2);yc=(b*d-2*a*e)/(4*a*c-b^2); %中心 la=sqrt(2*(a*xc^2+c*yc^2+b*xc*yc-1)/(a+c+sqrt((a-c)^2+b^2))); %長半軸 lb=sqrt(2*(a*xc^2+c*yc^2+b*xc*yc-1)/(a+c-sqrt((a-c)^2+b^2))) ;%短半軸 if la<=lb lx=la; la=lb; lb=lx; end theta=linspace(0,2*pi,100); xb=la*sin(theta);yb=lb*cos(theta); plot(xb,yb,'g*'); %% 求橢圓的傾角 if b==0 && abs(a)<abs(c) rota=0; disp(['角度1=' num2str(rota)]) elseif b==0 && abs(a)>abs(c) rota=pi/2; disp(['角度2=' num2str(rota)]) elseif b~=0 && abs(a)<abs(c) ex=1/2*acot((a-c)/b); rota=ex; rotax=rota*180/pi; disp(['角度3=' num2str(rotax)]) elseif b~=0 && abs(a)>abs(c) ex=1/2*acot((a-c)/b); rota=pi/2+ex; rotax=rota*180/pi; disp(['角度4=' num2str(rotax)]) end % disp(['角度' num2str(rotax)]) xuanzhuan=[cos(rota) -sin(rota) 0;sin(rota) cos(rota) 0;0 0 1]; pingyi=[1 0 xc;0 1 yc;0 0 1]; rota_xy=pingyi*xuanzhuan*[xb; yb;ones(size(xb))]; % rota_xy=[xc 1;1 yc]*[cos(rota) sin(rota);-sin(rota) cos(rota)]*[xb;yb]; %旋轉平移過去 xf1=rota_xy(1,:);yf1=rota_xy(2,:); % zf1=(df-af.*xf1-bf.*yf1)./cf; % fs=[xf1' yf1' zf1']; hold on plot(xf1,yf1,'k-'); title(['角度=' num2str(anglex*180/pi)]); pause(1); drawnow clf end
測試了360個角度的計算,擬合的橢圓和離散點符合地都比較好。