mirror of
https://github.com/eddyem/lectures.git
synced 2025-12-06 02:35:18 +03:00
add lab for images processing
This commit is contained in:
parent
ef040e5ebd
commit
13ca4c8bc2
BIN
Komp_obr_SFedU/06_Pract.pdf
Normal file
BIN
Komp_obr_SFedU/06_Pract.pdf
Normal file
Binary file not shown.
615
Komp_obr_SFedU/06_Pract.tex
Normal file
615
Komp_obr_SFedU/06_Pract.tex
Normal file
@ -0,0 +1,615 @@
|
||||
\documentclass[a4paper,12pt]{extarticle}
|
||||
\usepackage{/home/eddy/ed, verbatim}
|
||||
\title{Практикум \No6: обработка изображений}
|
||||
\author{}\date{}\nocolon
|
||||
|
||||
\long\def\task#1{\par\noindent\leavevmode\refstepcounter{sect}\llap{\textbf{\thesect}\;}\indent\textit{#1}\par}
|
||||
\def\t#1{{\upshape\ttfamily #1}}
|
||||
|
||||
\usepackage{etoolbox}
|
||||
\makeatletter
|
||||
\preto{\@verbatim}{\topsep=2pt \partopsep=1pt} % remove big space before verbatim
|
||||
\AtEndEnvironment{verbatim}{\vspace{5pt}}
|
||||
\makeatother
|
||||
|
||||
|
||||
\begin{document}
|
||||
\maketitle
|
||||
|
||||
\section{Работа с изображениями в Octave}
|
||||
\subsection{FITS-файлы}
|
||||
Наиболее популярной утилитой просмотра FITS-файлов является \t{ds9}.
|
||||
|
||||
Для работы с обычными изображениями в Octave используются функции \t{imread}, \t{iminfo},
|
||||
\t{imshow}. Основные функции обработки изображений находятся в пакете \t{image}.
|
||||
FITS-файлы~--- пакет \t{fits}. Узнать входящие в состав пакета функции можно так:
|
||||
\begin{verbatim}
|
||||
pkg describe -verbose fits
|
||||
---
|
||||
Package name:
|
||||
fits
|
||||
Version:
|
||||
1.0.7
|
||||
Short description:
|
||||
The Octave-FITS package provides functions for reading, and writing FITS
|
||||
(Flexible Image Transport System) files. This package uses the libcfitsio library.
|
||||
Status:
|
||||
Loaded
|
||||
---
|
||||
Provides:
|
||||
Reading and writing FITS files
|
||||
read_fits_image
|
||||
save_fits_image
|
||||
save_fits_image_multi_ext
|
||||
\end{verbatim}
|
||||
|
||||
Для чтения используем \t{read\_fits\_image}:
|
||||
\begin{verbatim}
|
||||
[I H] = read_fits_image('stars.fit');
|
||||
imshow(I,[1000 4000])
|
||||
\end{verbatim}
|
||||
Необходимо указывать пороги интенсивностей для \t{imshow}. Более точно можно определить диапазоны
|
||||
из статистики по изображению:
|
||||
\begin{verbatim}
|
||||
Imin = min(I(:))
|
||||
Imin = 1321
|
||||
Imax(I(:))
|
||||
Imax = 52826
|
||||
Imean = mean2(I)
|
||||
Imean = 2054.6
|
||||
Istd = std2(I)
|
||||
Istd = 1275.5
|
||||
Imed = median(I(:))
|
||||
Imed = 2009
|
||||
Low = Imin; High = Imed + Istd;
|
||||
imshow(I, [Low High]);
|
||||
% or: imshow(I/High)
|
||||
\end{verbatim}
|
||||
Как видите, изображение повернуто вправо на $90\degr$.
|
||||
Если мы захотим отображать изображения как в оригинале, нужно заранее повернуть их:
|
||||
\begin{verbatim}
|
||||
I = rot90(I);
|
||||
imshow(I, [Low High])
|
||||
\end{verbatim}
|
||||
Следует помнить, что в Octave координаты изображения начинаются с верхнего левого угла (и ось~Y
|
||||
направлена вниз), а в стандарте FITS~--- с левого нижнего (и ось~Y направлена вверх).
|
||||
|
||||
Убедимся в этом:
|
||||
\begin{verbatim}
|
||||
I2=I;
|
||||
I2([1:100],[1:100])=65000;
|
||||
imshow(I2, [Low High]);
|
||||
\end{verbatim}
|
||||
Сравним, как отображаются координаты пикселя в ds9.
|
||||
|
||||
\subsection{Работа с гистограммой}
|
||||
Для улучшения отображения попробуем эквализовать гистограмму:
|
||||
\begin{verbatim}
|
||||
HE = histeq(I/High, 65536);
|
||||
imshow(HE);
|
||||
% compare to HE = histeq(I/High, 256);
|
||||
\end{verbatim}
|
||||
|
||||
Посмотрим, как меняется гистограмма изображения в зависимости от распределения шума.
|
||||
Сгенерируем сначала пробное изображение:
|
||||
\begin{verbatim}
|
||||
I = uint8(zeros(300,300));
|
||||
I([1:50 250:end], :) = 200;
|
||||
I([51:249], [1:30 270:end]) = 200;
|
||||
I([101:199], [100:200]) = 100;
|
||||
imshow(I)
|
||||
imhist(I)
|
||||
Iuniform = I + uint8(50*rand(size(I)));
|
||||
imshow(Iuniform)
|
||||
imhist(Iuniform)
|
||||
Inorm = I + uint8(25*randn(size(I)));
|
||||
imshow(Inorm)
|
||||
Inorm = uint8(I + 25*randn(size(I)));
|
||||
imshow(Inorm)
|
||||
imhist(Inorm)
|
||||
Ipoisson = imnoise(I, "poisson");
|
||||
imshow(Ipoisson)
|
||||
imhist(Ipoisson)
|
||||
Isaltpepper = imnoise(I, "salt & pepper", 0.2);
|
||||
imshow(Isaltpepper)
|
||||
imhist(Isaltpepper)
|
||||
Ispeckle = imnoise(I, "speckle", 0.03);
|
||||
imshow(Ispeckle)
|
||||
imhist(Ispeckle)
|
||||
\end{verbatim}
|
||||
|
||||
Сравним с эквализацией гистограммы: \t{imshow(histeq(Inorm))}.
|
||||
|
||||
Попробуем применить к изображению гамма-коррекцию:
|
||||
\begin{verbatim}
|
||||
imshow(imadjust(Iuniform, [], [], 0.5))
|
||||
imshow(imadjust(Iuniform, [], [], 5))
|
||||
\end{verbatim}
|
||||
|
||||
Теперь попробуем преобразовать яркость кусочно-линейной функцией
|
||||
$$\begin{cases}
|
||||
I_{out} = 0.2 I_{in}, & I_{in} < 70,\\
|
||||
I_{out} = 14 + 1.5 (I_{in}-70), & 70 \le I_{in} < 130, \\
|
||||
I_{out} = 209 + 0.368*(I_{in}-130),& 130\le I_{in} < 256.
|
||||
\end{cases}
|
||||
$$
|
||||
\begin{verbatim}
|
||||
Ilinhyst = zeros(size(Inorm));
|
||||
idx = find(Inorm < 70);
|
||||
Ilinhyst(idx) = 0.2*Inorm(idx);
|
||||
idx = find(Inorm >= 70 & Inorm < 130);
|
||||
Ilinhyst(idx) = 14 + 1.5*(Inorm(idx)-70);
|
||||
idx = find(Inorm >= 130);
|
||||
Ilinhyst(idx) = 209 + 0.368*(Inorm(idx)-130);
|
||||
Ilinhyst = uint8(Ilinhyst);
|
||||
imshow(Ilinhyst);
|
||||
imhist(Ilinhyst)
|
||||
\end{verbatim}
|
||||
|
||||
Попробуем сделать ступенчатое преобразование яркости: на изображении \t{Inorm} заменим все
|
||||
интенсивности в диапазоне $[50, 150]$ на 100:
|
||||
\begin{verbatim}
|
||||
Ilinhyst = Inorm;
|
||||
Ilinhyst(find(Inorm >= 50 & Inorm <= 150)) = 100;
|
||||
imshow(Ilinhyst)
|
||||
imhist(Ilinhyst)
|
||||
\end{verbatim}
|
||||
|
||||
\subsection{Фильтрация изображений}
|
||||
Попробуем простую медианную фильтрацию на примере пары изображений.
|
||||
\begin{verbatim}
|
||||
subplot(2,2,1)
|
||||
subimage(Isaltpepper)
|
||||
subplot(2,2,2)
|
||||
subimage(medfilt2(Isaltpepper, [5 5])))
|
||||
subplot(2,2,3)
|
||||
subimage(Inorm)
|
||||
subplot(2,2,4)
|
||||
subimage(medfilt2(Inorm, [5 5]))
|
||||
\end{verbatim}
|
||||
|
||||
Видим, что медианный фильтр вполне неплохо справился с шумом <<соль-перец>> и значительно хуже~---
|
||||
с гауссовым шумом.
|
||||
|
||||
Рассмотрим применение различных фильтров. Для начала создадим матрицы фильтров:
|
||||
\begin{verbatim}
|
||||
fgauss = fspecial("gaussian", 5, 1);
|
||||
flog = fspecial("log", 5, 1);
|
||||
fsobelv = fspecial("sobel");
|
||||
fsobelh = rot90(fsobelv);
|
||||
\end{verbatim}
|
||||
|
||||
И применим их к оригинальному изображению, \t{Isaltpepper} и \t{Inorm}:
|
||||
\begin{verbatim}
|
||||
imshow(imfilter(I, fgauss, "symmetric"));
|
||||
imshow(imfilter(Isaltpepper, fgauss, "symmetric"));
|
||||
imshow(imfilter(Inorm, fgauss, "symmetric"));
|
||||
imshow(histeq(imfilter(I, flog, "symmetric")));
|
||||
imshow(histeq(imfilter(Isaltpepper, flog, "symmetric")));
|
||||
imshow(histeq(imfilter(Inorm, flog, "symmetric")));
|
||||
\end{verbatim}
|
||||
|
||||
Как видите, у дифференциального фильтра отсекается отрицательная компонента~--- т.к. изображения
|
||||
имеют тип \t{uint8\_t}, однако, можно сделать так:
|
||||
\begin{verbatim}
|
||||
imshow(histeq(imfilter(double(Isaltpepper), flog, "symmetric")));
|
||||
imshow(histeq(imfilter(double(Inorm), flog, "symmetric")));
|
||||
imshow(histeq(imfilter(double(I), flog, "symmetric")));
|
||||
\end{verbatim}
|
||||
|
||||
Octave неправильно рассчитывает значение фильтров, например:
|
||||
\begin{verbatim}
|
||||
sum(flog(:))
|
||||
ans = -0.024092
|
||||
sum(fgauss(:))
|
||||
ans = 1.00000
|
||||
sum(fsobelv(:))
|
||||
ans = 0
|
||||
\end{verbatim}
|
||||
У дифференциальных фильтров сумма элементов должна быть равна нулю (чтобы константные уровни
|
||||
превращались в нуль), а у усредняющих~--- единице (чтобы сохранять среднюю интенсивность по
|
||||
изображению). Расширим размер матрицы фильтра лапласиана гауссианы, чтобы улучшить приближение к
|
||||
нулю:
|
||||
\begin{verbatim}
|
||||
flog = fspecial("log", 17, 1);
|
||||
imshow(histeq(imfilter(double(I), flog, "symmetric")));
|
||||
imshow(histeq(imfilter(double(Isaltpepper), flog, "symmetric")));
|
||||
imshow(histeq(imfilter(double(Inorm), flog, "symmetric")));
|
||||
\end{verbatim}
|
||||
Теперь на примере первого изображения мы видим, что фильтр работает правильно.
|
||||
|
||||
Горизонтальная и вертикальная компоненты градиента:
|
||||
\begin{verbatim}
|
||||
ih = imfilter(double(Inorm), fsobelh, "symmetric");
|
||||
iv = imfilter(double(Inorm), fsobelv, "symmetric");
|
||||
imshow(histeq(iv)));
|
||||
imshow(histeq(ih));
|
||||
grad = sqrt(ih.*ih + iv.*iv);
|
||||
imshow(histeq(grad));
|
||||
\end{verbatim}
|
||||
|
||||
Если мы попытаемся проделать то же самое для \t{I}, увидим, что \t{histeq} в данном случае не
|
||||
сработает, и отображать придется командой
|
||||
\begin{verbatim}
|
||||
imshow(grad,[min(grad(:)) max(grad(:))]);
|
||||
\end{verbatim}
|
||||
Здесь \t{histeq} не сработал из-за слишком <<кривой>> гистограммы: подавляющее большинство пикселей
|
||||
приходится на нулевой уровень.
|
||||
|
||||
Для смягчения общего контраста можно использовать прием, называемый <<нерезким маскированием>>
|
||||
(применяемый еще в фотографии на фотоэмульсию). Для этого воспользуемся формулой
|
||||
$$I_{out}=N\cdot I_{in} - F(I_{in}),$$
|
||||
где $F$~-- некоторый усредняющий фильтр (в оригинале~--- расфокусированное позитивное изображение).
|
||||
\begin{verbatim}
|
||||
imshow(2*Inorm-imfilter(Inorm, fgauss, "symmetric"));
|
||||
\end{verbatim}
|
||||
|
||||
Посмотрим, как изменится размытое изображение при нерезком маскировании:
|
||||
\begin{verbatim}
|
||||
ig = imfilter(I, fgauss, "symmetric");
|
||||
subplot(1,2,1)
|
||||
imshow(ig)
|
||||
subplot(1,2,2)
|
||||
imshow(histeq(2*ig-imfilter(ig, fgauss, "symmetric")))
|
||||
\end{verbatim}
|
||||
|
||||
Очистим все и вернемся к FITS-файлам. Загрузим изображение и построим дифференциальные фильтры с
|
||||
более крупным ядром:
|
||||
\begin{verbatim}
|
||||
clear
|
||||
[I H] = read_fits_image('stars.fit');
|
||||
imshow(histeq(I,65536));
|
||||
fgauss = fspecial("gaussian", 30, 5);
|
||||
flog = fspecial("log", 37, 5);
|
||||
\end{verbatim}
|
||||
|
||||
Попробуем теперь применить к изображению нерезкое маскирование и различные фильтры:
|
||||
\begin{verbatim}
|
||||
imshow(histeq(I-imfilter(I, fgauss, "symmetric"), 65536));
|
||||
imshow(histeq(imfilter(I, fgauss, "symmetric"), 65536));
|
||||
imshow(histeq(imfilter(I, flog, "symmetric"), 65536));
|
||||
imshow(histeq(2*I-imfilter(I, fgauss, "symmetric"), 65536));
|
||||
imshow(histeq(medfilt2(I), 65536));
|
||||
imshow(histeq(I-medfilt2(I, [15 15]), 65536))
|
||||
\end{verbatim}
|
||||
Последний вариант является первым приближением к вычитанию фона.
|
||||
|
||||
Посмотрим, как можно найти приближенную маску для поиска звезд:
|
||||
\begin{verbatim}
|
||||
Imed = medfilt2(I, [3 3]);
|
||||
% [3 3] is default, we can omit it here
|
||||
ImedLG = imfilter(Imed, flog, "symmetric");
|
||||
imshow(ImedLG, [-0.1, 0.1]);
|
||||
mask = logical(zeros(size(I)));
|
||||
\end{verbatim}
|
||||
|
||||
Теперь нужно подобрать подходящий пороговый уровень:
|
||||
\begin{verbatim}
|
||||
mask = logical(zeros(size(I))); mask(find(ImedLG < 0)) = 1;
|
||||
imshow(mask)
|
||||
mask = logical(zeros(size(I))); mask(find(ImedLG < -0.005)) = 1;
|
||||
imshow(mask)
|
||||
\end{verbatim}
|
||||
Уже такое грубое приближение позволило обнаружить некоторое количество звезд на изображении. Если
|
||||
использовать более точный (<<робастный>>) метод выделения фона (а здесь фон достаточно перекошен),
|
||||
получатся результаты куда лучше.
|
||||
|
||||
Отобразим оригинал, заменив нулями все точки, где маска истинна, а затем~--- наоборот:
|
||||
\begin{verbatim}
|
||||
J=I; J(mask)=0; % hide stars
|
||||
imshow(histeq(J, 65536));
|
||||
J=I; J(~mask)=0; % hide background
|
||||
imshow(J);
|
||||
\end{verbatim}
|
||||
Наша грубая маска определила все звезды, а также некоторое количество шумов, но при помощи
|
||||
морфологических операций мы можем удалить мелкие объекты (правда, не факт, что не потеряем таким
|
||||
образом слабые звезды; кроме того, мы видим на первом изображении, что особо яркие звезды
|
||||
маскированы не полностью, наш способ достаточно плох и годится лишь для очень грубой астрометрии).
|
||||
|
||||
\subsection{Морфологические операции, поиск связных областей}
|
||||
Попробуем подчистить немного нашу маску.
|
||||
\begin{verbatim}
|
||||
imshow(imopen(mask, strel('disk', 1, 0)));
|
||||
imshow(imopen(mask, strel('disk', 2, 0)));
|
||||
imshow(imopen(mask, strel('disk', 3, 0))); % use this
|
||||
mask = imopen(mask, strel('disk', 3, 0));
|
||||
\end{verbatim}
|
||||
|
||||
Теперь можем аналогично просмотреть маскированные изображения:
|
||||
\begin{verbatim}
|
||||
J=I; J(mask)=0; % hide stars
|
||||
imshow(histeq(J, 65536));
|
||||
J=I; J(~mask)=0; % hide background
|
||||
imshow(J);
|
||||
\end{verbatim}
|
||||
|
||||
Но нам интересней выделить все звезды из изображения. Используем поиск связных областей:
|
||||
\begin{verbatim}
|
||||
[L NUM]= bwlabel(mask, 8);
|
||||
NUM
|
||||
NUM = 200
|
||||
imshow(L, [1 NUM])
|
||||
\end{verbatim}
|
||||
Как видим, нумерация объектов идет слева-направо, сверху-вниз. Чтобы выделить конкретный объект, мы
|
||||
можем применить маску такого типа:
|
||||
\begin{verbatim}
|
||||
J = zeros(size(I)); idx = find(L == 100); J(idx) = I(idx);
|
||||
imshow(J);
|
||||
\end{verbatim}
|
||||
Мы выделили одну звезду. Можем выделить тонкую полоску фона вокруг нее:
|
||||
\begin{verbatim}
|
||||
mask100 = logical(zeros(size(I)));
|
||||
mask100(idx) = 1;
|
||||
mask100 = xor(imdilate(mask100, strel('disk',2,0)), mask100);
|
||||
imshow(mask100);
|
||||
\end{verbatim}
|
||||
|
||||
И посчитать по ней статистику:
|
||||
\begin{verbatim}
|
||||
bg100 = I(mask100);
|
||||
mean(bg100)
|
||||
ans = 2063.1
|
||||
std(bg100)
|
||||
ans = 61.711
|
||||
\end{verbatim}
|
||||
|
||||
Но для вычисления положений центроидов удобней использовать другую функцию поиска связных областей:
|
||||
\t{bwconncomp}.
|
||||
\begin{verbatim}
|
||||
K = bwconncomp(mask, 8);
|
||||
p = regionprops(K);
|
||||
\end{verbatim}
|
||||
По умолчанию в \t{p} (это~--- массив структур) содержатся поля \t{Area} (площадь объекта),
|
||||
\t{BoundingBox} (координаты бокса, в котором содержится объект: левый верхний угол и размер) и
|
||||
\t{Centroid} (геометрический центр объекта). По первым двум параметрам мы можем отфильтровать
|
||||
слишком мелкие и слишком крупные объекты, а также объекты, у которых отношение ширины к высоте
|
||||
сильно отличается от единицы (т.е. там внутри~--- явно не круг). Третий параметр позволяет судить
|
||||
о примерном расположении центра объекта (более точно, конечно, мы можем вычислить его лишь взяв
|
||||
данные с оригинального изображения, вычтя фон и посчитав точный центроид).
|
||||
|
||||
Можно нарисовать несколько боксов:
|
||||
\begin{verbatim}
|
||||
rectangle('Position', p(1).BoundingBox, 'EdgeColor','g','LineWidth',2)
|
||||
rectangle('Position', p(3).BoundingBox, 'EdgeColor','g','LineWidth',2)
|
||||
rectangle('Position', p(100).BoundingBox, 'EdgeColor','g','LineWidth',2)
|
||||
\end{verbatim}
|
||||
|
||||
\begin{verbatim}
|
||||
centroids = cat(1, p.Centroid);
|
||||
plot(centroids(:,1), centroids(:,2), 'ko');
|
||||
\end{verbatim}
|
||||
|
||||
Теперь сравним координаты центроида изображения звезды с координатами центроида маски. Обратите
|
||||
внимание, что \t{BoundingBox} имеет координаты <<с половинками>>:
|
||||
\begin{verbatim}
|
||||
p(100).BoundingBox
|
||||
502.500 710.500 14.000 14.000
|
||||
imshow(mask100);
|
||||
rectangle('Position', p(100).BoundingBox, 'EdgeColor','g','LineWidth',2)
|
||||
\end{verbatim}
|
||||
Это связано с тем, что при отображении изображений целым координатам соответствует центр пикселя.
|
||||
Контур, описывающий нашу область интереса, не должен пересекать пиксели, из-за этого координаты его
|
||||
левого угла на 0.5\,пикселя меньше, а ширина~--- на 1\,пиксель больше.
|
||||
Следовательно, для того, чтобы получить часть изображения, содержащую только пиксели зоны интереса,
|
||||
нам нужно будет сделать преобразование:
|
||||
\begin{verbatim}
|
||||
Bstart = p(100).BoundingBox(1:2) + 0.5;
|
||||
Bsize = p(100).BoundingBox(3:4) - 1;
|
||||
rectangle('Position', [Bstart Bsize], 'EdgeColor','r','LineWidth',2);
|
||||
\end{verbatim}
|
||||
Теперь наш бокс включает все пиксели изображения звезды. Вычислим суммарный поток и центроид:
|
||||
\begin{verbatim}
|
||||
bg = mean(bg100); % mean background
|
||||
[y x] = ind2sub(size(I), idx);
|
||||
% coordinates of pixels in mask of 100th star
|
||||
M = sum(I(idx)) - numel(idx)*bg
|
||||
% energy in circle
|
||||
M = 55148.54545
|
||||
xc=0; yc=0; for n=1:numel(x); i=I(idx(n))-bg; xc+=i*x(n); yc+=i*y(n);
|
||||
printf("%d(%d,%d)\n",i,x(n),y(n)); endfor; xc/=M; yc/=M;
|
||||
xc
|
||||
% X centroid position
|
||||
xc = 509.36
|
||||
yc % Y centroid position
|
||||
yc = 718.41
|
||||
p(100).Centroid
|
||||
% centroid by mask
|
||||
ans =
|
||||
509.63 717.57
|
||||
imshow(histeq(I, 65536)); % take a look at real image
|
||||
% real centroid:
|
||||
rectangle('Position', [xc-1 yc-1 2 2], 'EdgeColor','g','LineWidth',2,
|
||||
"Curvature", 1)
|
||||
% centroid of mask:
|
||||
rectangle('Position', [p(100).Centroid-1 2 2], 'EdgeColor','r','LineWidth',2,
|
||||
"Curvature", 1)
|
||||
\end{verbatim}
|
||||
|
||||
Мы видим, что настоящий центр тяжести изображения звезды достаточно сильно отличается от
|
||||
геометрического центра маски. Особенно сильно это проявляется в случае деформаций изображения
|
||||
(вследствие сдвига изображения, комы или прочих аберраций).
|
||||
|
||||
Вычислять большое количество характеристик удобней иначе. Например, так:
|
||||
\begin{verbatim}
|
||||
regioninfo = regionprops(L,I,'MajorAxisLength','MinorAxisLength','PixelIdxList',
|
||||
'PixelValues');
|
||||
\end{verbatim}
|
||||
мы получим значения большой и малой полуосей эллипса с идентичными нашей фигурой моментами (что
|
||||
позволит судить о <<круглости>> каждого объекта), список индексов пикселей и список интенсивностей
|
||||
пикселей на изображении. Если бы фон у нашего объекта был идеально гладким, можно было бы добавить
|
||||
еще свойство \t{'WeightedCentroid'}, чтобы сразу получить координаты центра каждой звезды, но, увы,
|
||||
для каждой звезды придется считать фон аналогично вышесказанному~--- через кольца. Для тесных полей
|
||||
потребуется убедиться, что зона вокруг звезды свободна от другой звезды (при помощи все тех же
|
||||
морфологических операций).
|
||||
|
||||
Аргументом \t{regionprops} может выступать и структура, полученная при помощи \t{bwconncomp}.
|
||||
|
||||
Теперь найдем все объекты более-менее круглой формы:
|
||||
\begin{verbatim}
|
||||
roundness = [regioninfo.MajorAxisLength] ./ [regioninfo.MinorAxisLength];
|
||||
staridx = find(roundness < 1.1 & roundness > 0.9);
|
||||
% indexes of "stars"
|
||||
imshow(ismember(L, staridx)); % show filtered image
|
||||
\end{verbatim}
|
||||
|
||||
Теперь, если пройтись итеративно по каждому объекту с номером \t{staridx}, можно посчитать для него
|
||||
индивидуальную маску фона (как было показано выше~--- через дилатацию), определить таким образом
|
||||
уровень фона и использовать его для вычисления прочих параметров: полной интенсивности внутри маски
|
||||
и координат центроида.
|
||||
|
||||
Если мы добавим в \t{regionprops} свойство \t{'Area'}, у нас появится возможность до получения
|
||||
номеров объектов, возможно являющихся звездами, отсортировать их по убыванию площади (скорей
|
||||
всего~--- и по убыванию яркости):
|
||||
\begin{verbatim}
|
||||
[~, i] = sort([regioninfo(staridx).Area], 'descend'); % get sorted indexes
|
||||
staridxsorted = staridx(i);
|
||||
\end{verbatim}
|
||||
И можем отобразить окрестности первых 10 по площади маски:
|
||||
\begin{verbatim}
|
||||
imshow(histeq(I, 65536));
|
||||
for i=1:10;
|
||||
c = hsv2rgb([i/10. 1 1]);
|
||||
rectangle('Position', p(staridxsorted(i)).BoundingBox, 'EdgeColor', c,
|
||||
'LineWidth',2);
|
||||
endfor
|
||||
for i = 1:10; ltxt{i} = sprintf("star #%d", i); endfor
|
||||
legend(ltxt)
|
||||
\end{verbatim}
|
||||
Видим, что у ярких звезд маска потеряла приличную часть крыльев, а также одна достаточно яркая
|
||||
звезда была пропущена.
|
||||
Более надежным будет отсортировать по значению интенсивности.
|
||||
|
||||
\section{Первичная обработка снимков}
|
||||
Наиболее распространенными светоприемниками в астрофизике оптического диапазона являются
|
||||
ПЗС-матрицы. Среди прочих светоприемников этого диапазона они имеют наилучшие характеристики.
|
||||
Однако, есть у них и недостатки: в тонких подложках возможна интерференция (особенно ближе к
|
||||
ИК-диапазону), приводящая к возникновения <<фрингов>>; а наличие хотя бы одного очень яркого
|
||||
источника приводит к <<растеканию заряда>>, усугубляющемуся при считывании изображения.
|
||||
КМОП-светоприемники в значительной мере избавлены от проблем растекания заряда, но в них есть
|
||||
другая проблема: каждый пиксель по сути снабжен собственным усилителем, в результате точная
|
||||
фотометрия с КМОП превращается в сплошной ад!
|
||||
|
||||
Процесс получения изображений на ПЗС можно в упрощенном виде свести к формуле:
|
||||
$$ ADU_{x,y}= \gamma F_{x,y}(e_{x,y} + D_{x,y})T + B_{x,y} + R,$$
|
||||
(здесь опущен процесс дискретизации, растекания заряда и т.п.), где $ADU$~-- отсчеты, считанные с
|
||||
пикселя с координатами $(x,y)$; $\gamma$~-- <<gain>>, коэффициент преобразования фотоэлектронов в
|
||||
$ADU$ (зависит от длины волны излучения); $F$~-- поглощение излучения вследствие неидеальности
|
||||
оптической системы (компенсируется делением на <<плоские поля>>); $e$~-- количество фотоэлектронов,
|
||||
возникших при попадании кванта в данную ячейку (зависит от длины волны), оно зашумляется множеством
|
||||
факторов: фотонным шумом, турбулентностью атмосферы и т.д., и т.п.; $D$~--
|
||||
<<темновой ток>>, определяющийся электронами, возникающими в результате тепловых процессов в теле
|
||||
полупроводника; $B$~-- <<bias>>, начальное смещение (даже при нулевой экспозиции~--- собственно,
|
||||
так кадры <<bias>> и получают) для устранения нелинейности; $T$~-- время накопления сигнала
|
||||
(экспозиция); $R$~-- шум считывания.
|
||||
|
||||
Избавиться от шума считывания невозможно, однако, как мы помним, если усреднить $N$~кадров, то
|
||||
$R$~уменьшится в $\sqrt{N}$~раз. Кроме того, чем больше экспозиция, тем большим будет вклад прочих
|
||||
шумов. Однако, при малых экспозициях может проявляться <<эффект затвора>>, вызванный тем, что время
|
||||
открывания\slash закрывания затвора конечно.
|
||||
|
||||
Чтобы скорректировать интенсивность на уровень смещения, мы можем сделать как можно больше кадров с
|
||||
нулевой экспозицией (<<bias>>), получить медиану стопки изображений и вычесть из изображения. При
|
||||
этом шум bias'а также будет уменьшен в $\sqrt{N}$~раз.
|
||||
|
||||
Для коррекции на тепловой шум нам необходимо накопить как можно больше <<дарков>> (в идеале их
|
||||
экспозиция должна быть такой же, как экспозиция кадра данных, а условия должны быть абсолютно
|
||||
такими же: температура чипа, окружающей среды и т.д., и т.п.). При закрытом затворе мы получим:
|
||||
$$ ADU_{x,y}= \gamma D_{x,y}T + B_{x,y} + R,$$
|
||||
т.е. <<автоматически>> сюда же включен уровень смещения. Следовательно, если наши <<дарки>> имеют
|
||||
ту же самую экспозицию, что и основной научный кадр, то для удаления тепловых шумов достаточно
|
||||
вычесть медианное усреднение стопки <<дарков>> из нашего кадра. Однако, не всегда это возможно:
|
||||
скажем, при получении спектра высокого разрешения экспозиция может длиться несколько часов!
|
||||
Естественно, мы не можем получить даже десятка темновых кадров с такой экспозицией (т.к. и условия
|
||||
поменяться успеют, и начнется новая ночь). В подобных случаях прибегают к хитрости: темновой ток
|
||||
пропорционален времени экспозиции. Это означает, что можно сделать несколько серий коротких
|
||||
экспозиций (скажем, одна, пять, десять и двадцать минут) в течение дня, а затем экстраполировать их.
|
||||
Вот в этом случае для получения такого <<искусственного дарка>> необходимо будет, помимо всех
|
||||
остальных кадров, снимать еще и bias'ы. Для каждой экспозиции~$T$ мы вычисляем темновой ток как
|
||||
$D_T=M(D_{Ti})-M(B_i)$, где $M$~-- медиана. При помощи линейной экстраполяции мы получаем
|
||||
значение~$D$ для заданной экспозиции. Но т.к. это значение уже избавлено от смещения, для коррекции
|
||||
нам необходимо будет из изображения вычесть не только~$D$, но и~$B$!
|
||||
Это~--- единственный случай, когда нам необходимо будет получить и стопку кадров смещения (как
|
||||
говорилось выше, если <<темновые>> сняты с той же экспозицией, что и основной кадр, то смещение
|
||||
автоматически корректируется при вычитании <<темновых>> из <<объекта>>).
|
||||
|
||||
Значительно более сложной является коррекция на неоднородности оптической системы (вплоть до
|
||||
пылинок на фильтрах и прочих оптических поверхностях), $F$. Термин <<плоскость>> в данном случае
|
||||
носит двоякий смысл: для прямых снимков это~--- неоднородность освещенности по кадру. Для
|
||||
спектральных~--- еще и неоднородность кривой спектральной чувствительности. Отвлечемся пока от
|
||||
спектроскопии. Основными факторами, искажающими интенсивность объектов в кадре, являются
|
||||
виньетирование (экранирование боковых пучков апертурой оптического тракта) и прочие неоднородные
|
||||
свойства оптических систем. В идеальной ситуации для компенсирования~$F$ нам необходимо получить
|
||||
снимок абсолютно однородно засвеченного протяженного объекта с угловыми размерами, значительно
|
||||
превосходящими поле зрения нашей оптической системы. В случае телескопов с малым полем зрения для
|
||||
данных целей хватает вечерних или утренних снимков неба при максимально рассеянном солнечном свете
|
||||
во время гражданских сумерек. При большом поле зрения необходимо использовать специальные источники
|
||||
света с как можно более равномерным освещением. После получения <<плоских>> кадров следует
|
||||
вычислить медиану из их стопки, вычесть <<темновые>>, затем нормировать на максимум
|
||||
интенсивности, а далее~--- разделить подготовленный (с вычетом <<темновых>>) научный кадр на
|
||||
полученное изображение. При этом мы
|
||||
получаем:
|
||||
$$I_{x,y} = \frac{\gamma F_{x,y}e_{x,y}T + R}{\gamma F_{x,y}T + R}\approx e_{x,y}T.$$
|
||||
Конечно, <<плоские>> кадры мы можем снимать с любой подходящей экспозицией. Но для коррекции на
|
||||
темновые токи, если экспозиция <<плоских>> отличается от экспозиции <<научных>> кадров, нам
|
||||
необходимо будет сделать еще один набор <<темновых>>.
|
||||
|
||||
Как пример медианного усреднения стопки изображений, сгенерируем зашумленные изображения (можно
|
||||
использовать и \t{awgn}):
|
||||
\begin{verbatim}
|
||||
for N=1:10; II(:,:,N) = I+100*randn(size(I)); endfor
|
||||
imshow(histeq(II(:,:,2),65536))
|
||||
\end{verbatim}
|
||||
|
||||
Подобным образом формируются на ПЗС реальные изображения (разве что шумы мы несколько
|
||||
преувеличили). Именно из-за шумов для получения качественных кадров dark и flat необходимо сделать
|
||||
их как можно больше! После чего стопка изображений усредняется:
|
||||
\begin{verbatim}
|
||||
Imed = median(II, 3);
|
||||
subplot(2,2,1)
|
||||
imshow(histeq(II(:,:,2),65536))
|
||||
subplot(2,2,2)
|
||||
imshow(histeq(II(:,:,5),65536))
|
||||
subplot(2,2,3)
|
||||
imshow(histeq(Imed,65536))
|
||||
subplot(2,2,4)
|
||||
imshow(histeq(I,65536))
|
||||
\end{verbatim}
|
||||
|
||||
Даже для шума такого уровня мы приблизились к оригиналу достаточно неплохо всего-то на десяти
|
||||
изображениях. Если же их сделать хотя бы сотню, восстановление будет еще лучше. А учитывая то, что
|
||||
медианный фильтр хорошо удаляет выбросы, такой способ отлично очищает опорные кадры от космических
|
||||
частиц.
|
||||
|
||||
И для изображений объекта мы можем выполнять подобные манипуляции для снижения шума каждого
|
||||
$e_{x,y}$. Но, в этом случае процесс
|
||||
восстановления будет намного сложней, т.к., во-первых, телескоп имеет неидеальное сопровождение (и
|
||||
объекты не только немного <<размазываются>>, но еще и смещаются от экспозиции к экспозиции);
|
||||
во-вторых, в процессе получения изображений могут изменяться условия (seeing, температура и пр.), в
|
||||
результате чего PSF изображений также будет меняться (следовательно, придется сделать некоторую
|
||||
деконволюцию и приведение изображения к единой координатной системе, а это чревато ошибками
|
||||
интерполяции).
|
||||
|
||||
\section{Задание для самостоятельного выполнения}
|
||||
В данных к заданию содержатся кадры object, dark и flat. Выполните следующее.
|
||||
\begin{enumerate}
|
||||
\item Из <<научных>> кадров выберите один с наилучшим качеством изображений.
|
||||
\item Вычислите медианные значения темновых и плоских, получите нормированное изображение.
|
||||
\item Подберите подходящий фильтр, который позволит получить маску, выделяющую изображения звезд.
|
||||
\item Подготовьте m-файлы для выполнения рутинных операций: вычисления маски кольца фоновых
|
||||
пикселей, определения уровня фона, освещенности от звезды и координат ее центроида.
|
||||
\item Отсортируйте маски по уменьшению площади, для дальнейших вычислений используйте первые
|
||||
пятьсот.
|
||||
\item Вычислите освещенности от звезд в пределах полученных масок. Отсортируйте по уменьшению
|
||||
освещенности. Выберите первые 20.
|
||||
\item Выполните астрометрию для этих самых ярких звезд кадра, получив координаты~$(x,y)$ центроидов.
|
||||
\item Проверьте полученные величины (преобразуйте ADU в звездные величины и проведите нормировку на
|
||||
стандартные объекты из каталогов; для координат центроидов учтите, что изображения повернуты на
|
||||
$90\degr$ и ось~$Y$ направлена вниз) по каталогам. Определите погрешность своих расчетов (звездных
|
||||
величин и координат).
|
||||
\end{enumerate}
|
||||
Для определения каталожных величин воспользуйтесь aladin, xephem, stellarium (и т.п.) или on-line
|
||||
сервисами каталогов. Преобразовать координаты~$(x,y)$ на изображении в $(\alpha, \delta)$ можно при
|
||||
помощи утилиты \t{xy2sky} из пакета \t{wcstools} (либо при помощи \t{ds9}). Не забывайте о
|
||||
собственных движениях звезд: координаты из каталога (в т.ч. те, которыми мы можем воспользоваться в
|
||||
\t{ds9}) привязаны к эпохе J2000, а с тех пор прошло уже два десятилетия.
|
||||
\end{document}
|
||||
4690
Komp_obr_SFedU/Materials4Pract/06/stars.fit
Normal file
4690
Komp_obr_SFedU/Materials4Pract/06/stars.fit
Normal file
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user