Разложение волнового фронта по полиномам Цернике

Sep 12, 2012 17:20

Итак, нагулявшись в отпуске я таки решил вернуться к своим баранам.
Прежде, чем начать писать что-то для разложения нормалей к волновому фронту по упомянутым раньше функциям Жао, я решил попробовать обычное разложение. Для этого с сайта mathworks был сворован исходник функции zernfun2 (которая вычисляет полиномы), а также deco (которая выполняет декомпозицию).
Функцию deco пришлось маленько подправить (она вычисляла коэффициенты на основе двойного численного интегрирования, что крайне медленно). Но получилось довольно-таки сносно.




Итак, вот что у меня получилось с декомпозицией:

% deco1.m - decomposition N=101; % dimension of coordinates grid !!!MUST be odd!!! p = 0:100; % indexes of Zernike functions to be used in the decomposition (later should determine automatically) x = linspace(-1,1,N); y = linspace(-1,1,N); [x,y] = meshgrid(x,y); % make simple equidistant coordinate grid [t,r] = cart2pol(x,y); % polar coordinates corresponding to cartesian grid idx = find(r>1); % indexes of external elements x(idx) = NaN; y(idx) = NaN; t(idx) = NaN; r(idx) = NaN; % to be on a safe side, clear bad data F = sin(x*4).*cos(y*10)/4-tan(x.^2+y.^2); %F = x.^3-y.^2; % any surface to decompose surf(x,y,F); shading interp title('Function to be decomposed'); axis square; print -dpng composed.png; close n = length(p); z = zernfun2(p,r(:),t(:),'norm'); zz = reshape(z,N,N,length(p)); for k = 1:n z = zz(:,:,k); subplot(ceil(n^.5),ceil(n^.5),k) surf(x,y,z), shading interp set(gca,'XTick',[],'YTick',[]) axis square title(['Z_' num2str(p(k))]); end print -dpng zernike.png; close fprintf("Make decomposition\n"); fflush(1); Q = []; idx = find(~isnan(F)); % indexes of inner elements for i = 1:n fprintf(1, "K = %d\n", i); fflush(1); aSum = (zz(:,:,i).*F)(idx); aNorm = (zz(:,:,i).^2)(idx); Q(i) = sum(sum(aSum)) / sum(sum(aNorm)); end fprintf("Q = "), disp(Q); fflush(1); Z = zeros(N); for k = 1:n Z=Z+Q(k)*zz(:,:,k); fprintf(1, " K = %d, std(Z-F) = %f\n", k, std((Z-F)(idx))); fflush(1); subplot(ceil(n^.5),ceil(n^.5),k) surf(x,y,Z), shading interp set(gca,'XTick',[],'YTick',[]) axis square if k==1 title(['Z_' num2str(p(k))]); else title(['Z_0 to Z_' num2str(p(k))]); end end print -dpng decompose.png; close surf(x,y,Z-F); shading interp; title('Residual error'); axis square print -dpng error.png; close
N и p - изменяющиеся параметры. Так же как и функция F.
Для начала я взял функцию F=x^3-y^2 (она на рисунке выше, функция эта и была в примере). Так как функция простая, здесь вполне хватит 16 первых полиномов. Вот они:



После разложения получилось вот что:

Каждый N-й график - это результат суммирования полиномов с 0 по N-1, помноженных на соответствующие коэффициенты.
Получилось вполне неплохо, несмотря на то, что интегрирование по сути используется методом прямоугольников. Вот - остаточная ошибка:



Теперь попробуем более сложную функцию F = sin(x*4).*cos(y*10)/4-tan(x.^2+y.^2):



Разложение по 16 полиномам получилось плохое. Коэффициенты: Q = -1.0893e+00 -1.1108e-16 1.1683e-02 -1.9055e-18 -7.3561e-01 1.5183e-15 -2.8639e-17 -1.4932e-16 6.6768e-03 -1.3585e-02 8.0573e-18 1.3411e-17 -1.1139e-01 1.6325e-16 1.6105e-02 -1.9671e-18 -4.7822e-17, среднеквадратичное отклонение:

K = 1, std(Z-F) = 0.438467 K = 2, std(Z-F) = 0.438467 K = 3, std(Z-F) = 0.438417 K = 4, std(Z-F) = 0.438417 K = 5, std(Z-F) = 0.139009 K = 6, std(Z-F) = 0.139009 K = 7, std(Z-F) = 0.139009 K = 8, std(Z-F) = 0.139009 K = 9, std(Z-F) = 0.138957 K = 10, std(Z-F) = 0.138750 K = 11, std(Z-F) = 0.138750 K = 12, std(Z-F) = 0.138750 K = 13, std(Z-F) = 0.122085 K = 14, std(Z-F) = 0.122085 K = 15, std(Z-F) = 0.122385 K = 16, std(Z-F) = 0.122385 K = 17, std(Z-F) = 0.122385

Вот такая вот вышла остаточная ошибка:



Оно и понятно: первые 16 полиномов имеют довольно низкую частоту (это как и с вейвлетами - аналогия схожая). Поэтому попробуем увеличить количество полиномов.
Увеличение до 36 ничего путного не дало: среднеквадратичное отклонение упало лишь до 0.09.
Увеличение до сотни дало лучшие результаты:



ошибка уменьшилась до 0.0288 на N=77 и возрасла до 0.0324 на N=100.

Итак, несмотря на такое огрубление вычисления коэффициентов декомпозиции, результат получается вполне приличным. Остается лишь переписать zernfun2 для вычисления "полиномов Жао".

octave, обработка изображений, цернике, волновой фронт

Previous post Next post
Up