======= Cvičení 3 : Registrace ======= Na třetím cvičení se budeme zabývat registrací obrazů. Ta je potřebná ve chvíli, kdy máme dva obrázky I, J (např. rozdílné modality, rozdílné časy vytvoření snímku, apod.) a chceme informace z těchto dvou vstupů spojit dohromady. Cílem je tedy nalézt transformaci T, která převede obrázek J na obrázek I s co nejlepším možným překryvem. Na cvičení budeme pracovat s matlabem a vyzkoušíme si jak manuální, tak i automatickou registraci různých obrázků. ===== Zadání ===== * [[#Landmark registration]] Pracujte s dvojicí obrázků ''histology.HEstain'' a ''histology.PanCytokeratin'', které zobrazují skoro identický řez ve dvou různých barveních (Hematoxylin+Eosin a Cytokeratin). Určete dostatečný počet kontrolních bodů a nejděte co možno nejlepší transformaci. Vyzkoušejte alespoň dvě transformace, ukažte výsledek a diskutujte volbu transformace, rozmístění kontrolních bodů ve zprávě [1b] * [[#Automatic registration]] Máme k dispozici dva MRI snímky (stejného pacienta) - ''T1.nii'' a ''FLAIR.nii'', a dále segmentaci lézí na snímku FLAIR - obrázek ''LesionSeg.nii''. Spočítejte použitím automatické registrace transformaci snímku FLAIR na snímek T1 a touto pak přetransformujte snímek segmentací. [2b] Spočtěte histogram intenzit snímku T1 přes segmentované oblasti. [BONUS +1b] * [[#Deformable registration]] Zde máme dva MRI snímky kolene od různých pacientů - ''58_MRI.nii'' a ''64_MRI.nii''. Spočítejte použitím automatické registrace transformaci snímku 64 na snímek 58. Protože se jedná o dvě rozdílné anatomie, musíme použít metodu pružné a konzistentní deformace, abychom dosáhli rozumného zarovnání. [2b] ==== Data, funkce ==== Vstupní data a pomocné funkce pro načítání a zobrazování jsou ke stažení jako {{:courses:a6m33zsl:cviceni_3.zip |ZIP Archiv}}. V archivu je adresář ''registration_images'' a ''cv3_matlabfun''. Po rozbalení je potřeba přidat adresář ''cv3_matlabfun'' v Matlabu (//add path//), pak jsou funkce dostupné. * Načítání obrázků fixed = imread('registration_images/brain.t1.png'); * Načítání 3D obrázků funguje za pomocí metody ''load_nii'' image1 = load_nii('58_MRI.nii'); fixed = image1.img; Funkce vytvoří struct image1, pod ''image1.img'' se pak nachází obrazová data. * Zobrazení dvou obrázků {{https://www.mathworks.com/help/images/ref/imshowpair.html|imshowpair}} figure, imshowpair( m_poly, fixed ); pro 3D obrázky si lze buď zobrazit n-tou vrstvu pomocí ''image(:,:,n)'' nebo použijte metodu ''imshow3D'' z přiloženého balíčku pomocných funkcí. imshow3D(moving, fixed, 'montage', 1); Parametry funkce ''imshow3D'' jsou dva obrázky, které chceme zobrazit, dále metoda překryvu ''montage|falsecolor|blend'' a jako poslední dimenze, kterou chceme zobrazit. ===== Landmark registration ===== Registrace pomocí kontrolních bodů je jednou ze základních poloautomatických metod. Začneme tím, že ručně určíme páry bodů (x_i, y_i), i=1, \ldots N pro významné pozice, které lze identifikovat v obou obrázcích a pak hledáme transformaci T, která minimalizuje vzdálenost x_i a T(y_i) . === Postup === - Spustíme interaktivní rozhraní {{https://www.mathworks.com/help/images/ref/cpselect.html|cpselect}} pro definici kontrolních bodů h = cpselect(moving, fixed); - Před zavřením dialogového okna je potřeba uložit páry bodů do souborů, např ''fixedPoints'' a ''movingPoints'' - S těmito množinami bodů pak pracujeme dále a hledáme optimální transformaci pomocí {{https://www.mathworks.com/help/images/ref/fitgeotrans.html|fitgeotrans}} t_sim = fitgeotrans(movingPoints, fixedPoints, 'similarity'); Typ transformace (v příkladu ''similarity'') je závislý na vstupních datech, možné další třídy transformací jsou v uvedené v dokumentaci - Nakonec transformujeme ''moving'' image spočtenou transformací m_sim = imwarp(moving, t_sim, 'OutputView', imref2d(size(fixed))); Poslední argument ''imref2d'' specifikuje, že se vstupní obrázek má transformovat na mřížku o velikosti vstupního obrázku ''fixed''. ===== Automatic registration ===== Příklad s MRI snímky hlavy je typickým problémem při vyhodnocování medicínským obrazů. K jednomu pacientovi máme dva různé snímky -- MRI sekvence T1 a FLAIR. Na druhém jsou dobře vidět léze jako světlé oblasti a zajímají nás hodnoty druhém obrázku ve stejných oblastech. Kvůli pohnutí hlavy mezi snímáním jednotlivých sekvencí nejsou obrázky zarovnány a tudíž momentálně nesouhlasí segmentace a T1 snímek, jak je zřejmé z levého obrázku následující ilustrace. {{:courses:a6m33zsl:t1image.png?400 | T1-Image}} {{ :courses:a6m33zsl:flairimage.png?400|FLAIR Image}} === Metoda === Automatická registrace v MATLABu je dostupná přes funkci {{https://www.mathworks.com/help/images/ref/imregister.html|imregister}} (vrací přetransformovaný obrázek) nebo {{https://www.mathworks.com/help/images/ref/imregtform.html|imregtform}} (vrací transformaci). Abychom ji mohli spočíst, musíme specifikovat postup optimalizace přes parametr ''optimizer'' a dále pak vhodnou metriku, která měří chybu zarovnání -- parameter ''metric''. Jedná se o snímky s rozdílnými kontrasty, proto použijeme metriku ''MutualInformation'' registration.metric.MattesMutualInformation Properties: NumberOfSpatialSamples: 500 NumberOfHistogramBins: 50 UseAllPixels: 1 Nastavení parametrů uvedených pod ''Properties'' speficikují, jakým způsobem se metrika vyhodnocuje a má výrazný vliv na průběh a výsledek registrace. Výpočet lze urychlit, pokud nebudeme používat všechny pixely (''UseAllPixels = 0''), pak ale musíme počítat metriku přes dostatečné množství vzorků (''NumberOfSpatialSamples = 50000'' a více). Posledním parametrem před spuštěním registrace je nastavení třídy transformací. Jedná se o stejného pacienta, tudíž bychom mohli použít rigidní transformaci, lepší volbou je affiní transformace, která spolu s pohybem hlavy do určité míry kompenzuje rozdílná zkreslení v sekvencí i T1 a FLAIR. Objekt ''optimizer'' získáme následovně opt_gd = registration.optimizer.RegularStepGradientDescent opt_oneplus = registration.optimizer.OnePlusOneEvolutionary === Postup === - Načteme soubory ''brain_T1.nii'' a ''brain_FLAIR.nii'' pomocí funkce ''load_nii'' obsažené v balíčku s pomocnými funkcemi, od verze R2017b lze použít příkaz ''niftyread'' - Nastavíme objekty ''metric'' a ''optimizer'' a zavoláme funkci pro registraci obrázků moving_transformed = imregister(moving, fixed, 'rigid', optimizer, metric); % pokud počítáme transformaci, pak použijeme moving_t = imregtform(moving, fixed, 'rigid', optimizer, metric); moving_transformed = imwarp(moving, moving_t, imref3d(size(fixed))); - Výslednou transformaci aplikujeme na FLAIR image, abychom zjistili kvalitu registrace, pokud je dobrá, pak můžeme transformaci aplikovat i na snímek se segmentací - Histogram spočteme pomocí funkce {{https://www.mathworks.com/help/images/ref/imhist.html|imhist}}, nejprve ale musíme //aplikovat// transformovatnou masku ===== Deformable registration ===== Při registraci obrázků s rozdílnou anatomií není affiní transformace dostačující a je potřeba registrovaný obrázek deformovat. Tato metoda se používá ve chvíli, kdy chceme z množiny snímků vytvořit atlas (tj. mít obrázek, jak v průměru daná anatomická struktura vypadá), nebo když nás zajímá, jak se tkáň mezi dvěma snímky získaných s delším časovým odstupem změnila. Abychom nemuseli počítat příliš velké deformace, spočteme v prvním kroku affiní transformaci (viz. předchozí úloha) a deformaci budeme určovat až mezi výsledkem affiní registrace a cílovým obrázkem === Postup === - Spočteme ''moving_aff'' pomocí funkce ''imregister''. Snímky mají stejný rozsah intenzit, použijeme tedy metriku ''registration.metric.MeanSquare'', optimalizovat budeme pomocí ''registration.optimizer.RegularStepGradientDescent'' - Spočteme deformaci mezi ''moving_aff'' a ''fixed'' pomocí metody ''imregdemons'' [D, moving_def] = imregdemons( moving_aff, fixed, [400 150 60], 'AccumulatedFieldSmoothing', 1.8); Program pracuje s tzv. pyramidou - nejprve počítá deformaci na vstupech s redukovabným rozlišením, takto spočtenou deformaci postupně zjemňuje na úrovních pyramidy se rostoucím rozlišením, poslední úroveň je pak vstupní obrázek. Parameter ''[400 150 60]'' určuje, kolik iterací se počítá na jednotlivých úrovních pyramidy. Druhý parameter - ''AccumulatedFieldSmoothing'' regularizuje výslednou deformaci. Menší hodnoty umožňí detailnější deformace, vyšší hodnoty zvyšují //hladkost// výsledného deformačního pole. Vizualizaci výsledné deformace můžeme získat aplikací deformačního pole na obrázek se 3D-šachovnicí s velikostí odpovídající vstupním obrázkům. slice = checkerboard( 32, 4, 4 ); for i = 1:1:60 if mod( floor(i / 10), 2) > 0 check(i, :, :) = uint8(255 * slice(:, :)); else check(i, :, :) = uint8( 255 * (1 - slice(:, :))); end end warped_checkerboard = imwarp( check, D ); % Zobrazíme deformovaný vstup a vizualizaci pole vedle sebe imshow3d( moving_def, warped_checkerboard, 'montage', 1);