Stabilité numérique des polynômes de Zernike d'ordre supérieur

9

J'essaie de calculer des moments Zernike d' ordre supérieur (par exemple m=0, n=46) pour une image. Cependant, je rencontre un problème concernant le polynôme radial (voir wikipedia ). Il s'agit d'un polynôme défini sur l'intervalle [0 1]. Voir le code MATLAB ci-dessous

function R = radial_polynomial(m,n,RHO)
    R = 0;
    for k = 0:((n-m)/2)        
        R = R + (-1).^k.*factorial(n-k) ...
            ./ ( factorial(k).*factorial((n+m)./2-k) .* factorial((n-m)./2-k) ) ...
            .*RHO.^(n-2.*k);
    end
end

Cependant, cela se heurte évidemment à des problèmes numériques proches RHO > 0.9. Un polynôme avec beaucoup de bruit

J'ai essayé de le refactoriser en polyvalpensant qu'il pourrait avoir de meilleurs algorithmes en coulisses mais cela n'a rien résolu. Le convertir en un calcul symbolique a créé le graphique souhaité, mais était incroyablement lent, même pour un graphique simple tel que montré.

Existe-t-il un moyen numériquement stable d'évaluer de tels polynômes d'ordre élevé?

Sanchises
la source
3
Il est souvent préférable d'utiliser des polynômes orthogonaux, ici des polynômes de Jacobi . Avez-vous essayé mathworks.com/help/symbolic/jacobip.html et la relation
Rnm(r)=(-1)(n-m)/2rmP(n-m)/2(m,0)(1-2r2)?
gammatester
@gammatester Cela fonctionne! Pourriez-vous peut-être expliquer dans une réponse pourquoi cela serait le cas?
Sanchises
Bien entendu que cela fonctionne. Malheureusement, je ne peux pas donner de réponse décidée pour deux raisons. Premièrement: bien qu'il soit communément connu que les polynômes orthogonaux ont de meilleures propriétés de stabilité que la forme standard, je ne connais pas de preuve formelle (surtout dans ce cas). Deuxièmement, je n'utilise pas Matlab et ne peux pas fournir de données pour les polynômes Jacobi implémentés.
gammatester
1
@Sanchises Il n'y a pas de déjeuner gratuit ici: ce n'est pas parce que quelque chose est un polynôme que la formule directe en termes de pouvoirs est la bonne façon de le calculer, et le calcul précis des polynômes de Jacobi n'est pas en soi une question triviale - vous ne le faites pas à travers les coefficients, donc ce n'est pas aussi bon marché.
Kirill
2
La raison pour laquelle cela fonctionne pour utiliser les polynômes Jacobi est que vous vous débarrassez de l'annulation catastrophique dans votre formule (regardez tous ces facteurs oscillants avec de très grands coefficients!), Et la procédure d'évaluation par défaut du polynôme Jacobi est implémentée soigneusement dans une bibliothèque et est donc garantie pour être précis. La plupart du travail ici est fait pour s'assurer que les polynômes de Jacobi sont évalués avec précision.
Kirill

Réponses:

7

Rnm(ρ)=ρ(Rn-1|m-1|(ρ)+Rn-1m+1(ρ))-Rn-2m(ρ)

Ceci est implémenté dans le script Octave suivant:

clear                                     % Tested with Octave instead of Matlab
N = 120;
n_r = 1000;
R = cell(N+1,N+1);
rho = [0:n_r]/n_r;
rho_x_2 = 2*[0:n_r]/n_r;

R{0+1,0+1} = ones(1,n_r+1);               % R^0_0  Unfortunately zero based cell indexing is not possible
R{1+1,1+1} = R{0+1,0+1}.*rho;             % R^1_1  ==>  R{...+1,...+1} etc.
for n = 2:N,
    if bitget(n,1) == 0,                  % n is even
        R{0+1,n+1} = -R{0+1,n-2+1}+rho_x_2.*R{1+1,n-1+1};                % R^0_n
        m_lo = 2;
        m_hi = n-2;
    else
        m_lo = 1;
        m_hi = n-1;
    end
    for m = m_lo:2:m_hi,
        R{m+1,n+1} = rho.*(R{m-1+1,n-1+1}+R{m+1+1,n-1+1})-R{m+1,n-2+1};  % R^m_n
    end
    R{n+1,n+1} = rho.*R{n-1+1,n-1+1};                                    % R^n_n
end;


Z = @(m,n,rho) (-1)^((n-m)/2) * rho.^m .* jacobiPD((n-m)/2,m,0,1-2*rho.^2);
m = 22;
n = 112;
figure
plot(rho,Z(m,n,rho))
hold on
plot(rho,R{m+1,n+1},'r');
xlabel("rho")
ylabel("R^{22}_{112}(rho)")
legend("via Jacobi","recursive");
%print -djpg plt.jpg

m = 0;
n = 46;
max_diff_m_0_n_46 = norm(Z(m,n,rho)-R{m+1,n+1},inf)

m=22n=112ρ=0,7

entrez la description de l'image ici

m=0n=461.4e-10

wim
la source
Votre intrigue ressemble à un bug dans Matlab jacobiPD, pas à une annulation catastrophique générique.
Kirill
JacobiPDn=30mρ6.9e-13JacobiPDfactorial(n+a) * factorial(n+b)
m=22n=1121/(factorial(s)*factorial(n+a-s)*factorial(b+s)*factorial(n-s)) * ((x-1)/2).^(n-s).*((x+1)/2).^s * factorial(n+a) * factorial(n+b)1.4e18-2.1
1
@wim, je n'ai pas remarqué que ce n'est pas celui de Matlab. Si l'implémentation du polynôme Jacobi de quelqu'un est assez bonne pour leur objectif, ce n'est pas un problème. J'ai seulement dit que c'était un bogue parce que j'avais mal compris et pensé que c'était une fonction intégrée (je m'attends à ce que les fonctions de bibliothèque soient très solides). Par "générique", je voulais dire que si vous ne savez pas comment la fonction est implémentée, vous ne pouvez pas appeler des sorties incorrectes "annulation catastrophique" comme un terme fourre-tout pour toutes sortes d'erreurs, mais c'était juste ma mauvaise compréhension de ce que le code faisait.
Kirill
1
Pour être clair: mon code n'est pas récursif. C'est la relation de récurrence standard à trois termes itérative (similaire aux polynômes de Chebyshev) qui est censée être normalement plus stable que par exemple la forme Horner pour les polynômes.
gammatester
8

Une solution possible (suggérée par @gammatester) consiste à utiliser des polynômes de Jacobi. Ceci contourne le problème de l'annulation catastrophique en ajoutant les grands coefficients polynomiaux par évaluation polynomiale «naïve».

Le polynôme radial de Zernike peut être exprimé par les polynômes de Jacobi comme suit (voir équation (6) )

Rnm(ρ)=(-1)(n-m)/2ρmP(n-m)/2(m,0)(1-2ρ2)

Dans MATLAB cependant, l'utilisation de jacobiP(n,a,b,x)est trop lente pour les grands vecteurs / matrices de x=rho. La jacobiPfonction fait en fait partie de la boîte à outils symbolique et l'évaluation du polynôme est reportée au moteur symbolique, qui échange la vitesse contre une précision arbitraire. Une implémentation manuelle des polynômes de Jacobi est donc nécessaire.

α=mβ=0n=(n-m/2)s

Pn(α,β)(ρ)=(n+α)!(n+β)!s=0n[1s!(n+α-s)!(β+s)!(n-s)!(X-12)n-s(X+12)s]

Dans MATLAB, cela se traduit par (Jacobi p olice d ÉPARTEMENT P olynomial, ' D mise en oeuvre ouble')

function P = jacobiPD(n,a,b,x)
    P = 0;
    for  s  0:n
        P = P + ...
            1/(factorial(s)*factorial(n+a-s)*factorial(b+s)*factorial(n-s)) * ...
            ((x-1)/2).^(n-s).*((x+1)/2).^s;
    end
    P = P*factorial(n+a) * factorial(n+b);
end

Le polynôme radial de Zernike réel est donc (pour m=abs(m))

Z = @(m,n,rho) (-1)^((n-m)/2) * rho.^m .* jacobiPD((n-m)/2,m,0,1-2*rho.^2);

Remarque: cette auto-réponse n'est qu'une solution pratique; n'hésitez pas à ajouter une autre réponse qui explique pourquoi cela fonctionne.

Sanchises
la source