Idlimage — Zpracování dat STM v IDL

Petr Zimmermann, 1. ročník nmag. fyzika povrchů a ionizovaných prostředí
Zdrojový soubor ke stažení včetně ukázkových souborů ve složce data — 3 MB

1      Motivace


Ve Skupině tenkých vrstev (http://physics.mff.cuni.cz/kfpp/vrstvy/) používáme nekomerční řádkovací tunelový mikroskop (dále STM) pro zkoumání růstu kovových nanostruktur na površích křemíků. Výsledky se ukládají ve vlastním formátu souboru IMG, které se dále zpracovávají v IDL programu Idlimage [čti idlimáž].

Velikost souboru IMG se při rozlišení 512*512 pixelů standardně pohybuje okolo 2 MB. Chceme-li však navíc vytvořit mapu lokální hustoty stavů (LDOS), musíme použít synchronní detektor lock-in, čímž velikost souboru vzroste na 3 MB.

Soubor tvoří hlavičková data (datum, čas, rychlost skenování, různé konstanty apod.) a 3D pole typu integer typu 512*512*4 (případně *6 pokud byl použit lock-in). Za těmito daty případně následují voltampérové charakteristiky měřené v různých místech obrázku.

Význam jednotlivých datových vrstev je následující: V analogii s běžnou katodovou televizní obrazovkou hrot pomocí piezokeramických elektrod vykonává řádkovací pohyb nad vzorkem. Každý řádek hrot přečte dvakrát, a sice jednou při pohybu tam a podruhé při pohybu zpět, přičemž je možné nastavit, aby řídicí elektronika při pohybu zpět nastavila odlišné napětí.

Data se získávají v módu konstantního tunelového proudu, tedy tak, že se změnou napětí ovládá výška hrotu nad vzorkem a udržuje konstantní tunelový proud.  První dvě datové vrstvy výše popisovaného pole potom obsahují rozdíl skutečného tunelového proudu od nastaveného pro směr vpřed a vzad (záleží na rychlosti zpětnovazební smyčky) a další dvě vrstvy poté obsahují informaci o výšce hrotu nad vzorkem, opět při pohybu tam a zpět.


2      Výchozí stav

Původní program nedokázal rozpoznat, jestli jsou v souboru přítomna data z lockinu, a použít adekvátní šablonu pro zpracování binárních souborů, takže pokud jsme zpracovávali soubory obsahující data z lockinu, museli jsme přepsat šablonu a Idlimage sestavit znovu.  Dalším prohřeškem původní verze programu bylo to, že používal absolutní cesty k souborům a byl zakomponován do rozsáhlé adresářové struktury přesahující 600 MB, takže nebyl snadno přenosný.

Program bohužel obsahoval některé chyby, které nečekaně vedly k jeho pádu. Pro příklad zde uveďme situaci, kdy si člověk při volbě souboru uvědomil, že by chtěl použít jinou funkci a dialogové okno pro volbu souboru zavře. Jelikož program tímto dostal prázdný název souboru, okamžitě byl ukončen chybovou hláškou. Tento problém byl vyřešen tak, že pomocí IF — THEN se zkontroluje, jestli název souboru není prázdný řetězec, a pokud je, pak pomocí GOTO program skočí před END procedury a tím pádem nic nevykoná.

PRO open_img, Event

      ...

soubor = DIALOG_PICKFILE(title='Select a file', filter='*.img)

IF (soubor eq '') THEN GOTO, label_stop

      ...

label_stop:

END

Chtěl bych podotknout, že toto by šlo lépe vyřešit i obráceným způsobem, viz následující kód.

PRO open_img, Event

      ...

soubor = DIALOG_PICKFILE(title='Select a file', filter='*.img)

IF (soubor NE '') THEN BEGIN

      ;--- VLASTNÍ TĚLO PROCEDURY ---;

ENDIF

END

3      Konečný stav

V tomto oddílu vysvětlím některé způsoby, jakým bylo dosaženo úprav.

3.1    Zrušení absolutních cest

Absolutní cesty byly ve všech případech nahrazeny relativními následujícím způsobem. Funkce FILE_WHICH načte cestu k zadanému souboru. Dále byly vytvořeny složky dir_main pro kořenovou složku, dir_templates pro šablony na binární data a dir_data pro různé další případné soubory.

dir_main = FILE_WHICH("idlim.prj") ;nalezne hlavní soubor idlim.prj a uloží jeho cestu do proměnné cur
cd, dir_main, current=dir_main          ;do proměnné dir_templates uloží cestu k adresáři s templates
dir_templates = dir_main+"\templates"    ;do proměnné dir_templates uloží cestu k adresáři s templates
dir_data = dir_main+"\data"

3.2    Manipulace s jednotlivými daty

STM soubor se otevírá pomocí tlačítka Open IMG. Soubor při otevírání spustí proceduru open_img, která v průběhu zavolá proceduru get_version, kterou zjistí, jaká je verze zvoleného souboru a jestli soubor obsahuje data z lockinu. Podle toho open_image soubor načte pomocí adekvátní šablony. Každá datová vrstva se načte do dvou proměnných. Jedna je určena pro vizuální manipulace a druhá zůstává zachována pro export profilu mezi dvěma body (vizuální úpravy mění rozměry).

Idlimage byl rozšířen o paletu checkboxů. Po jejich zvolení se inicializuje okno a zobrazí v něm příslušná datová vrstva (Voltage BW je například mapa výšky hrotu nad povrchem), při zrušení zvolení se okno uzavře. Voltage BW je zároveň výchozí kanál, který se načítá pro manipulaci s daty.

Zvolený radiobutton (vpravo) naopak určuje, která datová vrstva je zvolena pro případné manipulace s daty. Pro manipulaci s aktivním kanálem se aktivní datová vrstva zobrazí ve speciálním okně, ve kterém probíhají úpravy.

 

Jelikož program byl rozšířen o možnost zobrazení jednotlivých datových vrstev a manipulace s nimi, stalo se potřebným mít možnost provést jednu úpravu všem datovým vrstvám zároveň. K tomuto slouží ovládací prvek Affect All Channels. V každé proceduře, které se Affect All Channels týká, se zavolá tento kód:

hbox_allc=widget_info(Event.top, FIND_BY_UNAME='WID_CHBOX_ALLC')

chbox_set = widget_info(chbox_allc, /button_set)

 

IF (chbox_set EQ 1) THEN BEGIN

...

ENDIF

 

3.3    Zjištění lockinu

Informace o tom, že byl používán lockin, je zapsána v hlavičkových datech. Jelikož stále pořád nevíme, který konkrétní bajt o tom rozhoduje, je jako přechodné řešení zvoleno zjištění na základě velikosti souboru, kdy se přeskočí veškerá hlavičková data. Je-li lockin přítomen, nastaví se globální proměnná lockin na hodnotu 1, jinak je nula.

velikost_souboru=N_ELEMENTS(READ_BINARY(file, DATA_START=134, DATA_TYPE=2))

IF (velikost_souboru GT 1200000) THEN lockin = 1 ELSE lockin = 0

Je-li přítomen lockin, po otevření souboru procedurou Open_IMG se aktivují další ovládací prvky, které umožňují vytvořit mapu lokální hustoty stavů:

Aktivace těchto prvků se provádí pomocí následujícího kódu:

IF LOCKIN EQ 0 THEN BEGIN

   button = widget_info(Event.top, FIND_BY_UNAME="WID_BUTTON_13")

   widget_control, button, sensitive = 0

      ...

ENDIF ELSE BEGIN

   button = widget_info(Event.top, FIND_BY_UNAME="WID_BUTTON_13")

   widget_control, button, sensitive = 1

      ...

ENDELSE

 

 

 

 

3.4    Výškové profily

Někdy je důležité mít možnost zobrazit výškový profil mezi dvěma body v obrázku. V tom případě je nutné nejprve odečíst rovinu a vyrovnat řádky. Nejprve se v programu zvolí funkce Line Profile a myší se v aktivním okně určí počáteční a koncový bod, mezi nimiž chceme zobrazit výškový profil. (V případě proudových datových vrstev lze zobrazit i proudový profil, nicméně je nejprve nutné zjistit konstantu úměrnosti mezi daty v souboru a skutečným proudem. V čase tohoto programu ještě nebyla známa.) Níže uvádím okomentovaný kód, který se vykoná.

pro line_profile, Event

common data, bmp

common line, line, linex, liney, x_A, x_B

common scale, x_nm, sizex, step_xy, const_z

common curr, current_fw

common active_window, active_window ;proměnná, která obsahuje hodnotu datové vrstvy nastavené jako aktivní

common lineexport, scan      ;proměnná scan, ve které jsou uloženy hodnoty

 

 siz=size(bmp)

 sizex=siz[1]

 sizey=siz[2]

 

;**********načte zvolené polohy*********

wset, 0

cursor, x0, y0, /down, /normal     ;/normal znamená, že se budou načítat souřadnice v rozmení O až 1

x1=long(fix(x0*sizex))

y1=long(fix(y0*sizey))

print, "x1,y1", x1,y1

x_A = [x1, y1]

 

cursor, x0, y0, /down, /normal

x2=long(fix(x0*sizex))

y2=long(fix(y0*sizey))

print, "x2,y2", x2,y2

x_B = [x2, y2]

 

points=fix(sqrt((x2-x1)^2+(y2-y1)^2)) ;vzdálenost vybraných bodů v pixlech

print, points

i_arr=indgen(points)

tempbmp=tvrd()  ;načte obrázek v aktivním okně a vykreslí do něj čáru v místě, kudy vede linie

tempbmp[fix(x1+(x2-x1)*i_arr/points), fix(y1+(y2-y1)*i_arr/points)]=0

tv, tempbmp

 

liney= scan[fix(x1+(x2-x1)*i_arr/points), fix(y1+(y2-y1)*i_arr/points)]

liney= liney*const_z    ;přepočítá hodnoty na správnou výšku

linex = i_arr*step_xy

 

;**********

 

print, fix(x1+(x2-x1)*i_arr/points), fix(y1+(y2-y1)*i_arr/points)

;print, "line", line

;line=tvrd(0,y,sizey-1,1)

;line=bmp(*,y)

;line=bmp(*,257)

window, 10, title = "Line Profile"

 

;print, line

IF ((active_window EQ 3) or (active_window EQ 4)) THEN BEGIN

plot, linex, liney, xtitle="[nm]", ytitle="z [nm]"

ENDIF ELSE BEGIN

plot, linex, liney, xtitle="[nm]", ytitle="arbitary units"

ENDELSE

line = MAKE_ARRAY(2,points, /double)

line[0,*] = linex

line[1,*] = liney

print, "aktivní okno", active_window

end

4      Práce s programem

V následujících pár krocích bych chtěl demonstrovat práci se souborem, ve kterém jsou uložena data indiových řetízků na povrchu Si(100)—2×1.

4.1    Otevření souboru

Nejprve otevřeme libovolný soubor. Na paletě s datovými vrstvami si zvolíme například proudový a napěťový (výškový) obrázek.

4.2    Srovnání řádků

Dále pak srovnáme řádky (Row Equalization). Srovnání řádků znamená, že se spočítá průměrná hodnota v jednom řádku a řádek se posune tak, aby průměru byla přidělena hodnota 128 — čili polovina rozsahu stupňů šedi (0—255). Průměr se zjistí funkcí moment, která vrací vektor, jehož 1. prvek je průměr zadaného souboru.

function row_eq, b2

b=b2

siz=size(b)

xsize=siz[1]

ysize=siz[2]

;help, b

;print, xsize, ysize

for i=0, ysize-1 do begin

    ; b[*,i]=(b[*,i]-min(b[*,i]))/(max(b[*,i])-min(b[*,i]))

    result=moment(b[*,i])

    b[*,i]=b[*,i]-result[0]+128

endfor

;print, b[*,100]

 

return, b

 

end

4.3    Odečtení roviny

Dále je nutné odečíst rovinu (Plain Substraction), protože hrot nemusí vždy skenovat vzorek přesně v rovině kolmé k povrchu — může být mírně nakloněn, a proto se data proloží plochou prvního řádu (tedy rovinou) a ta se odečte. Proložení plochou n-tého řádu se dělá funkcí SFIT

data=data-SFIT(data,1, kx=koef)

4.4    Histogramové zvýraznění kontrastu

Poslední důležitý krok je zvýraznění detailů získaného obrázku. K zobrazování dat se používá funkce tvscl, která zvolená data přeškáluje v rozmezí 0—255 a zobrazí je ve stupních šedi. Nicméně v každém souboru se nalezne pár hodnot — většinou chybových —, které negativně ovlivňují kontrast. Histogramové zvýraznění kontrastu (Histogram Equalization) těchto pár hodnot ořízne a znovu vykreslí.

Zájemce o kód odkazuju na zdrojový soubor, protože kód není příliš přehledný a skládá se z několika vlastních procedur a funkcí.

Nakonec je možné tyto výsledky přijmout a exportovat do JPEG, přičemž proměnná bmp je hodnota v okně nastaveném jako aktivní (okno má název IDL 0).

pro export_jpeg, Event

;common data, bmp

 

file = dialog_pickfile(/WRITE, FILTER = '*.jpg',PATH='c:')

IF (file EQ '') THEN GOTO, stop_export_jpeg

file = file+".jpg"

wset, 0

bmp = TVRD()

WRITE_JPEG, file, bmp

stop_export_jpeg:

END