• No results found

Linjering av ett mikro-CT- system

N/A
N/A
Protected

Academic year: 2021

Share "Linjering av ett mikro-CT- system"

Copied!
61
0
0

Loading.... (view fulltext now)

Full text

(1)

Linjering av ett

mikro-CT-system

(2)
(3)

Detta examensarbete har utförts i samarbete med STH Handledare på STH: Massimiliano Colarieti-Tosti

Linjering av ett mikro-CT-system

Alignment of a micro-CT system

A l e x a n d e r L u n d a h l J a c o b T r o w a l d

Examensarbete inom medicinsk teknik Grundnivå, 15 hp Handledare på KTH: Anna Bjällmark Examinator: Lars-Gösta Hellström Skolan för teknik och hälsa TRITA-STH. EX 2015:053

(4)
(5)

Sammanfattning

a Skolan f¨or Teknik och H¨alsa (STH) vid KTH byggs en

mikro-CT och f¨or att systemet ska fungera korrekt m˚

aste det

linjari-seras. Syftet med detta examensarbete var att ta fram ett

pro-gram som, utifr˚

an bilder tagna med mikro-CT:n, kan ber¨akna alla

n¨odv¨andiga parametrar f¨or att systemet ska kunna linjariseras.

Under projektet har LabView-kod, skapad f¨or att linjera ett

CT-system, modifierats f¨or att vara kompatibel med den

mikro-CT som byggs p˚

a STH. Koden har i viss m˚

an skrivits om till det

licensbefriade och plattformsoberoende spr˚

aket Java. D˚

a

mikro-CT:n p˚

a STH ¨annu inte ¨ar funktionell har varken koden i LabView

eller Java kunnat valideras med denna. Framg˚

angsrika f¨ors¨ok har

ist¨allet genomf¨orts p˚

a bilder fr˚

an en annan mikro-CT samt p˚

a

si-mulerade bilder av en fantom i en mikro-CT.

Abstract

(6)
(7)

Inneh˚

all

1 Inledning 1 1.1 M˚al . . . 2 2 Bakgrund 3 2.1 Parameterar . . . 4 2.2 LabView . . . 4 2.3 Teori . . . 6 2.4 Grafiskt anv¨andargr¨anssnitt . . . 6 3 Metod 7 3.1 LabView . . . 7 3.1.1 Utbildning . . . 7 3.1.2 Andringar i labview-koden . . . .¨ 7 3.1.3 Validering av labview-koden . . . 7

3.1.4 Bilder och filformat . . . 7

3.2 Java . . . 8

3.2.1 Krav . . . 8

3.2.2 Klasser och metoder . . . 8

3.2.3 Dokumentation och tredjepartspaket . . . 9

3.2.4 Koordinater . . . 9 3.2.5 Ber¨akningar . . . 10 4 Resultat 11 4.1 LabView . . . 11 4.2 Java . . . 11 5 Diskussion 13 5.1 Begr¨ansingar . . . 13 5.2 LabView . . . 13 5.3 Val av spr˚ak . . . 13 5.4 Java . . . 14

5.5 Graphical User Interface . . . 14

(8)

INNEH˚ALL INNEH˚ALL

(9)

1 INLEDNING

1

Inledning

Datortomografi (eng. Computed Tomography, CT) ¨ar ett medicinskt bildgivande system som anv¨ander joniserande str˚alning f¨or att erh˚alla bilder av en patient eller objekt i tre dimensioner [1]. En mikro-CT ¨ar en mindre variant av en CT, som fr¨amst anv¨ands f¨or mindre objekt eller sm˚adjur. Detektor och k¨alla roterar kring objektet och detektorn tar emot data fr˚an k¨allan i form av detekterade fotoner. Denna data visar p˚a attenueringen av fotoner i objektet och sammanst¨aller denna till en bild. Detektorn kan dock vara fellinjerad i f¨orh˚allande till dess ideala position gentemot k¨allan och rotationscentrum (se Figur 1). Om detta bortses fr˚an, kan resultatet bli suddiga eller felaktiga bilder. F¨or att generera en s˚a verklighetsn¨ara och tydlig bild som m¨ojligt kr¨avs att felen i detektorns position ¨ar tillgodor¨aknade n¨ar bilden ska-pas. F¨or att detta ska vara m¨ojligt beh¨over d¨arf¨or detektorn med j¨amna mellanrum kalibreras. [2]

Figur 1: Fellinjering av detektor. RA = rotationsaxel, Rf = Avst˚and mellan k¨alla

och RA, R = Avst˚and mellan k¨alla och detektor. Bild inspirerad av: [3]

P˚a STH har ett byggprojekt av en mikro-CT n˚att slutfasen och ska snart s¨attas i bruk. Kalibreringsmjukvara f¨or detektorn finns tillhanda men har tv˚a problem:

• Koden ¨ar utformad f¨or en annan mikro-CT och beh¨over anpassas f¨or STHs mikro-CT.

(10)

1.1 M˚al 1 INLEDNING

Dessa tv˚a problem ligger till grunden f¨or examensarbetet. Koden beh¨over skrivas om f¨or att anpassas till den aktuella mikro-CT:n och i m˚an av tid skriva om ko-den fr˚an LabView till ett programmeringsspr˚ak med fri licens (ex. Java) och med funktionalitet f¨or andra operativsystem.

1.1 M˚al

Det prim¨ara m˚alet med projektet ¨ar att g¨ora den givna LabView-koden kompatibel med mikro-CT:n p˚a STH.

(11)

2 BAKGRUND

2

Bakgrund

F¨or att linjera detektorn kr¨avs bilder i 360 av ett fantomobjekt (se Figur 2). Fan-tomobjektet best˚ar av en plast med l˚ag attenuering med kulor av metall med h¨og attenuering. P˚a bilderna som framst¨alls ¨ar d¨arf¨or kontrastskillnaden mellan metall-kulorna och resterande delen av fantomen stor (se Figur 3). Vid en full rotation projiceras kulornas banor i en sammans¨attning av bilderna (se Figur 4), dessa banor ¨

ar grundl¨aggande i ber¨akningen av fellinjeringen. Med hj¨alp av fourierkoe↵ecienterna f¨or kulornas koordinater kan felplaceringen av detektorn relativt en teoretiskt ideal detektor best¨ammas. Detektorn som anv¨ands i STH’s mikro-CT ¨ar en Hamamatsu C7942CA-22 med en pixelstorlek p˚a 0.050mm och en uppl¨osning p˚a 2400⇥ 2400 pixlar. [4]

Figur 2: Fantom

Figur 3: CT-bild av fantom

(12)

2.1 Parameterar 2 BAKGRUND

2.1 Parameterar

F¨or att kunna kalibrera detektorn beh¨over programmet generera information om f¨oljande parametrar:

x Detektorns felplacering i x-led

y Detektorns felplacering i y-led

z Detektorns felplacering i z-led (Se Fi-gur 5)

Figur 5: Fellinjering i tre riktningar. (Inspire-rad av: [5])

(slant) Rotation kring z-axel

✓ (tilt) Rotation kring x-axeln

⌘ (skew) Rotation kring y-axeln (Se Fi-gur 6)

Figur 6: Fellinjering i tre vinklar. (Inspirerad av: [2])

Rf Avst˚and mellan detektorplanet och Area of rotation. (se Figur 1)

2.2 LabView

(13)

2.2 LabView 2 BAKGRUND

Figur 7: Exempel p˚a en del av en LabView-VI

(14)

2.3 Teori 2 BAKGRUND

Arizona STH

Detektorns pixelstorlek 0.048 mm 0.050 mm Bildstorlek (output) 2048⇥ 1024 2400⇥ 2400

Filformat (output) Raw 32 bit float Unsigned 16 bit int

Tabell 1: Relevanta skillnader f¨or projektet mellan STH’s och Arizonas mikro-CT

2.3 Teori

Projektionerna av kulornas bana ¨ar central f¨or ber¨akningarna av de s¨okta v¨ardena. F¨or att finna storleken p˚a felen i vinklar och riktningar anv¨ands relationen mellan dessa variabler och banornas fourierkomponenter. De s¨okta v¨ardena defineras enligt Von Smeakal m.fl. [6]: ⌘ (skew) = arctan ✓ c11 c01 ◆ ✓ (tilt) = arcsin ✓ ±B(Fk Fj) (Ek Ej)(C Fk) (Fk Fj)(A Ek) ◆ (slant) = arctan ✓ C F sin(✓)(A E)± B ◆ dx= sin (Asin✓± B) Ccos

R0y = cos (Asin✓± B) Csin dx= Acos✓

(1)

d¨ar R0y = R + dy, A, B, C, E och F v¨ardena kommer fr˚an hj¨alpvektorer som

de-finieras av punkternas fourierkoefficienter och skew. Notera att slant ¨ar odefinierad d˚a tilt ¨ar n¨ara eller lika med 0. Vid problem att ber¨akna tilt och slant ber¨aknas resterande v¨arden, givet att tilt= 0 och antaget att slant= 0, enligt f¨oljande:

R0y =⌥B dx= C

dz = A

(2)

De anv¨anda hj¨alpvektorerna defineras i Appendix B. F¨orst ber¨aknas c-v¨ardena d˚a de ligger till grund f¨or resterande hj¨alpvektorer, d¨arefter d-v¨arden. Med skew som ber¨aknas med c-v¨arden (se ekvation 1) samt c- och d-v¨arden ber¨aknas de slutliga A,B,C,E och F hj¨alpvektorerna.

2.4 Grafiskt anv¨andargr¨anssnitt

(15)

3 METOD

3

Metod

3.1 LabView

3.1.1 Utbildning

F¨or att f˚a b¨attre f¨orst˚aelse f¨or LabView tillkallades en programmerare fr˚an Na-tional Instruments som h¨oll en privat f¨orel¨asning om LabViews syntax samt gav handledning i det projekt som skulle genomf¨oras. Det konstaterades att till¨agg f¨or bildbehandling (IMAQ) kr¨avdes f¨or att kunna k¨ora koden och att detta till¨agg inte fungerar p˚a OSX. All given Labview kod k¨ors enbart p˚a Windowsmaskiner men g˚ar att l¨asa och tolka i OSX.

3.1.2 Andringar i labview-koden¨

Den fungerande delen av Labview-koden kan ej ber¨akna tilt och slant. Vid ber¨akning utan tilt kr¨avs en f¨or¨andring av pixelstorleken (RunFullCalculation.vi), bildstorleken (GetCentroidCoord.vi) samt filformatet (GetCentroidCoord.vi).

F¨or att f˚a en fungerande ber¨akning med tilt och slant kr¨avdes en f¨or¨andring av Cal-culateAllThetas.vi. Kopplingar mellan funktionerna hade brutits och beh¨ovdes bytas ut mot fungerande kopplingar, NumberOfBalls som visar p˚a antalet bollar beh¨ovde l¨aggas till och och kopplas till sub-VI:n CalculateTheta.vi och en output-array med resultaten beh¨ovde l¨aggas till. Fler f¨or¨andringar kr¨avs ocks˚a i runFullCalculationW-Tilt.vi d¨ar ett v¨arde kallat Rf som visar p˚a avst˚andet mellan objekt och detektor.

Vid en n¨armare analys av matematiken och LV-kodens hierarki (den ordning i vil-ken de olika VI’s k¨ors) visade sig flertalet av VI’s vara ¨overfl¨odiga och antalet kunde sk¨aras ner till 22 som var n¨odv¨andiga f¨or att kalibrering ska kunna genomf¨oras. Varje av dessa har noga analyserats och j¨amf¨orts med matematiken i det dokument som beskriver fysiken bakom kalibreringen [6] f¨or att finna vilka variabler som kan beh¨ova justeras f¨or att vara kompatibel med STH’s mikro-CT.

3.1.3 Validering av labview-koden

D˚a STH’s mikro-CT inte var klar kunde inte valideringen ske p˚a denna, utan fick ist¨allet testas p˚a bilder fr˚an en mikro-CT som befinner sig p˚a University of Arizona och p˚a simulerad data. Den simulerade datan skapades med f¨orbest¨amd fellinjering anv¨andes i den f¨or¨andrade labview-koden f¨or att fastst¨alla att de s¨okta v¨ardena ber¨aknades korrekt (Se Tabell 2, 3, 4). Den simulerade datan hade an uppl¨osning p˚a 512⇥ 512 pixlar och ett raw-filformat p˚a 8 bitar.

3.1.4 Bilder och filformat

D˚a filformaten mellan STH’s och Arizonas mikro-CT skiljer sig ˚at, g¨ors samtliga bilder fr˚an Arizonas CT om till bin¨ara filer. Detta gjordes i en kort matlabkod som ¨

(16)

3.2 Java 3 METOD

G). Matlab anv¨andes i detta fall d˚a java inte har n˚agot inbyggt st¨od f¨or formatet uint samt d˚a bytet av filformat bara beh¨ovdes g¨oras vid ett tillf¨alle.

3.2 Java

3.2.1 Krav

D˚a kalibrering av detektor sker s¨allan, st¨alls l˚aga krav p˚a programmets hastighet. H¨ogre krav st¨alls ist¨allet p˚a kodens precision inom bildbehandling och matematiska korrekthet s˚a de framst¨allda bilderna blir s˚a riktiga som m¨ojligt.

Anv¨andaren ska kunna, med en knapp, v¨alja f¨orsta bild-filen. Om bilden som v¨aljs inte ¨ar i korrekt format (.bin) ska programmet s¨aga ifr˚an. N¨asta steg ¨ar att v¨alja en ROI. Efter detta ska anv¨andaren bara beh¨ova trycka ”Run Calculation” och erh˚alla de n¨odv¨andiga kalibreringsv¨ardena och en bild av kulornas banor.

Bilderna som anv¨andes f¨or att testa koden var fr˚an Arizonas mikro-CT d˚a STH’s CT inte var f¨ardigst¨alld.

3.2.2 Klasser och metoder

Vid ¨overs¨attning anv¨andes Java med designm¨onstret Model-View-Controller. All kod skrevs i programmet Eclipse. F¨oljande klasser skapades:

Controller controller-klass.

CalculateValues Model-klass f¨or samtliga matematiska utr¨akningar.

ImageProcessing Model-klass f¨or processering av bilder och koordinatutr¨akning GUI View-klass f¨or interface

Trajectories Model-klass f¨or skapande av ban-bild

ROI Model-klass f¨or best¨amning av vilka delar av bilden som ska analyseras (Region of interest).

¨

Aven flertalet mindre klasser s˚asom main-klass och observer-klasser beh¨ovdes i pro-jektet.

(17)

3.2 Java 3 METOD

3.2.3 Dokumentation och tredjepartspaket

Vid hj¨alp med kodande anv¨andes Javas egen dokumentation[7], hemsidan Stackoverflow[8], D. Flanagan, Java in a nutshell: a desktop quick reference[9] och K. Arnold m.fl. The Java Programming Language, 4th edition[10].

D˚a bilderna fr˚an mikro-CT:n ¨ar i ett unsigned int-format som Java inte kan l¨asa, m˚aste tredjepartspaketet guava-18.0.jar[11] installeras i Eclipse f¨or att programmet ska vara funtionellt.

3.2.4 Koordinater

Till en b¨orjan ber¨aknades varje punkts koordinat f¨or varje bild. Detta gjordes genom att v¨alja ett region of interest (ROI) med enbart det antal kulor som ¨onskas m¨ata p˚a, on¨odig information utanf¨or regionen skalas ocks˚a bort f¨or att e↵ektivisera koden. Kontrastjusteringar genomf¨ors och bilden unders¨oks genom att g˚a igenom pixel f¨or pixel tills en skillnad i kontrast hittas. Programmet finner kulorna och r¨aknar ut deras centrum. Samtliga koordinater f¨or alla kulor i alla bilder samlas i en array. Koordinaterna i Java definieras dock inte p˚a samma vis som i den matematiska teorin. Enligt teorin ska origo vara placerat i mitten av detektorplanet, i Java ¨ar det definierat som det ¨ovre v¨ansta h¨ornet och m˚aste d¨arf¨or flyttas (se Figur 8). Koordinaterna skiftas enligt:

x = x0 xmax 2 z = zmax 2 z0 (3)

d¨ar xmax, zmax ¨ar de maximala v¨ardena f¨or x och z innan skiftningen och x0, z0 ¨ar

de ursprungliga koordinaterna. Denna skiftning g¨ors f¨or koordinaterna till samtliga kulor i alla bilder innan ber¨akningar kan ske.

(18)

3.2 Java 3 METOD

3.2.5 Ber¨akningar

Programets ber¨akningar av s¨oka parametrar efter att koordinaterna har skiftats g¨ors i f¨oljande ordning:

Fourierkoefficienter Baserade p˚a koordinaterna d-v¨arden baserade p˚a fourierkoefficienterna

c-v¨arden baserade p˚a fourierkoefficienterna och d-v¨ardena skew baserad p˚a c-v¨arden

A,B,C,E,F Baserade p˚a d-v¨arden, c-v¨arden och skew

Resterande s¨okta parametrar Baserade p˚a A,B,C,E och F

(19)

4 RESULTAT

4

Resultat

4.1 LabView

Samtliga parametrar som beh¨over justeras f¨or att kalibrera mikro-CT’s detektor tros vara identifierade. Samtliga on¨odiga VI’s har tagits bort och de resterande har validerats med den data som erh˚allits fr˚an University of Arizona. Den modifierade koden har ¨aven validerats p˚a bilder som skapats med hj¨alp av simuleringar av en mikro-CT. Med simulerad data har f¨oljande v¨arden uppm¨atts:

Tabell 2: Ber¨akningar p˚a simulerad data 1 Uppm¨att v¨arde Faktiskt v¨arde di↵erens

skew 1 1 0

dz 0.76 mm 0.81 mm 0.05 mm dx -1.31 mm -1.31 mm 0 mm

Tabell 3: Ber¨akningar p˚a simulerad data 2 Uppm¨att v¨arde Faktiskt v¨arde di↵erens

slant -1.25 1.25 2.5

dz 0.82 mm 0.81 mm 0.01 mm dx 1.30 mm 1.31 mm 0.01 mm

Tabell 4: Ber¨akningar p˚a simulerad data 3 Uppm¨att v¨arde Faktiskt v¨arde di↵erens

skew 0.77 0.75 0.02

tilt -1.5 1.25 2.75

slant -1 1 2

dz 0.83 mm 0.81 mm 0.05 mm dx 1.30 mm 1.31 mm 0.01 mm

En ytterligare m¨atning gjordes utan resultat d˚a kulorna i simuleringen ej var tillr¨ackligt synliga.

4.2 Java

(20)

4.2 Java 4 RESULTAT

s.1I detta ¨ar inte ber¨akningar av tilt, slant och skew inr¨aknat. Sammanlagt inneh˚aller programmet 3300 rader kod och d˚a saknas fortfarande sammankoppling mellan den matematiska delen av koden med den resterande delen.

Den framst¨allda bilden av kulornas banor ser korrekt ut, med undantag f¨or den plats i banan d¨ar f¨orsta och sista kulan m¨ots, d¨ar det ser ut att ha blivit n˚agon sorts f¨orskjutning (se Figur 9). Samma f¨orskjutning kan dock ses i LV-koden.

Figur 9: F¨orskjutning mellan kulorna i f¨orsta och sista projektionen

(21)

5 DISKUSSION

5

Diskussion

5.1 Begr¨ansingar

I programmen har bara tv˚a typer av bilder anv¨ants. Dessa bilder, fr˚an Arizona Uni-versity och de simulerade bilderna, inneh˚aller sju kulor och har i stort sett samma kontrastskillnad mellan fantomens metallkulor, platsh¨olje och omliggande luft. Det ¨

ar sv˚art att avg¨ora hur programmet skulle fungera med bilder d¨ar kontrastskillnaden ¨

ar mindre. Problem kan d˚a uppst˚a med att hitta kulorna och d¨armed deras koordi-nater. Saknas f¨or m˚anga kulor i ber¨akningar av deras banor kommer felaktiga v¨arden erh˚allas. Det ¨ar sv˚art att s¨aga om koden fungerar med STH’s mikro-CT d˚a dessa bilder kan skilja sig markant fr˚an de som anv¨ants hittills.

5.2 LabView

Den modifierade LabView-koden har enbart validerats med bilder fr˚an mikro-CT:n fr˚an Arizona och simulerad data. F¨or att kunna s¨akerst¨alla att teorierna om vilka variabler som b¨or justeras ¨ar korrekta, kr¨avs att bilder erh˚alls fr˚an den mikro-CT programmet ¨ar byggt f¨or. Detsamma g¨aller f¨or vilka v¨arden vissa variabler b¨or anta, d˚a bara variablerna sj¨alva kan avg¨oras utan tester, inte deras v¨arden. Resultaten fr˚an simuleringarna ger en negativ tilt och slant, en teori ¨ar att det beror p˚a att rummet ¨ar definierat annorlunda i simuleringen.

5.3 Val av spr˚ak

Vid spr˚akval f¨or ¨overs¨attning avgjorde f¨oljande punkter: • Licensfritt

• Stabilitet

• Matematisk funktionalitet • Kan skapa exekverbara filer • Platformsoberoende

• Bra debugging

Java har funnits i ¨over 20 ˚ar och erbjuder d¨arf¨or stabilitet tillsammans med ett stort bibliotek av funktioner f¨or bildbehandling och matematik. Med programmet Eclipse kan enkelt exekverbara filer skapas och kommer med bra debugging-m¨ojligheter. Java har ¨aven m¨ojligheten att k¨oras p˚a de flesta plattformer, s˚asom Windows, OSX och Linux [12][9].

(22)

5.4 Java 5 DISKUSSION

inte accepterar det filformat bilderna fr˚an mikro-CT’n ¨ar i. Program som Matlab, Python eller LabView har fler inbyggda funktioner f¨or att l¨asa bin¨ara filformat och f¨ors¨ok att skriva kod i Matlab som kan l¨asa in bilderna var okomplicerat. MatLab och Pythons enkla syntax, inbyggda matematiska funktioner och st¨od f¨or de flesta filformat pekar p˚a att de kan vara b¨attre spr˚ak ¨an Java att skriva denna sorts pro-gram i. I slut¨andan kunde dock tredjeparts-paket (JAR) inkluderas i koden f¨or att l¨osa filformatsproblemen i Java [11].

5.4 Java

F¨orskjutningen mellan banans f¨orsta och sista boll kan bero av flera saker. En f¨orklaring kan vara att koden inneh˚aller en bugg som f¨orskjuter koordinaterna n˚agot i y-led f¨or varje bild. D˚a denna f¨orskjutning ¨aven g˚ar att se i den givna LabView-koden ¨ar en rimligare f¨orklaring att n˚agot skett under CT-scanningen. Exempelvis kan vibrationer under processen f¨orflyttat fantomen vilket skulle ge upphov till ett s˚adant resultat.

Det har visat sig att den ¨oversatta matematiska koden inte ¨ar fullt kompatibel med resten av koden, d˚a LabView behandlar bilderna och koordinaterna p˚a ett annat s¨att ¨

an det skrivna Java-programmet. Denna kommer till viss del beh¨ova skrivas om f¨or att kunna hantera bildbehandlingens input.

Det kan ocks˚a konstateras att skriftliga programmeringsspr˚ak ger st¨orre friheter ¨an grafiska d˚a utvecklaren ges st¨orre m¨ojlighet att manipulera detaljer i koden. Detta gav exempelvis m¨ojligheten att l˚ata programmet sj¨alv r¨akna ut flera parametrar i bilderna ist¨allet f¨or att anv¨andaren manuellt m˚aste skriva in dem och riskera fel-aktiga v¨arden. Ett exempel p˚a detta ¨ar att LV-koden kr¨aver en input av antalet projektioner och kulor i respektive projektion, medan den ¨oversatta Java-koden kan r¨akna ut detta p˚a egen hand.

5.5 Graphical User Interface

Gr¨anssnittet f¨or LV-koden ¨ar r¨origt och sv˚art att anv¨anda utan att f¨orst f¨orst˚a den bakomliggande koden. En av anledningarna till detta ¨ar att programmet har m˚anga parametrar som anv¨andaren sj¨alv m˚aste st¨alla in, samt att interfacet in-neh˚aller m˚anga detaljer och v¨arden som ¨ar irrelevanta f¨or anv¨andaren.

D˚a kalibrering beh¨over ske med j¨amna mellanrum ¨ar det f¨ordelaktigt om anv¨andaren p˚a egen hand kan sk¨ota s˚a stora delar av kalibreringen som m¨ojligt, utan att beh¨ova ta in en extern part.

5.6 Framtiden

(23)

5.6 Framtiden 5 DISKUSSION

Java-koden inneh˚aller ¨aven ett antal buggar som det inte fanns tid f¨or att ta bort. Exempel p˚a dessa ¨ar:

• Koden g˚ar inte att exekvera om bilden inte ¨ar i ”liggande” l¨age och inte har dimensionerna 2048*1024 pixlar. Detta m˚aste d˚a korrigeras i koden. D˚a filerna ¨

ar i formatet .bin, som enbart best˚ar av en array, ¨ar det en om¨ojlighet att l˚ata programmet sj¨alv ber¨akna storleken p˚a bilderna. F¨or att l¨osa detta beh¨ovs en ruta d¨ar anv¨andaren sj¨alv f˚ar skriva in dimensionerna.

• F¨or varje g˚ang Region of interest v¨aljs sparas en vit ruta i bilden ¨aven om anv¨andaren inte ¨ar n¨ojd och ¨onskar g¨ora en ny (se Figur 10). Detta inneb¨ar att f¨or varje f¨ors¨ok blir det fler rutor och d¨armed sv˚arare och sv˚arare att skapa en bra ROI. En l¨osning ¨ar att placera en osynlig ”JFrame”¨over bilden d¨ar markeringen kan ritas och suddas ut utan att p˚averka den underliggande bilden.

Figur 10: Val av Region of interest. Den vita rutan har anv¨andaren ritat ut. Allt utanf¨or rutan behandlar inte programmet.

Det finns ¨aven andra m¨ojligheter att f¨orb¨attra programmet. Exempelvis kan koden beh¨ova e↵ektiviseras d˚a den allokerar mycket av datorns minne, vilket kan leda till att programmet kraschar om det k¨ors p˚a en ¨aldre dator. Det kan ¨aven kontrolleras huruvida kulorna p˚a vissa bilder f¨orsvinner ur bild eller korsar varandras banor och i dessa fall ta bort dessa ur ber¨akningarna. Detta skulle inneb¨ara att valet av ROI inte l¨angre ¨ar n¨odv¨andigt och att anv¨andaren enbart beh¨over v¨alja .bin-fil och trycka p˚a en knapp f¨or att f˚a resultaten.

(24)

5.6 Framtiden 5 DISKUSSION

(25)

6 SLUTSATS

6

Slutsats

Modifiering av Labview-koden visade sig vara r¨attningar i matematiken f¨or ber¨akning av slant och tilt samt ¨andringar f¨or bildernas filformat och pixel- till millimeterra-tion. Dock ¨ar projektet, som det ser ut nu, inte f¨ardigst¨allt. LabView-koden m˚aste valideras med STH’s mikro-CT och kan komma beh¨ova ytterliggare modifieringar efter f¨ors¨ok. D˚a den givna datan fr˚an University of Arizona samt den simulerade datan g˚ar att k¨ora i LabView med goda resultat, antyder det att inga fler stora ¨

andringar ¨ar n¨odv¨andiga f¨or att uppn˚a m˚alet.

Den hittills skrivna Java-koden fungerar n¨ast intill optimalt, med undantag f¨or ett par buggar. De matematiska delarna ¨ar ej kopplade till varandra men fungerar v¨al separat.

Att anv¨anda ett annat spr˚ak f¨or ¨overs¨attning med fler inbyggda funktioner f¨or detta ¨

(26)
(27)

7

Referenser

[1] D. J. Brenner and E. J. Hall, “Computed Tomography — An Increasing Source of Radiation Exposure,” New England Journal of Medicine, vol. 357, no. 22, p. 2277, Nov. 2007, accessed: 2015-05-28. [Online]. Available: http://www.nejm.org/doi/abs/10.1056/NEJMra072149

[2] L. von Smekal, M. Kachelriess, E. Stepina, and W. A. Kalender, “Geometric mi-salignment and calibration in cone-beam tomography,” Medical Physics, vol. 31, no. 12, p. 3246, Dec. 2004.

[3] J. W. Moore, “Adaptive X-ray Computed Tomography,” The University of Ari-zone, p. 45, 2011.

[4] “Flat panel sensor C7942ca-22,” accessed: 2015-05-21. [Online]. Avai-lable: http://www.hamamatsu.com/jp/en/product/alpha/F/4158/C7942CA-22/index.html

[5] L. von Smekal, M. Kachelriess, E. Stepina, and W. A. Kalender, “Geometric mi-salignment and calibration in cone-beam tomography,” Medical Physics, vol. 31, no. 12, p. 3244, Dec. 2004.

[6] ——, “Geometric misalignment and calibration in cone-beam tomography,” Me-dical Physics, vol. 31, no. 12, pp. 3242–3266, Dec. 2004.

[7] O. Corporation, “JavaTM Platform, Standard Edition 7

API Specification,” accessed: 2015-04-20. [Online]. Available: http://docs.oracle.com/javase/7/docs/api/

[8] stack exchange inc, “Stackoverflow,” accessed: 2015-04 till 2015-06. [Online]. Available: www.stackoverflow.com

[9] D. Flanagan, Java in a nutshell: a desktop quick reference, 3rd ed., ser. The Java series (O’Reilly). Beijing ;Cambridge: O’Reilly, 1999, kap. 1.2 - Key Benefits of Java, Kap. 8 - Java Development Tools (The Java Debugger).

[10] K. Arnold, J. Gosling, and D. Holmes, The Java programming language, 4th ed. Upper Saddle River, NJ: Addison-Wesley, 2006.

[11] Hamamatsu, “guava-libraries google, inc,” accessed: 2015-04-15. [Online]. Available: https://code.google.com/p/guava-libraries/

(28)
(29)

Appendix

A Banbild

Bild av kulornas banor (Trajectory)

B Teori

Enligt Von Smekal m.fl. [6] kr¨avdes bara den diskreta fouriertransformen av k  3 givet av: Uk= 2 N N X n=1 uncos(kan), k = 0, ..., N/2 e Uk = 2 N N X n=1 unsin(kan), k = 1, ..., N/2 1 (4)

d¨ar Uk ¨ar den reella fourierkoefficienten, eUk ¨ar den komplexa fourierkoefficienten, N

¨

ar antalet projektioner, an¨ar punktens position p˚a cirkeln och un¨ar x-koordinaterna.

Samma ber¨akning skedde f¨or y-koordinaterna och betecknades Vk f¨or den reella

(30)
(31)

calculateValues.java 1public class calculateValues {

2 private int sense = 1; 3

4 public calculateValues(int[][][] in, int x, int y) { 5 fullCalculation(in, x, y);

6 }

7

8 publicint[][][] shiftCoords(int[][][] in, int xSize, int ySize) { 9 int[][][] temp = new int[in.length][in[0].length][in[0][0].length]; 10 for (int i = 0; i < temp.length; i++) {

11 for (int j = 0; j < temp[0][0].length; j++) { 12 temp[i][1][j] = (ySize / 2) - in[i][1][j]; 13 temp[i][0][j] = in[i][0][j] - (xSize / 2); 14 } 15 } 16 returntemp; 17 } 18

19 publicdouble[] getSkew(double[][] cVals, int ballsize) { 20 double[] skew = new double[ballsize];

21 for (int i = 0; i < ballsize; i++) {

22 skew[i] = Math.atan(-cVals[3][i] / cVals[1][i]);

23 }

24 returnskew; 25 }

26

27 publicvoid fullCalculation(int[][][] in, int xSize, int ySize) { 28 int[][][] shifted = shiftCoords(in, xSize, ySize);

29 double[][] uComplexArray = getComplexFourierCoeffs(in[0][0].length, 30 shifted, in.length, 0);

31 double[][] uRealArray = getRealFourierCoeffs(in[0][0].length, shifted, 32 in.length, 0);

33 double[][] vComplexArray = getComplexFourierCoeffs(in[0][0].length, 34 shifted, in.length, 1);

35 double[][] vRealArray = getRealFourierCoeffs(in[0][0].length, shifted, 36 in.length, 1);

37 double[][] dValues = getDvalues(uRealArray, uComplexArray, vRealArray, 38 vComplexArray, in[0][0].length, in.length);

39 double[][] cValues = getCvalues(dValues, uRealArray, uComplexArray, 40 vRealArray, vComplexArray, in.length);

41 double[] skew = getSkew(cValues, in.length);

42 double[] Rprime = getRprime(cValues, skew, in.length); 43 double[] dx = getDx(dValues, skew, in.length); 44 double[] dz = getDz(dValues, skew, in.length); 45 doublerad = 180 / Math.PI;

46 doublemm = 0.048; 47 doublesumSkew = 0; 48 doublesumRprime = 0; 49 doublesumDx = 0; 50 doublesumDz = 0;

51 for (int i = 0; i < in.length; i++) { 52 sumSkew = sumSkew + skew[i]; 53 sumRprime = sumRprime + Rprime[i]; 54 sumDx = sumDx + dx[i];

55 sumDz = sumDz + dz[i];

56 }

57 doublefixSkew = sumSkew * rad / in.length; 58 doublefixRprime = sumRprime * mm / in.length; 59 doublefixDx = sumDx * mm / in.length; 60 doublefixDz = sumDz * mm / in.length; 61 }

62

Page 1

(32)

calculateValues.java

63 public double[] getDz(double[][] dVals, double[] skew, int ballSize) { 64 double[] dz = new double[ballSize];

65 for (int i = 0; i < ballSize; i++) {

66 dz[i] = -dVals[3][i] * Math.sin(skew[i]) - dVals[6][i]

67 * Math.cos(skew[i]);

68 }

69 return dz;

70 }

71

72 public double[] getDx(double[][] dVals, double[] skew, int ballSize) { 73 double[] dx = new double[ballSize];

74 for (int i = 0; i < ballSize; i++) {

75 dx[i] = dVals[8][i] * Math.sin(skew[i]) - dVals[5][i]

76 * Math.cos(skew[i]);

77 }

78 return dx;

79 }

80

81 public double[] getRprime(double[][] cVals, double[] skew, int ballSize) { 82 double[] Rp = new double[ballSize];

83 for (int i = 0; i < ballSize; i++) {

84 Rp[i] = cVals[1][i] * Math.cos(skew[i]) - cVals[3][i]

85 * Math.sin(skew[i]);

86 }

87 return Rp;

88 }

89

90 public double[][] getCvalues(double[][] dValues, double[][] ur, 91 double[][] uc, double[][] vr, double[][] vc, int ballSize) { 92 double[][] cValues = new double[4][ballSize];

93 for (int i = 0; i < ballSize; i++) { 94 cValues[0][i] = dValues[0][i] 95 * (0.5 * (dValues[0][i] * ur[2][i] + dValues[1][i] 96 * uc[1][i]) + ur[1][i]) 97 + dValues[1][i] 98 * (0.5 * (dValues[0][i] * uc[1][i] - dValues[1][i] 99 * ur[2][i]) + uc[0][i]) + ur[0][i] / 2; 100 cValues[1][i] = dValues[1][i] 101 * (0.5 * (dValues[0][i] * ur[2][i] + dValues[1][i] 102 * uc[1][i]) + ur[1][i]) 103 - dValues[0][i] 104 * (0.5 * (dValues[0][i] * uc[1][i] - dValues[1][i] 105 * ur[2][i]) + uc[0][i]); 106 cValues[2][i] = dValues[0][i] 107 * (0.5 * (dValues[0][i] * vr[2][i] + dValues[1][i] 108 * vc[1][i]) + vr[1][i]) 109 + dValues[1][i] 110 * (0.5 * (dValues[0][i] * vc[1][i] - dValues[1][i] 111 * vr[2][i]) + vc[0][i]) + vr[0][i] / 2; 112 ; 113 cValues[3][i] = dValues[1][i] 114 * (0.5 * (dValues[0][i] * vr[2][i] + dValues[1][i] 115 * vc[1][i]) + vr[1][i]) 116 - dValues[0][i] 117 * (0.5 * (dValues[0][i] * vc[1][i] - dValues[1][i] 118 * vr[2][i]) + vc[0][i]); 119 } 120 return cValues; 121 } 122

(33)

calculateValues.java 125 double dvalues[][] = new double[9][ballSize]; 126 for (int i = 0; i < ballSize; i++) {

127 // d20 128 dvalues[0][i] = (ur[1][i] - ur[3][i]) * ur[2][i] 129 - (uc[2][i] - uc[0][i]) * uc[1][i]; 130 // d21 131 dvalues[1][i] = (ur[1][i] + ur[3][i]) * uc[1][i] 132 - (uc[2][i] + uc[0][i]) * ur[2][i]; 133 // d22 134 dvalues[2][i] = 0.5 * (Math.pow(ur[3][i], 2)

135 - Math.pow(ur[1][i], 2) + Math.pow(uc[2][i], 2) + Math.pow(

136 uc[0][i], 2)); 137 // d00 138 dvalues[3][i] = 0.5 * ((ur[0][i] + ur[2][i]) * dvalues[0][i] 139 + uc[1][i] * dvalues[1][i] + 2 * ur[1][i] * dvalues[2][i]); 140 // d01 141 dvalues[4][i] = 0.5 * (uc[1][i] * dvalues[0][i] 142 + (ur[0][i] - ur[2][i]) * dvalues[1][i] + 2 * uc[0][i] 143 * dvalues[2][i]); 144 // d02 145 dvalues[5][i] = 0.5 * (ur[1][i] * dvalues[0][i] + uc[0][i] 146 * dvalues[1][i] + ur[0][i] * dvalues[2][i]); 147 // d10 148 dvalues[6][i] = 0.5 * ((vr[0][i] + vr[2][i]) * dvalues[0][i] 149 + vc[1][i] * dvalues[1][i] + 2 * vr[1][i] * dvalues[2][i]); 150 // d11 151 dvalues[7][i] = 0.5 * (vc[1][i] * dvalues[0][i] 152 + (vr[0][i] - vr[2][i]) * dvalues[1][i] + 2 * vc[0][i] 153 * dvalues[2][i]); 154 // d12 155 dvalues[8][i] = 0.5 * (vr[1][i] * dvalues[0][i] + vc[0][i] 156 * dvalues[1][i] + vr[0][i] * dvalues[2][i]); 157 } 158 return dvalues; 159 } 160

161 public double[][] getComplexFourierCoeffs(int noOfProjections, 162 int[][][] coordinateVector, int ballSize, int UorV) { 163 double[][] complexSum = new double[3][ballSize];

164 double[][] Complex1 = new double[noOfProjections][ballSize]; 165 double[][] Complex2 = new double[noOfProjections][ballSize]; 166 double[][] Complex3 = new double[noOfProjections][ballSize]; 167 double radians = Math.PI / 180;

168 double ProjectionAngle = 360 / noOfProjections; 169 for (int i = 0; i < noOfProjections; i++) { 170 for (int j = 0; j < ballSize; j++) {

171 Complex1[i][j] = Math.sin(1 * radians * ProjectionAngle * i

172 * sense);

173 Complex2[i][j] = Math.sin(2 * radians * ProjectionAngle * i

174 * sense);

175 Complex3[i][j] = Math.sin(3 * radians * ProjectionAngle * i

176 * sense);

177 }

178 }

179 for (int i = 0; i < noOfProjections; i++) { 180 for (int j = 0; j < ballSize; j++) { 181 complexSum[0][j] = complexSum[0][j]

182 + coordinateVector[j][UorV][i] * Complex1[i][j] * 2

183 / noOfProjections;

184 complexSum[1][j] = complexSum[1][j]

(34)

calculateValues.java 187 complexSum[2][j] = complexSum[2][j]

188 + coordinateVector[j][UorV][i] * Complex3[i][j] * 2

189 / noOfProjections; 190 } 191 } 192 return complexSum; 193 } 194

195 public double[][] getRealFourierCoeffs(int noOfProjections, 196 int[][][] coordinateVector, int ballSize, int UorV) { 197 double[][] realSum = new double[4][ballSize];

198 double[][] Real1 = new double[noOfProjections][ballSize]; 199 double[][] Real2 = new double[noOfProjections][ballSize]; 200 double[][] Real3 = new double[noOfProjections][ballSize]; 201 double[][] Real4 = new double[noOfProjections][ballSize]; 202 double radians = Math.PI / 180;

203 double ProjectionAngle = 360 / noOfProjections; 204 for (int i = 0; i < noOfProjections; i++) { 205 for (int j = 0; j < ballSize; j++) {

206 Real1[i][j] = Math.cos(0 * radians * ProjectionAngle * i

207 * sense);

208 Real2[i][j] = Math.cos(1 * radians * ProjectionAngle * i

209 * sense);

210 Real3[i][j] = Math.cos(2 * radians * ProjectionAngle * i

211 * sense);

212 Real4[i][j] = Math.cos(3 * radians * ProjectionAngle * i

213 * sense);

214 }

215 }

216 for (int i = 0; i < noOfProjections; i++) { 217 for (int j = 0; j < ballSize; j++) {

218 realSum[0][j] = realSum[0][j] + Real1[i][j]

219 * coordinateVector[j][UorV][i] * 2 / noOfProjections; 220 realSum[1][j] = realSum[1][j] + Real2[i][j]

221 * coordinateVector[j][UorV][i] * 2 / noOfProjections; 222 realSum[2][j] = realSum[2][j] + Real3[i][j]

223 * coordinateVector[j][UorV][i] * 2 / noOfProjections; 224 realSum[3][j] = realSum[3][j] + Real4[i][j]

225 * coordinateVector[j][UorV][i] * 2 / noOfProjections;

226 }

227 }

228 return realSum;

229 }

(35)

Controller.java 1import java.awt.image.BufferedImage; 3

4public class Controller implements Observe { 5 imageJFileChooser iJCF; 6 GUI gui; 7 ImageProcessing IP; 8 ROI roi; 9 Trajectories traj; 10 int width = 2400; 11 int height = 2400; 12 int noOfImages; 13 int noOfBalls; 14 int[][][] allCoordsArray; 15 int contrastInt = 1; 16 int mx1, mx2, my1, my2 = 0; 17

18 // CONSTRUCTOR

19 public Controller() {

20 iJCF = new imageJFileChooser();

21 try {

22 gui = new GUI(iJCF); 23 } catch (IOException e) {

24 // TODO Auto-generated catch block

25 e.printStackTrace();

26 }

27 iJCF.AddObserver(this); 28 gui.AddObserver(this); 29 }

30

31 publicvoid runImageProcess() { 32 noOfBalls = 0;

33 noOfImages = roi.getNoOfImages(iJCF.getFileName()); 34 boolean firstImageRun = true;

35 String filename = iJCF.getFileName().replace("001.bin", ""); 36 String tempFilename;

37 for (int i = 1; i <= noOfImages; i++) { 38 if (firstImageRun) {

39 IP = new ImageProcessing(iJCF.getFileName(), contrastInt, mx1,

40 mx2, my1, my2);

41 allCoordsArray = new int[getNoOfBallsFromImage()][2][noOfImages]; 42 allCoordsArray[0][0][0] = IP.getCoordList().get(0).get(0); 43 allCoordsArray[0][1][0] = IP.getCoordList().get(0).get(1); 44 firstImageRun = false;

45 } else {

46 if (i < 10) {

47 tempFilename = filename + "00" + i + ".bin"; 48 } elseif (i < 100) {

49 tempFilename = filename + "0" + i + ".bin";

50 } else {

51 tempFilename = filename + i + ".bin";

52 }

53 System.out.printf("Image processed: %d\n", i); 54 gui.setNoOfImagesLabel(i);

55 IP = new ImageProcessing(tempFilename, contrastInt, mx1, mx2,

56 my1, my2);

57 new Thread() {

58 public void run() {

59 setNoOfBallsLabelView();

60 }

61 }.start();

62 // Show image in Frame

63 new Thread() {

Page 1

(36)

Controller.java

64 public void run() {

65 BufferedImage panelImage = IP.scaleBufferedImage(

66 IP.getBufferedImage(), 0.2);

67 gui.setImageToGoPanel(panelImage);

68 }

69 }.start();

70 for (int j = 0; j < IP.getCoordList().size(); j++) { 71 if (IP.getCoordList().size() <= allCoordsArray.length) {

72 // Find the closest one and put it there

73 // NOOFBALLS IS SET TO 7, MAKE SURE IT CHANGES TAKES IN

74 // A NOOFBALLS-VARIABLE

75 // Check if none of the balls in the previous image was 76 if (IP.getCoordList().size() == noOfBalls) { 77 allCoordsArray[j][0][i - 1] = IP.getCoordList() 78 .get(j).get(0); 79 allCoordsArray[j][1][i - 1] = IP.getCoordList() 80 .get(j).get(1); 81 } else { 82 System.out.printf("noOfBalls: %d\n", IP 83 .getCoordList().size());

84 intyCoord = IP.getCoordList().get(j).get(0);

85 intxCoord = IP.getCoordList().get(j).get(1);

86 if (yCoord == 0) {

87 }

88 intdist = (int) Math.sqrt(Math.pow(

89 Math.abs(yCoord

90 - allCoordsArray[0][0][i - 2]), 2)

91 + Math.pow(Math.abs(xCoord

92 - allCoordsArray[0][1][i - 2]), 2));

93 intidy = 0;

94 for (int k = 1; k < IP.getCoordList().size(); k++) {

95 int cDist = (int) Math.sqrt(Math.pow(

96 Math.abs(yCoord 97 - allCoordsArray[k][0][i - 2]), 98 2) 99 + Math.pow(Math.abs(xCoord 100 - allCoordsArray[k][1][i - 2]), 101 2)); 102 System.out

103 .printf("Distance for ball %d = %d\n",

104 k, cDist); 105 if (cDist < dist) { 106 dist = cDist; 107 idy = k; 108 } 109 }

110 System.out.printf("idy = %d\n", idy);

111 allCoordsArray[idy][0][i - 1] = IP.getCoordList()

112 .get(j).get(0);

113 allCoordsArray[idy][1][i - 1] = IP.getCoordList()

114 .get(j).get(1);

115 }

116 }

117 }

118 }

119 noOfBalls = noOfBalls + getNoOfBallsFromImage();

120 }

121 noOfBalls = noOfBalls / noOfImages; 122 // Make Trajectory

123 gui.enableTrajectoryButton();

124 calculateValues calcVal = new calculateValues(allCoordsArray, width,

(37)

Controller.java

126 traj = new Trajectories(allCoordsArray, width, height, noOfBalls);

127 }

128

129 public BufferedImage getCurrentImage() { 130 return IP.getBufferedImage();

131 }

132

133 public int getNoOfBallsFromImage() { 134 return IP.getNoOfBalls();

135 }

136

137 public void setNoOfBallsLabelView() {

138 gui.setBallLabel(getNoOfBallsFromImage());

139 }

140

141 public void setCoordLabelView() { 142 gui.setCoordLabel(IP.getCoordList());

143 }

144

145 public void setImageToContentPane() {

146 gui.setImageToContentPane(IP.getBufferedImage());

147 }

148

149 public void setDirectoryString(String directoryString) { 150 gui.setTextFieldString(directoryString);

151 }

152

153 public void setROIimgGui() {

154 }

155

156 @Override

157 public void Update() {

158 // TODO Auto-generated method stub 159 runImageProcess();

160 gui.setRunButtonText("Run Calculation");

161 }

162

163 @Override

164 public void UpdateTextFieldString(String s) { 165 // TODO Auto-generated method stub 166 gui.setTextFieldString(s);

167 }

168

169 @Override

170 public void UpdateROIimg() {

171 // TODO Auto-generated method stub

172 try {

173 roi = new ROI(iJCF.getFileName(), width, height); 174 roi.AddObserver(this);

175 roi.startROIimg();

176 gui.loadROIimgFrame(roi.getAfterPic()); 177 gui.setROIButtonText("Select ROI"); 178 gui.disposeDialog();

179 } catch (IOException e) {

180 // TODO Auto-generated catch block 181 e.printStackTrace();

182 }

183 }

184

185 @Override

(38)

Controller.java 188 contrastInt = contrast;

189 }

190

191 @Override

192 public void UpdateROIimgRotation() { 193 // TODO Auto-generated method stub 194 gui.disposeROI();

195 try {

196 roi = new ROI(iJCF.getFileName(), width, height); 197 } catch (IOException e) {

198 // TODO Auto-generated catch block 199 e.printStackTrace();

200 }

201 roi.AddObserver(this); 202 roi.startROIimgWithRotation();

203 gui.loadROIimgFrame(roi.getAfterPic()); 204 gui.setRunButtonEnabled();

205 gui.setROIButtonText("Select ROI"); 206 gui.disposeDialog();

207 }

208

209 @Override

210 public void UpdateRIO(int mx1, int mx2, int my1, int my2) { 211 // TODO Auto-generated method stub

212 this.mx1 = mx1; 213 this.mx2 = mx2; 214 this.my1 = my1; 215 this.my2 = my2;

216 }

217

218 @Override

219 public void UpdateTrajectoryFrame() { 220 // TODO Auto-generated method stub 221 traj.startTrajectory();

222 }

(39)

GUI.java 1import java.awt.BorderLayout;

36

37public class GUI implements Subject { 38 JLabel coordLabel;

39 JPanel contentPane = new JPanel(); 40 JPanel imageContentPane = new JPanel(); 41 JPanel middlePanel;

42 JTextField imageDirectoryTextField; 43 private JFrame mainFrame;

44 private JFrame contrastFrame;

45 private JPanel controlPanel = new JPanel(); 46 private JPanel goPanel = new JPanel(); 47 private JLabel ballLabel;

48 private JPanel contrastImagePanel = new JPanel(); 49 private JFrame ROIFrame;

50 private ImageIcon imageIcon; 51 private JLabel noOfImagesLabel;

52 private JPanel buttomPanel = new JPanel(); 53 JDialog dialog;

54 JPanel dialogPanel; 55 JLabel dotLoadingLabel; 56 private JLabel imageLabel;

57 private JButton runButton = new JButton("Run Calculation"); 58 private JButton ROIButton = new JButton("Select ROI"); 59 private JButton settingsButton = new JButton("Settings"); 60 private JButton trajectoryButton = new JButton("Show Trajectory"); 61 staticfinal int contrastMax = 30;

62 staticfinal int contrastMin = 0; 63 staticfinal int contrastInit = 10; 64 private int mx1, mx2, my1, my2; 65 JSlider contrastSlider; 66 imageJFileChooser iJFC;

67 private ArrayList<Observe> observers; 68

69 public GUI() { 70 }

71

72 public GUI(imageJFileChooser iJFC) throws IOException { 73 this.iJFC = iJFC;

74 observers = new ArrayList<Observe>(); 75 runButton.setForeground(Color.blue); 76 prepareGUI(); 77 showImageButtonJPanel(); 78 showDirectoryJPanel(); 79 showBallJPanel(); 80 showGoJPanel();

81 mainFrame.add(controlPanel); 82 mainFrame.add(goPanel); 83 mainFrame.add(buttomPanel); 84 mainFrame.setVisible(true); 85 }

86

87 private void prepareGUI() {

88 mainFrame = new JFrame("Detector Calibration"); 89 mainFrame.setSize(1800, 1000);

90 mainFrame.setLayout(new GridLayout(3, 1)); 91 mainFrame.addWindowListener(new WindowAdapter() { 92 publicvoid windowClosing(WindowEvent windowEvent) {

93 System.exit(0);

94 }

95 });

96 BufferedImage firstBuffered = new BufferedImage(200, 400,

Page 1

(40)

GUI.java 97 BufferedImage.TYPE_USHORT_GRAY); 98 imageIcon = new ImageIcon();

99 imageIcon.setImage(firstBuffered);

100 imageDirectoryTextField = new JTextField("No directory chosen"); 101 ballLabel = new JLabel("Number of balls: ");

102 controlPanel.setLayout(new GridLayout(1, 3)); 103 goPanel.setLayout(new GridLayout(1, 3)); 104 buttomPanel.setLayout(new GridLayout(1, 3)); 105 JPanel rightButtomPanel = new JPanel();

106 rightButtomPanel.setLayout(new GridLayout(5, 2)); 107 runButton.setEnabled(false);

108 trajectoryButton.setEnabled(false);

109 ROIButton.addActionListener(new ActionListener() {

110 @Override

111 public void actionPerformed(ActionEvent e) {

112 if (imageDirectoryTextField.getText().contains(".bin")) { 113 ROIButton.setText("Loading ROI");

114 new Thread() {

115 public void run() {

116 dialog = new JDialog();

117 dialogPanel = new JPanel();

118 JPanel dialogPanel2 = new JPanel(); 119 dialog.setLayout(new GridLayout(2, 1));

120 dialog.add(dialogPanel);

121 dialog.add(dialogPanel2);

122 dialog.setUndecorated(true);

123 dotLoadingLabel = new JLabel("");

124 Dimension screenSize = Toolkit.getDefaultToolkit()

125 .getScreenSize();

126 Double dwidth = screenSize.getWidth(); 127 Double dheight = screenSize.getHeight();

128 intwidth = dwidth.intValue();

129 intheight = dheight.intValue();

130 dialog.setPreferredSize(new Dimension(400, 200)); 131 dialog.setBounds(width / 2 - 200, height / 2 - 100,

132 dialog.getWidth(), dialog.getHeight());

133 dialog.pack();

134 JLabel loadingLabel = new JLabel("Loading ROI");

135 loadingLabel.setFont(loadingLabel.getFont()

136 .deriveFont(30.0f));

137 dotLoadingLabel.setFont(loadingLabel.getFont()

138 .deriveFont(30.0f));

139 dialogPanel.add(loadingLabel);

140 dialogPanel2.add(dotLoadingLabel);

141 dialog.setVisible(true);

142 Timer timer = new Timer();

143 timer.schedule(new UpdateLoadingROILabel(), 0, 500);

144 }

145 }.start();

146 new Thread() {

147 public void run() {

148 NotifyObserversROIimg();

149 }

150 }.start();

151 } else {

152 final JFrame exceptionFrame = new JFrame(); 153 JButton exitButton = new JButton("OK");

154 exceptionFrame.getContentPane().setLayout(

155 new GridLayout(2, 1));

156 exceptionFrame

157 .getContentPane()

(41)

GUI.java

159 "Please choose the first file. Ends with 001.bin")); 160 exceptionFrame.getContentPane().add(exitButton);

161 exceptionFrame.setBounds(mainFrame.getWidth() / 2 - 150, 162 mainFrame.getHeight() / 2 - 50, 300, 100);

163 exceptionFrame.setVisible(true);

164 exitButton.addActionListener(new ActionListener() {

165 @Override

166 public void actionPerformed(ActionEvent e) {

167 exceptionFrame.dispose(); 168 } 169 }); 170 } 171 } 172 });

173 runButton.addActionListener(new ActionListener() {

174 @Override

175 public void actionPerformed(ActionEvent e) {

176 if (imageDirectoryTextField.getText().contains(".bin")) { 177 runButton.setText("Running...");

178 new Thread() {

179 public void run() {

180 NotifyObservers();

181 }

182 }.start();

183 } else {

184 final JFrame exceptionFrame = new JFrame(); 185 JButton exitButton = new JButton("OK");

186 exceptionFrame.getContentPane().setLayout(

187 new GridLayout(2, 1));

188 exceptionFrame

189 .getContentPane()

190 .add(new JLabel(

191 "Please choose the first file. Ends with 001.bin")); 192 exceptionFrame.getContentPane().add(exitButton);

193 exceptionFrame.setBounds(mainFrame.getWidth() / 2 - 150, 194 mainFrame.getHeight() / 2 - 50, 300, 100);

195 exceptionFrame.setVisible(true);

196 exitButton.addActionListener(new ActionListener() {

197 @Override

198 public void actionPerformed(ActionEvent e) {

199 // TODO Auto-generated method stub

200 exceptionFrame.dispose();

201 }

202 });

203 }

204 runButton.setText("Run Calculation");

205 }

206 });

207 settingsButton.addActionListener(new ActionListener() {

208 @Override

209 public void actionPerformed(ActionEvent e) { 210 // TODO Auto-generated method stub 211 JFrame settingsFrame = new JFrame();

212 settingsFrame.getContentPane().setLayout(new GridLayout(2, 1)); 213 contrastSlider = new JSlider(JSlider.HORIZONTAL, contrastMin,

214 contrastMax, contrastInit);

215 contrastSlider.addChangeListener(new ChangeListener() {

216 @Override

217 public void stateChanged(ChangeEvent e) { 218 if (contrastSlider.getValueIsAdjusting()) {

(42)

GUI.java

221 }

222 });

223 contrastSlider.setMajorTickSpacing(10); 224 contrastSlider.setMinorTickSpacing(1); 225 contrastSlider.setPaintTicks(true); 226 contrastSlider.setPaintLabels(true);

227 contrastImagePanel.setPreferredSize(new Dimension(2000, 2000)); 228 contrastImagePanel.setVisible(true);

229 contrastFrame = new JFrame("Settings");

230 contrastFrame.getContentPane().setLayout(new GridLayout(3, 1)); 231 contrastFrame.add(contrastSlider);

232 contrastFrame.add(contrastImagePanel); 233 contrastFrame.pack();

234 contrastFrame.setVisible(true);

235 }

236 });

237 trajectoryButton.addActionListener(new ActionListener() {

238 @Override

239 public void actionPerformed(ActionEvent e) { 240 NotiifyObserverShowTrajectory();

241 }

242 });

243 noOfImagesLabel = new JLabel("Images Processed: "); 244 imageLabel = new JLabel();

245 Border border = BorderFactory.createLineBorder(Color.darkGray, 5); 246 JPanel imagePanel = new JPanel();

247 JPanel insideImagePanel = new JPanel(); 248 insideImagePanel.setLayout(new BorderLayout()); 249 imagePanel.setLayout(new GridLayout(1, 4)); 250 imagePanel.add(new JPanel());

251 imagePanel.add(new JPanel()); 252 imagePanel.add(new JPanel()); 253 imagePanel.add(insideImagePanel);

254 insideImagePanel.add(noOfImagesLabel, BorderLayout.NORTH); 255 insideImagePanel.add(imageLabel, BorderLayout.CENTER); 256 imageLabel.setBorder(border);

257 goPanel.add(imagePanel); 258 buttomPanel.add(new JPanel()); 259 buttomPanel.add(new JPanel()); 260 buttomPanel.add(rightButtomPanel); 261 rightButtomPanel.add(trajectoryButton); 262 rightButtomPanel.add(new JPanel()); 263 rightButtomPanel.add(new JPanel()); 264 rightButtomPanel.add(new JPanel()); 265 rightButtomPanel.add(new JPanel()); 266 rightButtomPanel.add(new JPanel());

267 }

268

269 public void updateContrastFrame(BufferedImage bI) {

270 contrastFrame.getContentPane().add(new JLabel(new ImageIcon(bI))); 271 contrastImagePanel.add(new JLabel(new ImageIcon(bI)));

272 }

273

274 private void showBallJPanel() { 275 JPanel panel = new JPanel(); 276 panel.setLayout(new FlowLayout()); 277 panel.add(ballLabel);

278 controlPanel.add(panel);

279 }

280

(43)

GUI.java 283 panel.setLayout(new FlowLayout()); 284 panel.add(iJFC, FlowLayout.LEFT); 285 controlPanel.add(panel);

286 }

287

288 private void showDirectoryJPanel() { 289

290 JPanel panel = new JPanel(); 291 panel.setLayout(new FlowLayout());

292 imageDirectoryTextField.setPreferredSize(new Dimension(400, 30)); 293 panel.add(imageDirectoryTextField, FlowLayout.LEFT);

294 controlPanel.add(panel);

295 }

296

297 private void showGoJPanel() { 298 middlePanel = new JPanel();

299 middlePanel.setLayout(new FlowLayout()); 300 middlePanel.add(runButton);

301 middlePanel.add(ROIButton); 302 middlePanel.add(settingsButton); 303 goPanel.add(middlePanel);

304 }

305

306 public void loadROIimgFrame(BufferedImage ROIImage) { 307 final Graphics2D g2d = ROIImage.createGraphics(); 308 ROIFrame = new JFrame();

309 JButton okButton = new JButton("OK"); 310 JButton cancelButton = new JButton("Cancel");

311 JButton rotateButton = new JButton("Rotate Clockwise"); 312 final JLabel xAxisLabel = new JLabel("X:");

313 final JLabel yAxisLabel = new JLabel("Y:"); 314 final JLabel xAxisLabel2 = new JLabel("X:"); 315 final JLabel yAxisLabel2 = new JLabel("Y:");

316 rotateButton.addActionListener(new ActionListener() {

317 @Override

318 public void actionPerformed(ActionEvent e) {

319 new Thread() {

320 public void run() {

321 dialog = new JDialog();

322 dialogPanel = new JPanel(); 323 JPanel dialogPanel2 = new JPanel(); 324 dialog.setLayout(new GridLayout(2, 1));

325 dialog.add(dialogPanel);

326 dialog.add(dialogPanel2); 327 dialog.setUndecorated(true); 328 dotLoadingLabel = new JLabel("");

329 Dimension screenSize = Toolkit.getDefaultToolkit()

330 .getScreenSize();

331 Double dwidth = screenSize.getWidth(); 332 Double dheight = screenSize.getHeight();

333 int width = dwidth.intValue();

334 int height = dheight.intValue();

335 dialog.setPreferredSize(new Dimension(400, 200)); 336 dialog.setBounds(width / 2 - 200, height / 2 - 100, 337 dialog.getWidth(), dialog.getHeight());

338 dialog.pack();

339 JLabel loadingLabel = new JLabel("Loading new Image"); 340 loadingLabel.setFont(loadingLabel.getFont().deriveFont(

341 30.0f));

342 dotLoadingLabel.setFont(loadingLabel.getFont()

(44)

GUI.java

345 dialogPanel2.add(dotLoadingLabel);

346 dialog.setVisible(true);

347 // Set timer for loading dialog box

348 Timer timer = new Timer();

349 timer.schedule(new UpdateLoadingROILabel(), 0, 500);

350 }

351 }.start();

352 new Thread() {

353 public void run() {

354 NotifyObserverRotate();

355 }

356 }.start();

357 }

358 });

359 cancelButton.addActionListener(new ActionListener() {

360 @Override

361 public void actionPerformed(ActionEvent e) { 362 // TODO Auto-generated method stub 363 System.out.println("Cancel"); 364 ROIFrame.dispose();

365 }

366 });

367 final JLabel test = new JLabel(new ImageIcon(ROIImage)); 368 JScrollPane scrollPane = new JScrollPane(test);

369 scrollPane

370 .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);

371 scrollPane

372 .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 373 Dimension preferredSize;

374 if (ROIImage.getWidth() <= 1500 && ROIImage.getHeight() <= 700) { 375 preferredSize = new Dimension(ROIImage.getWidth(),

376 ROIImage.getHeight());

377 } else if (ROIImage.getWidth() <= 1500 && ROIImage.getHeight() > 700) { 378 preferredSize = new Dimension(ROIImage.getWidth(), 700);

379 } else if (ROIImage.getWidth() > 1500 && ROIImage.getHeight() <= 700) { 380 preferredSize = new Dimension(1500, ROIImage.getHeight());

381 } else {

382 preferredSize = new Dimension(1500, 700);

383 }

384 scrollPane.setPreferredSize(preferredSize); 385 scrollPane.setMaximumSize(preferredSize); 386 test.addMouseListener(new MouseAdapter() { 387 private Boolean clicked = false; 388

389 @Override

390 public void mousePressed(MouseEvent e) { 391 if (clicked == false) {

392 mx1 = e.getX();

393 my1 = e.getY();

394 xAxisLabel.setText("X: " + mx1); 395 yAxisLabel.setText("Y: " + my1); 396 System.out.println(mx1 + ", " + my1);

397 clicked = true;

398 } else if (clicked == true) {

399 mx2 = e.getX();

400 my2 = e.getY();

401 System.out.println(mx2 + ", " + my2);

402 clicked = false;

(45)

GUI.java

407 g2d.setColor(Color.BLACK);

408 test.paint(g2d);

409 xAxisLabel2.setText("X: " + mx2); 410 yAxisLabel2.setText("Y: " + my2);

411 }

412 ROIFrame.repaint();

413 }

414

415 @Override

416 public void mouseReleased(MouseEvent e) {

417 }

418

419 });

420

421 okButton.addActionListener(new ActionListener() { 422

423 @Override

424 public void actionPerformed(ActionEvent e) { 425 // TODO Auto-generated method stub 426 System.out.println("OK");

427 NotifyObserverROI();

428 System.out.println(mx1 + ", " + my1 + " and " + mx2 + ", "

429 + my2); 430 ROIFrame.dispose(); 431 setRunButtonEnabled(); 432 } 433 }); 434

435 JPanel rightPanel = new JPanel(new GridLayout(20, 1)); 436

437 rightPanel.add(new JLabel("First Coordinates:")); 438 rightPanel.add(xAxisLabel);

439 rightPanel.add(yAxisLabel);

440 rightPanel.add(new JLabel("Second Coordinates:")); 441 rightPanel.add(xAxisLabel2);

442 rightPanel.add(yAxisLabel2); 443 rightPanel.add(new JPanel()); 444 rightPanel.add(new JPanel()); 445 rightPanel.add(new JPanel()); 446 rightPanel.add(new JPanel()); 447 rightPanel.add(new JPanel()); 448 rightPanel.add(new JPanel()); 449 rightPanel.add(new JPanel()); 450 rightPanel.add(new JPanel()); 451 rightPanel.add(new JPanel()); 452 rightPanel.add(new JPanel()); 453 rightPanel.add(new JPanel()); 454 rightPanel.add(rotateButton); 455 rightPanel.add(okButton); 456 rightPanel.add(cancelButton); 457

458 ROIFrame.getContentPane().add(rightPanel, BorderLayout.EAST); 459 ROIFrame.getContentPane().add(scrollPane, BorderLayout.CENTER); 460 ROIFrame.setResizable(false);

461 ROIFrame.pack();

462 ROIFrame.setVisible(true); 463

464 }

465

(46)

GUI.java

469 System.out.printf("Width: %d\nHeight: %d\n\n", image.getWidth(),

470 image.getHeight());

471

472 }

473

474 public void setBallLabel(int noOfBalls) {

475 String ballString = String.valueOf(noOfBalls); 476 ballLabel.setText("Number of Balls: " + ballString); 477

478 }

479

480 // Is this supposed to be in this class?

481 private String convertIntegerListToString(List<List<Integer>> list) { 482 int[][] tempToStringArray = new int[list.size()][2];

483 String outputString = "<html>"; 484 int ballInt = 0;

485

486 for (int i = 0; i < list.size(); i++) {

487 tempToStringArray[i][0] = list.get(i).get(0); 488 tempToStringArray[i][1] = list.get(i).get(1);

489 ballInt++;

490

491 outputString += "Ball " + ballInt + ":<br>x:" 492 + tempToStringArray[i][0] + "<br>y: " 493 + tempToStringArray[i][1] + "<br><br> "; 494 } 495 outputString += "</html>"; 496 ballInt = 0; 497 498 return outputString; 499 } 500

501 public void setImageToContentPane(BufferedImage image) { 502

503 // System.out.println("FRAME");

504 BufferedImage scaledImage = new BufferedImage(image.getWidth(), 505 image.getHeight(), BufferedImage.TYPE_INT_ARGB); 506 AffineTransform at = new AffineTransform();

507 at.scale(0.4, 0.4);

508 at.translate(image.getWidth() * 0.5, image.getHeight() * 0.5); 509 // at.rotate(Math.PI/2);

510 at.translate(-image.getWidth() * 0.5, -image.getHeight() * 0.5); 511 AffineTransformOp scaleOp = new AffineTransformOp(at,

512 AffineTransformOp.TYPE_BILINEAR); 513 scaledImage = scaleOp.filter(image, scaledImage); 514 setImageToGoPanel(scaledImage);

515 }

516

517 public void setCoordLabel(List<List<Integer>> ballCoordArray) { 518

519 coordLabel.setText(convertIntegerListToString(ballCoordArray)); 520 coordLabel.setBounds(20, 20, 50, 550);

521 controlPanel.add(coordLabel); 522

523 }

524

525 public void setTextFieldString(String directoryString) { 526 imageDirectoryTextField.setText(directoryString);

527 }

528

(47)

GUI.java

531 }

532

533 public void openImageInFrame(BufferedImage image) { 534 JScrollPane scrollPane = new JScrollPane(new JLabel( 535 new ImageIcon(image)));

536 scrollPane

537 .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);

538 scrollPane

539 .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 540

541 JButton contrastButton = new JButton("Cancel"); 542

543 contrastButton.addActionListener(new ActionListener() { 544

545 @Override

546 public void actionPerformed(ActionEvent e) { 547 // TODO Auto-generated method stub 548

549 }

550 });

551

552 JFrame frame = new JFrame();

553 frame.getContentPane().setLayout(new GridLayout(1, 2)); 554 frame.getContentPane().add(scrollPane);

555 frame.pack();

556 frame.setVisible(true); 557

558 }

559

560 public void setROIButtonText(String text) { 561

562 ROIButton.setText(text);

563 }

564

565 public void setRunButtonText(String text) { 566

567 runButton.setText(text);

568 }

569

570 public void disposeROI() { 571 ROIFrame.dispose();

572 }

573

574 public void setNoOfImagesLabel(int noOfImages) {

575 noOfImagesLabel.setText("Images processed: " + noOfImages);

576 }

577

578 public void disposeDialog() { 579 dialog.dispose();

580 }

581

582 public void enableTrajectoryButton() { 583 trajectoryButton.setEnabled(true);

584 }

585

586 // OBSERVERS 587

588 @Override

(48)

GUI.java 593

594 @Override

595 public void RemoveObserver(Observe o) { 596 // TODO Auto-generated method stub 597 observers.remove(o);

598 }

599

600 @Override

601 public void NotifyObservers() { 602 // TODO Auto-generated method stub

603 for (int i = 0; i < observers.size(); i++) { 604 observers.get(i).Update();

605 }

606

607 }

608

609 @Override

610 public void NotifyObserversTextField() { 611 // TODO Auto-generated method stub 612

613 }

614

615 @Override

616 public void NotifyObserversROIimg() { 617 // TODO Auto-generated method stub

618 for (int i = 0; i < observers.size(); i++) { 619 observers.get(i).UpdateROIimg();

620 }

621 }

622

623 @Override

624 public void NotifyObserversContrast(int contrast) { 625 // TODO Auto-generated method stub

626 for (int i = 0; i < observers.size(); i++) { 627 observers.get(i).UpdateContrast(contrast);

628 }

629 }

630

631 @Override

632 public void NotifyObserverRotate() { 633 // TODO Auto-generated method stub

634 for (int i = 0; i < observers.size(); i++) { 635 observers.get(i).UpdateROIimgRotation();

636 }

637

638 }

639

640 @Override

641 public void NotifyObserverROI() { 642 // TODO Auto-generated method stub

643 for (int i = 0; i < observers.size(); i++) { 644 observers.get(i).UpdateRIO(mx1, mx2, my1, my2);

645 }

646 }

647

648 // Subclasses

649 class UpdateLoadingROILabel extends TimerTask { 650 public void run() {

651 if (dotLoadingLabel.getText() == "") { 652 dotLoadingLabel.setText(".");

(49)

GUI.java 655

656 } else if (dotLoadingLabel.getText() == "..") { 657 dotLoadingLabel.setText("...");

658

659 } else if (dotLoadingLabel.getText() == "...") { 660 dotLoadingLabel.setText("....");

661

662 } else if (dotLoadingLabel.getText() == "....") { 663 dotLoadingLabel.setText(""); 664 665 } 666 667 } 668 } 669 670 @Override

671 public void NotiifyObserverShowTrajectory() { 672 // TODO Auto-generated method stub

673 for (int i = 0; i < observers.size(); i++) { 674 observers.get(i).UpdateTrajectoryFrame();

675 }

676 }

(50)

ImageProcessing.java 1import java.awt.FlowLayout;

21

22public class ImageProcessing { 23

24 private int[][] resultImgMatrix; 25 private int minContrast = 40000;

26 private List<List<Integer>> ballCoordArray = new ArrayList<List<Integer>>(); 27 private BufferedImage image;

28 29 // Size of images 30 int width = 1024; 31 int height = 2048; 32 33 int contrastInt; 34 35 // Constructor

36 public ImageProcessing(String imageName, int contrastInt, intmx1, intmx2, 37 int my1, int my2) {

38

39 this.contrastInt = contrastInt; 40

41 try {

42 resultImgMatrix = getDataArray(width, height, imageName); 43

44 } catch (IOException e) {

45 // TODO Auto-generated catch block

46 e.printStackTrace();

47 }

48

49 // CALCULATE MAX AND MIN VALUES

50 int max = resultImgMatrix[0][0]; 51 int min = resultImgMatrix[0][0]; 52

53 for (int i = 0; i < resultImgMatrix.length; i++) { 54 for (int j = 0; j < resultImgMatrix[0].length; j++) { 55 if (resultImgMatrix[i][j] > max) {

56 max = resultImgMatrix[i][j]; 57 } elseif (resultImgMatrix[i][j] < min) { 58 min = resultImgMatrix[i][j];

59 }

60 }

61 }

62 // END CALC MAX/MIN

63

64 // ContrastCorrection

65 resultImgMatrix = contrastArrayCorrection(resultImgMatrix, 1); 66 resultImgMatrix = contrastArrayCorrection(resultImgMatrix, 2); 67 resultImgMatrix = fullContrastCorrection(resultImgMatrix); 68

69 if (mx1 != 0 && mx2 != 0) {

(51)

ImageProcessing.java

82 public int[][] getDataArray(int x, int y, String filename) 83 throws IOException {

84

85 FileInputStream is = new FileInputStream(filename); 86 byte[] bytes = ByteStreams.toByteArray(is); 87

88 int[][] data = new int[x][y]; 89 int c = 0;

90

91 for (int i = 0; i < x; i++) { 92 for (int j = 0; j < y; j++) {

93 data[i][j] = (bytes[c] & 0xff) | (short) (bytes[c + 1] << 8); 94 if (data[i][j] < 0) { 95 data[i][j] = 65536 + data[i][j]; 96 } 97 c = c + 2; 98 } 99 100 } 101 102 is.close(); 103 return data; 104 } 105

106 public int[][] contrastArrayCorrection(int[][] imageArray, 107 double contrastValue) {

108 int min = imageArray[0][0]; 109 int max = min;

110 // Calc min and max values

111 for (int i = 0; i < imageArray.length; i++) { 112 for (int j = 0; j < imageArray[0].length; j++) { 113 if (imageArray[i][j] < min) {

114 min = imageArray[i][j];

115 } else if (imageArray[i][j] > max) { 116 max = imageArray[i][j];

117 }

118 }

119 }

120

121 int middleValue = max / 2;

122 for (int i = 0; i < imageArray.length; i++) { 123 for (int j = 0; j < imageArray[0].length; j++) { 124

125 if ((imageArray[i][j] - (middleValue - imageArray[i][j]))

126 * contrastValue < 0) {

127 imageArray[i][j] = min;

128 } else if ((imageArray[i][j] + (imageArray[i][j] - middleValue))

129 * contrastValue >= max) {

130 imageArray[i][j] = 65000;

131 } else if (imageArray[i][j] < middleValue) {

132 imageArray[i][j] = (int) ((imageArray[i][j] - (middleValue - imageArray[i][j])) * contrastValue);

133 } else if (imageArray[i][j] > middleValue) {

(52)

ImageProcessing.java

142 public BufferedImage scaleBufferedImage(BufferedImage image, 143 double scaleFactor) {

144

145 Double dwidth = image.getWidth() * scaleFactor; 146 int width = dwidth.intValue();

147 Double dheight = image.getHeight() * scaleFactor; 148 int height = dheight.intValue();

149

150 BufferedImage scaledImage = new BufferedImage(width, height, 151 BufferedImage.TYPE_INT_RGB);

152

153 Graphics g = scaledImage.createGraphics(); 154 g.drawImage(image, 0, 0, width, height, null); 155 g.dispose();

156

157 return scaledImage;

158 }

159

160 public int[][] fullContrastCorrection(int[][] array) { 161

162 for (int i = 0; i < array.length; i++) { 163 for (int j = 0; j < array[0].length; j++) { 164 if (array[i][j] >= minContrast) { 165 array[i][j] = 65000; 166 } else { 167 array[i][j] = 0; 168 } 169 } 170 } 171 172 return array; 173 } 174

175 private int[][] contrastCorrection(int[][] matrix) { 176

177 BufferedImage bufferedImage = new BufferedImage(width, height, 178 BufferedImage.TYPE_BYTE_GRAY);

179 for (int i = 0; i < matrix.length; i++) { 180 for (int j = 0; j < matrix[0].length; j++) { 181 int pixel = matrix[i][j];

182

183 bufferedImage.setRGB(i, j, pixel); 184

185 }

186 }

187

188 final byte[] pixels = ((DataBufferByte) bufferedImage.getRaster() 189 .getDataBuffer()).getData();

190

191 final boolean hasAlphaChannel = bufferedImage.getAlphaRaster() != null; 192

193 int[][] result = new int[width][height]; 194 if (hasAlphaChannel) {

195 final int pixelLength = 4;

196 for (int pixel = 0, row = 0, col = 0; pixel < pixels.length; pixel += pixelLength) {

197 int argb = 0;

(53)

ImageProcessing.java 203 col++; 204 if (col == width) { 205 col = 0; 206 row++; 207 } 208 } 209 } else {

210 final int pixelLength = 3;

211 for (int pixel = 0, row = 0, col = 0; pixel < pixels.length; pixel += pixelLength) {

212 int argb = 0;

213 argb += -16777216; // 255 alpha

214 argb += ((int) pixels[pixel] & 0xff); // blue

215 argb += (((int) pixels[pixel + 1] & 0xff) << 8); // green 216 argb += (((int) pixels[pixel + 2] & 0xff) << 16); // red 217 result[row][col] = argb;

218 col++; 219 if (col == width) { 220 col = 0; 221 row++; 222 } 223 } 224 } 225 226 return result; 227 228 } 229

230 public BufferedImage getImage(String picName) {

231 try {

232 image = ImageIO.read(getClass().getResource(picName)); 233

234 // Contrast

235 RescaleOp rescaleOp = new RescaleOp(1.8f, -190, null); 236 RescaleOp rescaleOp2 = new RescaleOp(4f, 0, null); 237 rescaleOp.filter(image, image);

238 rescaleOp2.filter(image, image); 239 240 return image; 241 242 } catch (IOException e) { 243 e.printStackTrace(); 244 245 return null; 246 } 247 248 } 249

250 private int[][] flipMatrixClockwise(int[][] inputMatrix) {

251 int[][] outputMatrix = new int[inputMatrix[0].length][inputMatrix.length]; 252 int[][] tempMatrix = new int[inputMatrix[0].length][inputMatrix.length]; 253

254 // Transpose

255 for (int i = 0; i < inputMatrix.length; i++) { 256 for (int j = 0; j < inputMatrix[0].length; j++) { 257 tempMatrix[j][i] = inputMatrix[i][j];

258 }

259 }

260 // Flip each row

References

Outline

Related documents

I dagsläget är priset på elcertifikat väldigt låga och om priserna på elcertifikat blir varaktigt låga och närmar sig administrationskostnaderna anser branschföreningen Svensk

Dock anser Chalmers att det inte bara är uppfyllandet av målet för elcertifikatsystemet som ska beaktas vid ett stopp utan även balansen mellan tillgång och efterfrågan av

Missa inte vårt politiska nyhetsbrev som varje vecka sammanfattar de viktigaste nyheterna om företagspolitik. Anmäl

Till följd av en miss i hanteringen uppmärksammades igår att Havs- och vattenmyndigheten inte inkommit med något remissvar på Promemorian Elcertifikat stoppregel och

Adress 103 85 Stockholm Besbksadress Ringviigen 100 Tele/on 08-7001600 konkurrensverket@kkv.se.

handläggningen har också föredragande vej amhetsanalytiker Peter Vikström

J an-Olof Olsson har varit

Dessutom har utbyggnaden av förnybar elproduktion fortgått vilket leder till att det är än mer sannolikt än tidigare att målet om totalt 46,4 TWh förnybar elproduktion till