universiteit gent faculteit ingenieurswetenschappen...
TRANSCRIPT
Universiteit Gent
Faculteit Ingenieurswetenschappen
Vakgroep
Elektronica en Informatiesystemen
Voorzitter: Prof. Dr. Ir. J. Van Campenhout
Inbedbare DICOM-viewer voor browsers en framework
in het kader van E-learning
door
Sabine DE VREESE
Promotor: Prof. Dr. Ir. I. Lemahieu
Scriptie ingediend tot het behalen van de academische graad van Licentiaat in de Informatica
Academiejaar 2005-2006
Universiteit Gent
Faculteit Ingenieurswetenschappen
Vakgroep
Elektronica en Informatiesystemen
Voorzitter: Prof. Dr. Ir. J. Van Campenhout
Inbedbare DICOM-viewer voor browsers en framework
in het kader van E-learning
door
Sabine DE VREESE
Promotor: Prof. Dr. Ir. I. Lemahieu
Scriptie ingediend tot het behalen van de academische graad van Licentiaat in de Informatica
Academiejaar 2005-2006
Inbedbare DICOM-viewer voor browsers en framework
in het kader van E-learning
door
Sabine DE VREESE
Scriptie ingediend tot het behalen van de academische graad van
Licentiaat in de Informatica
Academiejaar 2005-2006
Promotor: Prof. Dr. Ir. I. Lemahieu
Faculteit Ingenieurswetenschappen
Universiteit Gent
Vakgroep Elektronica en Informatiesystemen
Voorzitter: Prof. Dr. Ir. J. Van Campenhout
Samenvatting
In het eerste deel werd een applet ontwikkeld ten behoeve van de studenten Geneeskunde zodat
zij via het Internet op interactieve manier radiologische beelden zouden kunnen bekijken.
De implementatie van dit applet gebeurde in de reeds bestaande omgeving ImageJ.
In het tweede deel komt een studie van ImageJ aan bod. Via bestaande heuristieken werd
ImageJ aan een kritisch onderzoek onderworpen, dit zowel op het vlak van lay-out als van
implementatie.
Trefwoorden: medische beeldverwerking, ImageJ, usability, OO-ontwerp
De auteur geeft de toelating deze scriptie voor consultatie beschikbaar te stellen en delen van
de scriptie te kopiëren voor persoonlijk gebruik.
Elk ander gebruik valt onder de beperkingen van het auteursrecht, in het bijzonder met
betrekking tot de verplichting de bron uitdrukkelijk te vermelden bij het aanhalen van
resultaten uit deze scriptie
Inbedbare DICOM-viewer voor browsers en framework in het kader van E-learning
Sabine De Vreese
Promoter: Prof. Dr. Ir. I. Lemahieu
Abstract—An applet to view medical images was implemented using ImageJ. This article first describes some implementation issues. Next, the methods used to perform a critical study of ImageJ and the results from this study are presented. Keywords—Medical Images, ImageJ, Usability Engineering, Object Oriented Design
I. INTRODUCTION
his article consists of mainly two parts. The first part discusses some details of the
implementation of an applet, by which medical images, like CT-scans and DICOM images can be viewed. The main purpose of the applet is to offer Med students a flexible way to interactively work with medical scans. The applet was implemented using ImageJ. ImageJ is a public domain Java image processing program. It can display, edit, analyze, process, save and print 8-bit, 16-bit and 32-bit images. Many image formats including TIFF, GIF, JPEG, BMP can be read. It also supports “stacks”. Because of some odd pecularities that drew my attention during the implementation phase, ImageJ was submitted to a strict investigation. On one hand, the usability of ImageJ was tested, on the other hand the implementation of ImageJ was researched.
II. APPLET
A. Functions of the applet The applet starts by reading a stack of images from the server and can build entirely new axial, coronal or sagittal slices using the pixels of the input stack. There’s also the possibility to make oblique slices. One can zoom in and out, scroll, adjust brightness and contrast by dragging the mouse. B. Implementation details The most important functionality throughout the applet is building new images using the input stack. Instead of treating orthogonal views seperately from oblique views, here, the orthogonal views are considered as special cases of oblique views. So only one function needed to be implemented. To simplify this implementation, the input stack, when read from the server, is first converted to a coronal stack.
Afterwards the input pixels of the coronal stack are saved in a 3D-array.
Fig. 1. Coordinate System B1, B2, B3and the plane
A cartesian coordinate system B2 is linked to this 3D-array, this can be seen in figure 1. Figure 1 also shows two other cartesian coordinate systems, namely B1 and B3 and a plane. This plane represents the resulting image and therefor, to become the oblique view, we need to know for every pixel of this plane to which pixel of the 3D-array it corresponds to. This can be calculated by means of transition matrices between B1, B2 and B3. As B2 rotates, different oblique views become visible. During the implementation specific problems rose due to the fact that this is an applet and not a regular application: the input of an applet is restricted to files from the server on which the applet resides. How were these problems solved? Let’s first mention that the directory on the server containing the medical scans, is called RadiologyImages. Every time someone visits the website with the applet, some PHP code is executed. This code makes a listing of all the files and subdirectories of the RadiologyImages directory and of all it’s subdirectories. The findings of this code are saved in textfiles on the server: one for each (sub)directory. This is the first step. In the second step a filechooser, that was build completely from scratch, is able to communicate directly with the server. This filechooser reads these textfiles and presents the content of the textfile to the user in a typical filechooser way. When the user doubleclicks a directory in the filechooser, a request is sent to the server to obtain the matching textfile of this directory and after receiving this file the content is shown by the filechooser. On the other hand, when the user doubleclicks an image, the
T
server receives a request to send the corresponding image. This all works very well. The most important drawback however is that the size of the images on the server may not be too large to assure reasonable response time.
III. STUDY OF IMAGEJ
A. Layout After the implementation of the applet was completed, some research took place. To investigate the usability of ImageJ, three tests, extracted from the field of Usability Engineering, were carried out. Usability Engineering is concerned with the question of how to design software that is easy to use. It is closely related to the field of human-computer interaction and industrial design. It describes several methods to examine the user friendliness of GUI’s in a structured way: Usability Inspection methods and Usability Testing methods are such methods. Usability Inspection is the generic name for a set of methods that are all based on having evaluators inspect a user interface. Typically, Usability Inspection is aimed at finding usability problems in the design. The Usability Inspection method used in this survey is called Heuristic Evaluation and involves having someone judge whether each dialogue element follows established usability principles (the "heuristics"). Usability Testing methods on the other hand address the overall usability of an entire system. Usability Testing is a means for measuring how well people can use some human-made object, like a website, for its intended perpose. In this survey two usability tests took place: a Paper-and-Pencil Test and a Thinking Aloud Test. In a Paper-and-Pencil Test, test users show aspects of the interface on paper and answer questions. It deals with the first impression the user gets from the system. During a Thinking Aloud Test, test users are presented with a list of tasks to perform. While doing each task the test user verbalise his thoughts, tells what he expects to happen and continuously gives his opinion about the system that is tested. As a result of these three tests a few structural problems on the layout of ImageJ were revealed. Heuristic Evaluation was the method that gave most results. We found out that ImageJ sometimes suffers from inconsistency and demands too much knowledge of image processing to be easy to use. The results from the Think Aloud Test confirmed the findings we got from Heuristic Evaluation. The Paper-and-Pencil Test did not provide many new insights. B. Implementation To survey the implementation of ImageJ, the source code was compared to ten well accepted principles of good object oriented design. It turns out abstraction is the key to good object oriented programming and a whole system should consist of some instable, easy to
change packages at the top and some stable, easy to extend packages at the bottom. A simple glance at the source code of ImageJ makes clear that ImageJ rarely uses abstraction: there are only 4 abstract classes on a total number of 99 classes. In addition, the packages, of which ImageJ consists, are very strictly related to one another, as one can see in figure 2.
Fig. 2. Dependencies between the main packages of ImageJ
Finally the Instability and Abstractness of each of the packages was calculated. Figure 3 shows the Instability versus the Abstractness of the packages of ImageJ. Packages should appear at either the two black points (0,1) or (1,0) on figure 3. Those at the upper left are completely abstract and very stable. Those at the lower right are completely concrete and very instable. This is the way it should be. It is clear however that ImageJ does not even come close to this ideal situation. This makes ImageJ a very stable system but even so very difficult to change.
Fig. 3. Instability and Abstractness of the packages of ImageJ
IV. CONCLUSIONS
The implementation of the applet was quite difficult. ImageJ, first supposed to be a great help, turned out to be hard to adapt.
ACKNOWLEDGMENTS
The author would like to acknowledge Prof. I. Lemahieu and Lic. P. Vandemaele for their help.
Inhoudsopgave
I. Inleiding ......................................................................................................... 1 I. 1. Waar het allemaal mee begon ........................................................................ 1 I. 2. Over Wilhelm Röntgen, CT-scan, MRI en DICOM...................................... 3 I. 3. ImageJ ............................................................................................................ 8 I. 4. Functies van het applet................................................................................. 11 II. Implementatie............................................................................................... 14 II. 1. Inleiding ....................................................................................................... 14 II. 2. Algemeen ..................................................................................................... 14 II. 3. Nieuwe beelden berekenen .......................................................................... 18 II. 4. Applet........................................................................................................... 22 III. Kritische studie ............................................................................................ 30 III. 1. Inleiding ....................................................................................................... 30 III. 2. De omkadering............................................................................................. 30 III. 3. Studie van de lay-out.................................................................................... 33 III. 3. 1. Inleiding ....................................................................................................... 33 III. 3. 2. Wat is Usability Engineering ....................................................................... 33 III. 3. 3. Wat zijn Usability Inspection methodes ...................................................... 34 III. 3. 4. Wat zijn Usability Testing methodes ........................................................... 35 III. 3. 5. Usability Inspection en ImageJ .................................................................... 35 III. 3. 6. Usability Testing en ImageJ......................................................................... 40 III. 3. 7. Usability Inspection en ImageJ : de resultaten............................................. 43 III. 3. 8. Usability Testing en ImageJ : de resultaten ................................................. 49 III. 3. 9. Besluit .......................................................................................................... 52 III. 4. Studie van de implementatie ........................................................................ 53 III. 4. 1. Inleiding ....................................................................................................... 53 III. 4. 2. Heuristieken voor goed object georiënteerd ontwerp .................................. 53 III. 4. 3. Heuristieken voor goed object georiënteerd ontwerp en ImageJ................. 60 III. 4. 4. Suggestie ...................................................................................................... 68 III. 4. 5. Besluit .......................................................................................................... 68 IV. Besluit .......................................................................................................... 69 Appendix A..................................................................................................................... 70 Appendix B ..................................................................................................................... 72 Bibliografie ..................................................................................................................... 75
1
I. Inleiding I. 1. Waar het allemaal mee begon Medische scans. Tot voor het aanvangen van deze scriptie waren ze mij voornamelijk bekend
van op TV. ER, Grey’s Anatomy, … u kent dat wel. Het zijn de wit-zwart-grijze foto’s die aan
een lichtgevende bak worden gehangen en meer dan eens uitsluitsel geven over de mysterieuze
ziekte waar deze of gene patiënt aan lijdt. In tegenstelling tot wat deze series – waarin de
traditionele scans nog volop worden gebruikt – laten geloven, is dit type scan echter met
uitsterven bedreigd. Tegenwoordig worden scans immers bekeken met behulp van computers
met grafisch krachtige software aan boord. Deze hedendaagse manier van werken biedt
mogelijkheden die met de traditionele scans ondenkbaar zijn, zoals 3D-voorstellingen.
Dit eindwerk vindt zijn oorsprong bij deze medische scans en meer in het bijzonder bij de wil
van Professor Achten om studenten Geneeskunde op vlotte manier met deze scans te leren
werken. Professor Achten is het hoofd van de afdeling Medische Beeldvorming aan het
Universitair Ziekenhuis Gent, en doceert verscheidene cursussen Medische Beeldvorming aan
studenten Geneeskunde. Hij was voornamelijk op zoek naar een eenvoudige methode die de
studenten Geneeskunde zou toelaten op levendige wijze kennis te maken met de beginselen
van de Medische Beeldvorming. Bovendien is uitgebreide ICT-ondersteuning momenteel ook
dé heersende trend in onderwijsmilieus: meer dan één aggregaatscursus gaat gebukt onder de
superlatieven die worden toegeschreven aan de student die door middel van ICT een actieve
onderzoeker wordt in plaats van een passieve herkauwer.
Tot op heden wordt er in de cursussen Medische Beeldvorming ook al een beroep gedaan op
ICT: medisch beeldmateriaal wordt namelijk op een website ter beschikking gesteld van de
studenten, zodat deze bij het instuderen de beelden opnieuw kunnen bekijken en gebruiken,
Figuur I-1 CT-scan bekeken met lichtbak Figuur I-2 MRI-scan bekeken met PC
2
maar daar houdt de ICT-ondersteuning op. Dezer dagen biedt het Internet echter veel meer
mogelijkheden. Professor Achten kwam dan ook met het idee op de proppen om een applet te
maken, dat de software waarmee DICOM-beelden door professionelen worden bekeken, zo
goed mogelijk nabootst.
Er werd uitdrukkelijk voor een applet gekozen en niet voor een klassieke applicatie. Zo hoeven
de studenten immers geen programma te downloaden en te installeren: de juiste website
bezoeken volstaat om zich voor even een echte radioloog te wanen. Een ander voordeel is dat
op deze manier heel gemakkelijk extra scans aan de studenten ter beschikking kunnen gesteld
worden, het volstaat om de nieuwe beelden naar de juiste map op de server te kopiëren en de
volgende keer dat de studenten de website bezoeken, kunnen ze de nieuwe scans raadplegen.
De implementatie van dit applet maakte het eerste deel uit van dit eindwerk. Na een speurtocht
op het Internet bleek algauw dat het niet nodig was om de implementatie helemaal vanaf nul te
starten. In plaats daarvan werd het applet geïmplementeerd als plugin van ImageJ. Wat dit
precies mag betekenen komt u in de volgende pagina’s te weten. In het uiteindelijke applet
worden volgende functies geïmplementeerd
• openen van allerlei medische beelden
• zoemen en scrollen
• windowing en centering
• uitgaande van een stapel beelden nieuwe doorsneden maken: zowel axiale, sagittale,
coronale als oblique doorsneden zijn mogelijk
Na de implementatie volgde in het tweede luik het onderzoek. In dit deel werd ImageJ onder de
loep genomen, zowel de lay-out als de broncode werden aan een kritisch onderzoek
onderworpen.
De eerstvolgende pagina’s van dit inleidende hoofdstuk vertellen over de inzichten die ik heb
verworven toen ik mijzelf wegwijs maakte in de vele beeldvormingstechnieken die de
medische wereld rijk is. In de daaropvolgende paragraaf wordt ImageJ besproken. Tot slot van
dit eerste hoofdstuk, wordt de functionaliteit van het geïmplementeerde applet kort toegelicht.
In hoofdstuk twee worden vervolgens de interessantste implementatiedetails besproken. Dat
het geen sinecure was om het programmeren van dit applet tot een goed einde te brengen, mag
blijken uit het derde hoofdstuk van onderhavige tekst, waarin de resultaten van de kritische
studie van ImageJ omstandig behandeld worden.
3
I. 2. Over Wilhelm Röntgen, CT-scan, MRI en DICOM Vooraleer te kunnen begrijpen wat DICOM-beelden precies zijn, bleek het noodzakelijk een
omweg te maken langs Wilhelm Röntgen, CT-scans en MRI’s. Dit
verhaal begon op de avond van 8 november 1895…
Wilhelm Röntgen was reeds gedurende meer dan een jaar in zijn
verduisterde laboratorium aan het experimenteren met een
kathodestraalbuis. Vanavond had Röntgen de buis overdekt met een
koker van zwart karton om te voorkomen dat er kathodestralen
zouden weglekken. Tot zijn grote verbijstering merkte hij bij zijn
proefnemingen dat een met fluorescerende verf behandeld scherm
bij elke ontlading van de buis helder oplichtte, ook al lag er meer
dan 2 meter tussen de buis en het scherm. Gedurende
daaropvolgende experimenten vond hij dat objecten die in de
stralenbundel werden geplaatst, met een variërende helderheid
konden worden vastgelegd op een fotografische plaat. Na een
maand van hard labeur, nam hij op 22 december van datzelfde jaar
zijn vrouw mee naar zijn laboratorium. Toen de hand van zijn
vrouw de stralenbundel obstrueerde, werd duidelijk dat de stralen
gemakkelijk door de huid heen drongen, maar werden
tegengehouden door bot. De schaduw van het bot kon worden vastgelegd op een fotografische
plaat: de eerste röntgenfoto was een feit. Omdat de aard van de nieuwe stralen nog onbekend
was, gaf hij de stralen de naam X-stralen. Zijn ontdekking, waarvoor hij in 1901 de Nobelprijs
kreeg, betekende een drastische verandering voor de geneeskunde, aangezien het nu mogelijk
werd met röntgenapparatuur binnenin het lichaam te kijken. Röntgen weigerde om morele
redenen de röntgenstraal of de toepassingen ervan te patenteren en stierf in armoede op 10
februari 1923 in München.
Het principe van röntgenstraling is dus vrij eenvoudig: Straling wordt door weefsel gezonden
en laat een afdruk na op een fotografische plaat. Daar waar de dichtheid van het weefsel het
hoogst is, dringt de straling minder goed door en laat de plaat dus relatief onberoerd.
De volgende stap van klassieke (niet-ontwikkelde) foto’s naar digitale foto’s laat zich al raden.
Als je namelijk de fotografische plaat verwisselt voor een digitaal sensorveld, kunnen de
signalen doorgegeven worden aan een computer waarop het beeld wordt weergegeven.
Figuur I-3 W. Röntgen
Figuur I-4 De hand van mevr. Röntgen
4
Wanneer je het röntgenapparaat vervolgens laat schuiven (en dus
telkens een ander stukje fotografeert), kun je de plaatjes achter
elkaar monteren. Zo simuleer je een 3D-beeld. Deze techniek
wordt Computed Tomography genoemd, afgekort CT. De CT-
scan wordt voor alle organen in het lichaam gebruikt.
Een MRI-scanner is nog een ander technisch hoogstandje. De
afkorting staat voor Magnetic Resonance Imaging, of in het
Nederlands, magnetische resonantie beeldvorming. Een oudere naam is NMR-scanner, van
Nuclear Magnetic Resonance, ofwel kernspinresonantie, maar deze term is in onbruik geraakt
omdat hij bij leken het volledig onjuiste beeld van
kernreacties en schadelijke straling opriep.
Het was begin 1970 dat de Amerikaanse
biofysicus Raymond Damadian zich als eerste
realiseerde dat met NMR beeldvorming van
levend weefsel kon worden gemaakt. Tegen 1977
kon hij een eerste, enorm groot, prototype van de
MRI-scanner laten zien. Vanaf toen ging de
ontwikkeling snel en ieder jaar worden er
verbeteringen in de beeldvorming en verwerking
aangebracht.
De werking van een MRI-scanner berust hierop dat isotopen met een oneven aantal
kerndeeltjes, bijvoorbeeld waterstof en fosfor, een magnetisch veld maken. Dit miniscule
magneetje kan met een extern magneetveld mee, of tegen een extern magneetveld in werken.
Dit is een kwantumeffect, dit wil zeggen tussenstanden zijn niet mogelijk. Tussen deze twee
toestanden bestaat een energieverschil, afhankelijk van de sterkte van het externe magneetveld.
Wordt de kern nu blootgesteld aan een puls elektromagnetische straling met precies de goede
energie (bij MRI-scanners zijn dat radiogolven), dan kan de spin daardoor omklappen. De zo
'aangeslagen' kern valt na een tijdje weer terug in de grondtoestand onder het uitzenden van een
foton. Door een gradiënt in de sterkte van het magneetveld te maken, de waterstofkernen aan te
slaan en dan te meten hoeveel straling van verschillende golflengten terugkomt van de
terugvallende spins kun je te weten komen op welke plaats hoeveel waterstofkernen zitten. De
enorme hoeveelheden metingen worden in een krachtige computer verwerkt tot een 3-
dimensionaal plaatje dat bijvoorbeeld het waterstofgehalte van de weefsels van de patiënt
aangeeft. Aangezien allerlei soorten weefsel verschillende waterstofdichtheden hebben, kunnen
Figuur I-5: CT-scanner
Figuur I-6 MRI-scanner
5
op die manier details van de anatomie worden waargenomen. Bloed is bijvoorbeeld te
onderscheiden van vet en van orgaanweefsel.
Om het resultaat te visualiseren wordt de scan door de computer meestal als een aantal 'plakjes'
van het lichaam of het hoofd gepresenteerd, die naar keuze in de drie anatomische vlakken –
sagittaal, coronaal of axiaal – kunnen worden bekeken. Vaak kan zelfs elk mogelijk vlak onder
willekeurige hoek gekozen worden: de gegevens kunnen door een snelle computer op iedere
gewenste manier worden gepresenteerd.
Hoewel de beelden van een MRI-onderzoek in eerste instantie lijken op die van een CT-
scanner zijn er toch grote verschillen. Een CT-scanner meet absorptie van röntgenstraling,
vooral het dichte calcium in botten valt daardoor sterk op. Een mogelijk nadeel is dat de
straling schade kan aanrichten in het lichaam. Een MRI-scanner meet dan weer het voorkomen
van één element, vaak is dat waterstof en stelt de patiënt niet bloot aan gevaarlijke straling. Er
zijn echter wel andere gevaren, zoals het eerder genoemde sterke magnetisme.
CT en MRI vullen elkaar aan, ze kunnen elkaar niet helemaal vervangen. MRI is bijzonder
nuttig om gedetailleerde beelden te krijgen van de hersenen en de ruggengraat.
Figuur I-8 CT-scan van de hersenen
Figuur I-9 MRI-scan van de hersenen
Figuur I-7 Sagittale, Coronale en Axiale doorsnede van het lichaam
6
Nog een laatste vraag bleef onbeantwoord: “Wat is DICOM en waarvoor dient het?”
DICOM is een acroniem voor Digital Imaging and Communications in Medicine, anders
geformuleerd: met behulp van de DICOM standaard kan een enorm scala aan medische
beelden uitgewisseld worden, dus zowel CT-scans als MRI’s als nog andere beelden. Om
hiertoe te komen bevat een DICOM beeld pixeldata plus tientallen beschrijvende
informatieblokken.
DICOM vond zijn oorsprong begin de jaren ’70. De intrede van de gedigitaliseerde medische
beelden bracht het American College of Radiology (ACR) en het National Electrical
Manufacturers Association (NEMA) er immers toe om een comité op te richten met de
bedoeling een standaard methode te formuleren voor de uitwisseling van medische beelden en
de er bijhorende informatie. Het comité kwam er in 1983 en publiceerde in 1985 de eerste
ACR-NEMA standaard. Voordien gebruikten verschillende toestellen eigen formaten voor de
opslag en transfer van medische beelden. Hoewel deze eerste standaard reeds een stap in de
goede richting betekende, kwam er pas een echte doorbraak in het gebruik van de standaard in
1993. Niet alleen werd de verbeterde standaard met een nieuwe naam – DICOM – bedacht, er
werden belangrijke verbeteringen aangebracht, waardoor de standaard gemeen goed werd. Zo
was er het toevoegen van een netwerk protocol op basis van TCP-IP en de mogelijkheid om
bijvoorbeeld ook informatie over patiënten te definiëren in plaats van enkel beelden.
Figuur I-10 Virtueel DICOM-bestand
Figuur I-11 Virtuele DICOM-hoofdding
7
Eén DICOM-bestand bestaat enerzijds uit een hoofdding en anderzijds uit afbeeldingspixels.
De hoofdding bevat informatie, zoals de naam van de patiënt, het type scan, de afmetingen van
de scan, … . De grootte van de hoofdding is afhankelijk van de hoeveelheid informatie die
erin opgeslagen is. Welke info er precies opgenomen wordt, hangt op zijn beurt samen met de
aard van de ingesloten afbeelding. Wanneer het bijvoorbeeld om een DICOM bestand van een
MRI-scan gaat, wordt doorgaans het tijdstip waarop de scan werd gemaakt, opgenomen in de
hoofdding.
In de hoofdding wordt de informatie sequentieel georganiseerd onder de vorm van
opeenvolgende elementen.
Elk dergelijk element bestaat uit 3 velden
• Veld 1 (lengte = 8 octetten) : bevat één van de voorgedefinieerde DICOM – tags en legt
vast welke informatie Veld 3 bevat. De eerste 4 octetten leggen de groep vast waartoe
deze informatie behoort, de volgende 4 octetten wat deze informatie precies is.
Bijvoorbeeld als de leeftijd van de patiënt wordt opgenomen in de hoofdding, is de
DICOM – tag hiervoor 0x0010 1010
• Veld 2 (lengte = 8 octetten) : geeft de lengte van Veld 3
Bijvoorbeeld voor wat betreft de leeftijd, dit wordt gecodeerd in 2 octetten, dus krijgen
we voor het tweede veld 0x0000 0002
• Veld 3 (lengte vastgelegd door Veld 2) : de eigenlijke informatie
Stel dat we binnen een hoofdding de volgende stroom gegevens terugvinden (hexadecimaal)
00 10 00 20 00 00 00 0A 4A 6F 68 6E 5E 48 65 6E 72 79
dan heeft dit volgende betekenis
00 10 → de informatie in Veld 3 behoort tot de groep ‘informatie over de patiënt’
00 20 → de informatie in Veld 3 is de naam van de patiënt
00 00 00 0A → lengte van Veld 3 = 10
4A 6F 68 6E 5E 48 65 6E 72 79 → John Henry
De hoofdding is dus een sequentie van soortgelijke elementen. Op die manier is het mogelijk
om uit de hoofdding precies die informatie te extraheren die men nodig heeft.
Figuur I-10 toont een hypothetisch DICOM bestand waarvan de hoofdding 794 bytes groot is
en waarin onder andere de afmetingen van de afbeelding zijn opgenomen.
In Figuur I-11 is een voorbeeld te zien van een virtuele hoofdding. De eerste 128 bytes van de
hoofdding zijn doorgaans 0, gevolgd door de letters ‘D’, ‘I’, ‘C’, ‘M’. Pas daarna volgt de
eigenlijke informatie onder de vorm van opeenvolgende elementen.
8
Toepassingsgebieden ImageJ
0,00%5,00%
10,00%15,00%20,00%25,00%30,00%35,00%
Bio
logi
e
Che
mie
Dig
itale
Fot
ogra
fie
Fys
ica
Gen
eesk
unde
Geo
graf
ie
Gra
fisch
ew
erel
d
Indu
strie
Ond
erw
ijs
And
ere
Categorie
I. 3. ImageJ Intussen is het woord ImageJ al verscheidene keren gevallen, zonder dat het tot dusver correct
gedefinieerd werd. Deze paragraaf heeft dan ook de bedoeling dit euvel weg te werken.
ImageJ is een fotobewerkingsprogramma. Niets bijzonders op het eerste zicht, want er bestaan
tegenwoordig een heleboel programma’s waarmee je foto’s te lijf kan gaan. Één van de
bekendste is zonder meer Adobe Photoshop en daarnaast bestaan er nog talloze andere. Dit
soort programma’s wordt traditioneel gebruikt om gebouwen op foto’s recht te zetten,
eventueel mensen te verwijderen, een extra kleurrijk randje toe te voegen, … ImageJ echter
houdt zich ver van dit soort praktijken vandaan. ImageJ wordt namelijk aangewend voor
wetenschappelijke doeleinden. Het wordt onder andere gebruikt door onderzoekers die aan de
hand van een foto de grootte van een orgaan willen meten of die beelden afkomstig van een
microscoop moeten kunnen bewerken. De wetenschappelijke domeinen waarin ImageJ zijn nut
bewijst zijn niet beperkt tot de geneeskunde of de biologie, ImageJ wordt evengoed gebruikt in
de fysica en de geografie. Op de de ‘ImageJ User & Developer Conference’ die plaatsvond op
18 en 19 mei 2006 werd aan de deelnemers gevraagd in welk gebied ze gebruik maakten van
ImageJ. Figuur I-12 laat de verdeling over de verschillende toepassingsgebieden zien.
Er zijn verschillende redenen waarom ImageJ zo’n polyvalente speler is. Eerst en vooral loopt
ImageJ zowel op Linux, Mac OS 9, Mac OS X als Windows. Een tweede belangrijke pluspunt
is dat ImageJ een waaier van verschillende formaten kan openen en opslaan, gaande van TIFF
en Gif over Jpeg tot BMP en ASCII-beelden. Ook is ImageJ in staat een breed scala van
beelden te analyseren, bewerken en filteren: zowel 8-bit, 16-bit en 32-bit beelden worden
ondersteund. Daarnaast kunnen hoeken, afstanden en oppervlaktes probleemloos berekend
Figuur I-12 In welk toepassingsgebied gebruikt u ImageJ?
9
worden. Tenslotte beschikt ImageJ nog over de klassieke beeldbewerkingsfuncties zoals
wijzigen van helderheid en contrast, verscherpen, vervagen, hoeken detecteren en de klassieke
geometrische transformaties als schalen, roteren en spiegelen.
ImageJ pretendeert ook ’s werelds snelst werkende fotobewerkingsprogramma geschreven in
Java te zijn. Zo kan het een foto van 2048 pixels x 2048 pixels in 0,1 seconde filteren. Dit
betekent 40 miljoen pixels per seconde!
Naast zoveel fraais, is er nóg een belangrijk concept dat het geheel zo mogelijks nog
aantrekkelijker maakt. ImageJ is namelijk volledig vrije software die publiek domein is en door
iedereen naar believen mag gebruikt en herbruikt worden zonder copyright. Daarenboven kan
iedereen zijn steentje bijdragen aan de verdere ontwikkeling van ImageJ. Zo bestaat enerzijds
de mogelijkheid tot het maken van macro’s om handelingen te automatiseren. Anderzijds, en
veel interessanter, is het voor gebruikers mogelijk om ImageJ “her uit te vinden” door het
schrijven van Java plugin’s. Dit zijn programmaatjes die veelal worden geschreven om een
specifiek fotobewerkingsprobleem op te lossen en waarmee de functionaliteit van ImageJ
moeiteloos kan worden uitgebreid en aan de eigen wensen aangepast. Plugin’s kunnen onder
meer worden aangewend om extra bestandsformaten te ondersteunen. Om te voorkomen dat
het warm water meer dan eens wordt uitgevonden, kunnen de plugin’s nadien met de andere
gebruikers gedeeld worden door zowel de programmacode als een uitvoerbaar bestand op de
ImageJ website te plaatsen. Momenteel zijn er reeds meer dan 300 plugin’s vrij beschikbaar.
Dit laat toe dat ImageJ constant verder blijft
groeien en bloeien. Dit proces wordt nog
bespoedigd door het bestaan van een
uitgebreide, wereldwijde gemeenschap van
ImageJ gebruikers die elkaar helpt via een
mailinglijst waaraan heel actief geparticipeerd
wordt.
Deze constante evolutie wordt in goede banen
geleid door Wayne Rasband, de oorspronkelijke bezieler van ImageJ, die werkt aan het
National Institute of Mental Health in Bethasda, Maryland, USA.
Figuur I-13 National Institute of Mental Health in Bethasda, Maryland, USA
10
Na zoveel woorden van lof, is het dringend tijd om het wonder eens van naderbij te gaan
bekijken. In Figuur I-14 staat ImageJ in z’n typische voorkomen, afgebeeld. Het ImageJ
venster heeft een weinig traditioneel uiterlijk. Vergeet de schermvullende vensters van MS
Word of Excel, het hoofdvenster van ImageJ is niets meer dan het grijze venstertje links
bovenaan Figuur I-14.
Het beschikt over de
traditionele menubalk
en werkbalk,
daaronder is de
statusbalk. De
werkbalk bevat
knoppen die toelaten
om selecties te
maken, tekst toe te
voegen, te zoemen en
te pannen. In de
statusbalk verschijnt
gebruikersinformatie,
bijvoorbeeld wanneer
men met de muis over een foto beweegt, kan men daar de correcte muiscoördinaten aflezen.
Aan de rechterkant van de statusbalk verschijnt er bij bewerkingen die
veel tijd vragen een balkje dat de voortgang aangeeft.
Analoog met andere foto-editeerprogramma’s zoals Adobe Photoshop
wordt elke nieuwe foto in een afzonderlijk venster geopend, dit is ook
te zien op Figuur I-14. Er bestaat ook de mogelijkheid om stapels
samen horende beelden, in vakjargon stacks genoemd, te openen. Het
venster beschikt dan onderaan over een schuifbalk die toelaat door de
stapel te navigeren.
Via http://studwww.ugent.be/~sdvreese kan u kennismaken met
ImageJ.
Figuur I-14 Schermafdruk van ImageJ
Figuur I-15 Een stack in ImageJ
11
I. 4. Functies van het applet Vooraleer dieper in te gaan op de
implementatiedetails van het applet, wordt eerst aan
de hand van een aantal vensters de gerealiseerde
functionaliteit van het applet toegelicht.
Het gemaakte applet is beschikbaar via de website
http://studwww.ugent.be/~sdvreese
In het venster ‘Open New Stack’ wordt de
gebruiker de mogelijkheid geboden om een nieuwe
stapel beelden te laden. Nadat dit gebeurd is, moet
de gebruiker via de keuzelijst de oriëntatie van de
stapel (axiaal, coronaal of sagittaal) vastleggen en
opgeven hoeveel de vermoedelijke afstand bedraagt
tussen twee beelden van de stapel.
Het venster ‘Show Slices’ is bedoeld om beelden
van de stapel te bekijken.
Figuur I-16 Het venster Open New Stack
Figuur I-17 Het venster Show Slices
12
Op deze beelden kan in – en uitgezoemd worden en de helderheid en contrast kunnen
aangepast worden door te slepen met de muis terwijl de rechtermuisknop wordt ingedrukt.
Bovendien bestaat de mogelijkheid om deze bewerkingen op alle slices tegelijk uit te voeren.
In de volgende vensters, ‘Orthogonal
Slices’ en ‘Orthogonal Stack’, worden
nieuwe beelden in de drie orthogonale
richtingen berekend. Het verschil
situeert zich vooral in de manier waarop
de resulterende beelden worden
gepresenteerd. In het venster
‘Orthogonal Slices’ worden de beelden
naast elkaar geplaatst, in het venster
‘Orthogonal Stack’ worden de nieuwe
afbeeldingen getoond onder de vorm van
een stack.
Het venster ‘Axial Coronal Sagittal View’ laat toe om tegelijk de axiale, coronale en sagittale
doorsnede door één punt te bekijken.
Figuur I-18 Het venster Orthogonal Stack
Figuur I-19 Het venster Axial Coronal Sagittal View
13
Tot slot is er het venster ‘Oblique View’. In dit venster kan men een willekeurige doorsnede
maken doorheen de stapel. De manier van doorsnijden wordt vastgelegd door de kubus aan de
linkerkant te roteren.
Figuur I-20 Het venster Oblique View
14
II. Implementatie II. 1. Inleiding Na de voorstelling van de mogelijkheden van het applet in het voorgaande hoofdstuk, komen in
dit hoofdstuk de interessantste problemen aan bod, die gedurende de implementatie de kop
opstaken.
Er wordt begonnen met wat algemene uitleg over de verschillende klassen die werden
geschreven. In de volgende paragraaf wordt er behandeld hoe op basis van de beschikbare
beelden nieuwe beelden worden gegenereerd, een functie die doorheen de volledige applicatie
prominent aanwezig is, en waar dus veel zorg aan besteed werd. Dit hoofdstuk wordt afgerond
met een paragraaf die gewijd is aan de specifieke problemen die moesten opgelost worden om
het applet te laten communiceren met de server.
II. 2. Algemeen
Alles samen bestaat het gecreëerde applet uit welgeteld 32 samenwerkende klassen. Het is
bijna hallucinant dat er zoveel tijd geslopen is in zo’n beperkt aantal klassen. Het moet echter
gezegd dat de weg niet altijd even goed verlicht en soms wat krom was, waardoor er heel wat
meer klassen het levenslicht hebben gezien, maar even snel weer werden afgevoerd wegens
niet afdoende.
Voor elk van de zeven vensters, ‘Welcome’, ‘Open New Stack’, … bestaat er een aparte klasse
LeftPanelx, deze klasse LeftPanelx is een extensie van de Java JPanel. Het grootste gedeelte,
meer dan de helft, van de code van deze klassen is bedoeld voor het goed functioneren van de
lay-out. Opdat de gele linkerdeelvensters er netjes zouden blijven uitzien ook nadat de
venstergrootte werd gewijzigd, moest er gebruik gemaakt worden van een BorderLayout. Álle
knoppen, tekstvakken, schuivers en zo meer worden bij de
initialisatie toegevoegd aan een noordelijk paneel. Daarnaast
bestaat er nog een centraal paneel, in hetzelfde kleur geel, dat
gewoon leeg is. We bevestigen dit noordelijk paneel aan
LeftPanel via BorderLayout.NORTH en het lege paneel via
BorderLayout.CENTER. Door deze constructie wordt alle ruimte
die beschikbaar komt bij het eventueel vergroten van het venster,
ingenomen door het lege paneel, waardoor de elementen op het noordelijk paneel netjes blijven
staan. De verschillende GUI elementen werden trouwens niet zomaar neergezet op het
Figuur II-1 LeftPanel Schematisch
15
noordelijke paneel, vaak was een ganse resem van subpanels, met telkens een geschikte
layoutmanager, nodig om het geheel er zo goed mogelijk te laten uitzien.
Behalve verantwoordelijk voor de lay-out, implementeren deze LeftPanels doorgaans een
heleboel interfaces zoals ActionListener, Mouse(Motion)Listener, ComponentListener, … om
de vele gebeurtenissen op te vangen. Tenslotte zorgen ze er ook voor dat in het
rechterdeelvenster de juiste beelden op de juiste plaats komen te staan. De berekening van de
beelden zelf gebeurt door middel van een afzonderlijke klasse Picture.
Bij de implementatie werd er constant dankbaar gebruik gemaakt van het Model View
Controller patroon. Dit was simpelweg noodzakelijk om acties die in één venster plaatsvinden
de juiste uitwerking te laten vinden in een ander venster. Helemaal vooraan in het programma
worden de verschillende modellen aangemaakt in de klasse WebApplet, dit is de klasse die
wordt opgeroepen bij het openen van de webpagina en die het hoofdvenster activeert. Via de
parameterlijst van de constructor van elk LeftPanel worden de models gedistribueerd naar de
verschillende deelvensters.
Hét belangrijkste model is de klasse ImageModel. ImageModel houdt alle data bij van de
stapel beelden die momenteel actief is: de pixels, de grootte en breedte, welke oriëntatie de
stapel heeft, …
Een ander voorbeeld van een model is de klasse FileChooserModel. FileChooserModel hoort
als vanzelfsprekend bij de klasse FileChooser, te zien in Figuur II-2. Deze klasse is de
implementatie van een typische bestandskiezer. Het was niet anders mogelijk, zo zal straks
blijken, dan zelf vanaf nul zo’n klasse op te bouwen. Er kon jammer genoeg geen gebruik
gemaakt worden van bijvoorbeeld de klasse JFileChooser zoals die al bestaat in Swing. Omdat
het implementeren van de volledige functionaliteit van de bestandskiezer in één bestand, zou
resulteren in een enorm grote klasse, werd in plaats daarvan gekozen voor drie afzonderlijke
klassen: FileChooserNorth, FileChooserCenter en FileChooserSouth. Deze drie klassen moeten
met elkaar moeten kunnen communiceren en omdat we de code niet wilden overbelasten, werd
ook hier gekozen voor het gebruik van het MVC patroon. Als bijvoorbeeld in
FileChooserCenter een bestand geselecteerd wordt, wordt dit meegedeeld aan
FileChooserModel die het op zijn beurt vertelt aan bijvoorbeeld FileChooserSouth. In
FileChooserSouth verschijnt dan de naam van het geselecteerde bestand in centrale tekstvak.
16
Een ander voorbeeld deed zich voor bij de communicatie tussen de bestandskiezer en het
hoofdvenster. Op het ogenblik dat er op de knop ‘Open’ rechts onderaan van de bestandskiezer
wordt geklikt, moet het hoofdvenster te weten komen welke stapel er werd geopend. Dit kan
gebeuren door een instantie van het hoofdvenster op te nemen in de klasse FileChooser, maar
die werkwijze wordt al vlug omslachtig en komt de transparantie van de code dikwijls niet ten
goede. Door daarentegen te werken via het MVC patroon wordt bekomen dat de klassen als
zelfstandige entiteiten kunnen fungeren, die enkel communiceren met het model en eigenlijk
niet van elkaars bestaan hoeven af te weten.
Behalve de LeftPanel’s werd ook nog een klasse ImageCanvasZSWC geschreven. Dit canvas
is een afgeleide klasse van ImageCanvas, dat al bestaat in ImageJ en voornamelijk wordt
gebruikt als achtergrond om een foto op te tekenen. ImageCanvas is op zijn beurt een extensie
van het klassieke Java Canvas. De laatste vier letters van ImageCanvasZSWC staan er
vanzelfsprekend met een goede reden. Het gaat namelijk om een ImageCanvas dat toelaat om
in en uit te Zoemen op het beeld, om het beeld te Scrollen en om Windowing en Centering toe
te passen. Windowing en Centering zijn twee begrippen die vooral in de context van medische
beeldvorming gebruikt worden, maar eigenlijk niets anders zijn dan een manier om de
helderheid en het contrast te beschrijven.
De figuur hieronder illustreert de concepten verandering in ‘window center’ en ‘window
width’. Bovenaan de figuur staat drie keer hetzelfde beeld maar telkens met een andere
verhouding tussen window center en window width (C:W). Onderaan de figuur wordt getoond
Figuur II-2 Bestandskiezer
17
hoe de beeldpixels een andere ‘kleur’ krijgen. Hierbij wordt de verticale as gebruikt voor
uiteenlopende helderheid en de horizontale as voor veranderende intensiteit.
Stel dat het beeld bestond uit pixels met een helderheid tussen 0 en 170. In dit geval is center =
85 en width = 171 een goed begin. Dit beeld wordt getoond op de middelste van de drie foto’s.
Wanneer de width verandert van 171 naar 71, verhoogt het contrast, zoals te zien op de
linkerfoto. Aan de andere kant, wanneer de width behouden blijft op 171, maar het center
daarentegen verminderd wordt naar 40, wordt het beeld helderder, zoals in het beeld rechts.
Het kunnen wijzigen van de C:W verhouding is in het bijzonder belangrijk om X-ray’s en CT-
scans goed te kunnen bekijken. Zo kan een verhouding 400:2000 interessant zijn om bot goed
te kunnen onderscheiden, terwijl 50:350 dan weer beter kan geschikt zijn voor het tonen van
zacht weefsel.
Figuur II-3 Windowing en Centering
Door het implementeren van de klasse ImageCanvasZSWC, was het dan wel mogelijk om in –
of uit te zoemen op één canvas, of de bewerkingen Windowing en Centering toe te passen
maar het laten samenwerken van alle canvassen tegelijk, zoals in de vensters ‘Show Slices’ en
‘Orthogonal Slices’, was daarmee nog niet gerealiseerd. Eigenlijk is de oplossing voor dit
probleem voor de hand liggend: probeer de muisbewerkingen op één canvas te achterhalen en
distribueer deze naar de overige canvassen. In het licht van al het voorgaande mag het niet
verbazen dat hiervoor opnieuw werd gebruik gemaakt van het MVC patroon. De
muisbewerkingen toegepast op één canvas worden gemeld aan MouseModel. Alle andere
canvassen zijn geregistreerd bij dit MouseModel en krijgen op die manier het klikken en slepen
18
van de muis op een buurcanvas te ‘horen’. Daardoor weten zij op hun beurt welke adequate
reactie van hen verwacht wordt.
II. 3. Nieuwe beelden berekenen
Tijdens de beschrijving van de functionaliteit van het applet op het einde van het vorige
hoofdstuk, kwam al duidelijk naar voor dat het noodzakelijk was om op efficiënte wijze
uitgaande van de inputstack nieuwe slices te kunnen berekenen. Zo moeten er n de vensters
‘Orthogonal Slices’, ‘Orthogonal Stack’ en ‘Axial Coronal Sagittal View’, nieuwe slices
berekend worden in de drie orthogonale richtingen. In het venster ‘Oblique View’ moet een
nieuw beeld in een willekeurige richting berekend worden. De gekozen aanpak laat zich
wellicht al raden: in plaats van voor elk van deze functies een afzonderlijk algoritme te
ontwikkelen, kan het bekomen van de slices in de drie orthogonale richtingen beschouwd
worden als een bijzonder geval van het berekenen van een nieuw beeld in een willekeurige
richting. Het bekomen van zo’n nieuw afbeelding gebeurt met behulp van de klasse Picture.
Het volstaat om aan de klasse Picture de juiste hoeken mee te geven om zo in plaats van een
willekeurig georiënteerd beeld, een scan in axiale, coronale of sagittale richting te verkrijgen.
Om uit te leggen hoe de klasse Picture precies werkt, moeten we eerst terugkeren naar de
klasse ImageModel, dit is de klasse die onder andere de breedte en hoogte van de stack, alsook
de array met pixels bijhoudt. Op het ogenblik dat een nieuwe stapel beelden door de gebruiker
wordt geopend, wordt ImageModel aangepast: er komt
hoogstwaarschijnlijk een nieuwe breedte en hoogte, de oriëntatie wordt
misschien veranderd, …, maar er gebeurt meer dan dat. De klasse
ImageModel bezit namelijk een 3D-array (int [][][] pixels) waarin de
pixels van de inputstack worden opgeslagen: elke slice van de
inputstack kan voorgesteld worden door een tweedimensionale array
van pixels, dit kan gemakkelijk afgeleid worden uit Figuur II-4 Voor een
stapel beelden, zoals te zien in Figuur II-5, is daarom een 3D-array
nodig.
Omwille van de eenvoud van werken wordt de oorspronkelijke stapel,
die een axiale, coronale of sagittale oriëntatie kan hebben, eerst
omgevormd tot een coronale stapel. Het is deze stapel – die nog altijd
bestaat uit identiek dezelfde pixels als de oorspronkelijke stapel, enkel
Figuur II-4 Éen slice is een 2D array
Figuur II-5 Een stapel is een 3D array
19
anders georganiseerd – die wordt opgeslagen in de 3D-array pixels van de klasse
ImageModel. Op die manier krijgen we als het ware een kubus van inputpixels.
Deze kubus verbinden we met een coördinatenstelsel 2B , zie Figuur II-6 Om uiteindelijk een
willekeurige doorsnede te kunnen maken, zullen we eerst nog twee andere coördinatenstelsels
moeten invoeren. We beginngen met 1B (Figuur II-7). Dit coördinatenstelsel kan beschouwd
worden als het ‘inertiaalstelsel’. In dit stelsel kan een vlak, evenwijdig aan het 11YX -vlak, met
lengte l met l =1,1 * Max (Breedte inputstack, Hoogte inputstack, Diepte inputstack)
bewegen van van z = 0 tot z = l
Ten opzichte van 1B plaatsen we een nieuw assenstel 3B (groen) met oorsprong 3o =
12/
2/
2/
Bl
l
l
.
We plaatsen in1B ook nog de kubus 2B (zwart) zodanig dat het middelpunt van de kubus
samenvalt met de oorsprong van 3B , dit wordt voorgesteld in Figuur II-8.
Op die manier zijn de hoekpunten van de kubus ten opzichte van 2B en 3B de volgende
met usbreedteKubw = en shoogteKubuh = en sdiepteKubuz =
[ ]32
2/
2/
2/
0
0
0
0
BBd
h
w
kubus
−−−
=
= [ ]32
2/
2/
2/
0
0
4
BBd
h
w
h
kubus
−−
=
=
[ ]32
2/
2/
2/
0
01
BBd
h
ww
kubus
−−−
=
= [ ]32
2/
2/
2/
05
BBd
h
w
d
w
kubus
−=
=
Figuur II-6 B2 Figuur II-7 B1 Figuur II-8 B1 + B2 + B3
20
[ ]32
2/
2/
2/
0
2
BBd
h
w
h
w
kubus
−=
= [ ]32
2/
2/
2/
6
BBd
h
w
d
h
w
kubus
=
=
[ ]32
2/
2/
2/
0
0
3
BBd
h
w
hkubus
−
−=
= [ ]32
2/
2/
2/0
7
BBd
h
w
d
hkubus
−=
=
Dit alles zullen we nodig hebben om uiteindelijk de oblique doorsnede te kunnen berekenen.
De oblique doorsnede wordt bekomen door de kubus te roteren rond de X - en de Y -as en
vervolgens de doorsnede te bepalen met het roze vlak, evenwijdig
met het 11YX -vlak, zoals ook te zien is op Figuur II-9.
Men kent de hoeken waarover geroteerd word rond de X - en de
Y -as: ofwel worden ze opgegeven, zoals voor orthogonale slices
het geval zal zijn, ofwel worden ze afgeleid uit de
muisbewegingen.
Hoe wordt nu in essentie het resulterende, oblique beeld
bekomen? We berekenen voor alle punten ),,( 111 zyxp van het vlak
het overeenkomstige punt ),,( 222 zyxp in de kubus. Dit kan door
middel van een coördinatentransformatie. De coördinaten van het punt p ten opzichte van 2B ,
zijnde ),,( 222 zyxp , geven ons de pixelwaarde van het punt p in het vlak, namelijk
pixels[z 2][y 2][x 2] Dit is de essentie. Hoe gaan we concreet te werk?
De transformatie van 1B naar 3B kan beschreven worden door een translatie van de oorsprong
van 1B ( 1o ) naar de oorsprong van 3B ( 3o ), gevolgd door een rotatie over de X -as, opnieuw
gevolgd door een rotatie over de Y -as. In wiskundige termen kunnen we zeggen dat de
coördinatentransformatie 31 BB → beschreven wordt door middel van een matrix yx RTRQ =
zodat [ ] [ ]31 BB pQp = en [ ] [ ]
13
1BB pQp −= met
=
1000
2/100
2/010
2/001
l
l
l
T en
−=
1000
0cossin0
0sincos0
0001
ϕϕϕϕ
xR en
−
=
1000
0cos0sin
0010
0sin0cos
ψψ
ψψ
yR
Figuur II-9 B3 geroteerd
21
Deze coördinatentransformatie laat ons toe om uitgaande van de coördinaten van een punt ten
opzichte van 1B , de coördinaten ten opzichte van 3B te berekenen. Door middel van een
translatie 23BBT van 23 oo → levert ons dat tenslotte de coördinaten ten opzichte van 2B op.
Met behulp van deze laatste coördinaten kunnen we de pixelwaarde ophalen uit de 3D-array
pixels .
Hoe worden nu alle pixels van het roze vlak, dit is de oblique doorsnede, bepaald? We kennen
ten opzichte van 1B de coördinaten van alle punten van het vlak: de 1x en 1y – coördinaten van
alle punten worden namelijk bekomen via het doorlopen van een geneste for-lus
for (int y = 0; y < l; y++){ …
for (int x = 0 ; x < l ; x++){ …
}
}
De 1z – coördinaat is bekend, want die wordt opgegeven. Op basis van deze coördinaten
( )111 ,, zyx berekenen we daarna eerst de coördinaten ten opzichte van 3B ( )333 ,, zyx en
daaruit via translatie de coördinaten ten opzichte van 2B ( )222 ,, zyx . Door middel van deze
laatste coördinaten kunnen we de juiste pixelwaarde uit de 3D-array pixels extraheren.
Hieronder wordt het algoritme in Java-code afgebeeld.
int [] p = new int [3];
p[2] = z; // het vlak gaat door z
for (int y = 0; y < l; y++){
for (int x = 0 ; x < l ; x++){
// de coördinaten ten opzichte van 1B
p[0] = x;
p[1] = y;
// bereken de coördinaten ten opzichte van 3B
q = 1−Q p
// voer een translatie uit naar de oorsprong va n 2B
r = 23BBT q
// lees de waarde af in de 3D-matrix pixels
int waarde = pixels[r[2]][r[1]][r[0]];
}
}
22
Nu rest nog de vraag welke hoeken er nodig zijn om op bovenstaande manier orthogonale
doorsneden te bekomen. Dit is niet eens zo moeilijk.
De eenvoudigste manier om zich dit aanschouwelijk voor te stellen is door in gedachten een
hoofd te verbinden met 2B . 2B is een coronale stapel, dus kijkt dit gezicht ons aan. Dit
impliceert dat een doorsnede, evenwijdig met het 11YX -vlak een coronale afbeelding zal
opleveren.
Roteren we het hoofd over °90 rond de Y -as, dan krijgen we het oor te zien. Maken we nu
doorsneden evenwijdig met het 11YX -vlak, dan krijgen we sagittale beelden.
Draai het hoofd in gedachten terug naar de coronale positie en kantel het gezicht over °90 rond
de X -as. Doorsneden evenwijdig met het 11YX -vlak geven ons nu axiale beelden.
Samengevat geldt het volgende, met de hoek ϕ = rotatie over X -as en ψ = rotatie over Y -as
Coronaal 0=→ ϕ en 0=ψ
Axiaal 2/πϕ −=→ en 0=ψ
Sagittaal 0=→ ϕ en 2/πψ −=
II. 4. Applet Het programmeren van een applet verschilt in niet zoveel van het programmeren van een
gewone applicatie, zo zou men kunnen denken. Vanuit het standpunt van de programmeur
gedraagt een applet zich in hoofdzaak zoals een venster van het type JFrame. Echter om
redenen van veiligheid worden een aantal restricties opgelegd aan wat een applet allemaal mag
doen. Hier zijn de restricties op de invoer in het bijzonder van belang. Deze restricties luiden
als volgt
• Applets kunnen geen bestanden lezen of schrijven op de computer waarop de applet
wordt uitgevoerd
Figuur II-10 Coronaal Figuur II-11 Axiaal Figuur II-12 Sagittaal
23
• Een applet kan enkel netwerkverbindingen aanmaken met de computer vanwaar het werd
opgeladen
Vooraleer van wal te steken met de behandeling van de concrete gevolgen van deze restricties,
eerst nog dit. Het lag in de bedoeling van Professor Achten dat de medische scans op twee
manieren konden aangeboden worden aan de studenten: enerzijds als enkelvoudige bestanden
waarbij zo’n bestand dan ofwel één afbeelding is of een stack, anderzijds als meervoudige
samenhorende bestanden verenigd in één map, met andere woorden een stapel afzonderlijke
beelden die fysiek geen stack zijn maar zich naar buiten toe wel als dusdanig moeten
manifesteren. Dit wil concreet zeggen dat de inhoud van de map met medische beelden op de
server, kan ingedeeld worden in drie groepen: de enkelvoudige bestanden, de mappen met
samenhorende bestanden (stack-mappen) en tenslotte gewone submappen. Er wordt bovendien
een regel opgelegd aan de stack-mappen: de naam moet beginnen met de vijf letters STACK.
De reden hiervoor zal blijken uit de verdere tekst.
Laten we terugkeren naar ons betoog. Wat betekenen de bovenstaande beperkingen concreet
voor het applet? Als de studenten Geneeskunde beelden willen bekijken via het applet, dan
moeten deze beelden ergens beschikbaar zijn. Hiervoor bestaan er twee mogelijkheden: ofwel
staan ze op de PC van de student – die de beelden vooraf heeft gedownload – ofwel staan ze op
een server. De eerste van de twee bovenstaande restricties maakt onmiddellijk duidelijk dat het
bekijken van vooraf gedownloade beelden via een applet niet vanzelfsprekend zal zijn. En
inderdaad, deze manier van werken impliceert het gebruik van signed applets. Voor deze weg
werd niet gekozen. Deze methode kan immers bezwaarlijk echt gebruiksvriendelijk genoemd
worden: vooraleer ze de beelden kunnen bekijken moeten de studenten de afbeeldingen eerst
downloaden. Bovendien zijn de studenten in dat geval ook verplicht om zelf van tijd tot tijd te
controleren of er intussen misschien nieuwe beelden beschikbaar zijn.
Er werd dus voor de tweede manier gekozen: studenten halen de beelden binnen terwijl ze aan
het werk zijn met het applet. De tweede restrictie laat dit toe onder de voorwaarde dat de
beelden op dezelfde server staan als het applet, iets wat normaal gezien geen groot probleem
kan zijn. De implementatie van deze tweede weg bleek echter ook allesbehalve triviaal.
Programmatorisch was het weliswaar mogelijk om beelden van de server te halen en deze aan
de studenten te laten zien, maar daarmee was nog niet duidelijk hoe de studenten de server
konden vertellen wélke beelden ze wilden zien. Er moest met andere woorden een systeem op
poten gezet worden waarlangs de gebruiker van het applet de server kan meedelen welke
bestanden hij wil bekijken. Traditioneel verloopt zoiets via een bestandskiezer. Echter de
klasse JFileChooser uitbreiden was in deze niet mogelijk, want niet de inhoud van de lokale PC
24
maar de inhoud van de map met medisch beeldmateriaal op de server moest getoond worden.
Toch wilden we voor deze taak niet te ver afwijken van de gebruikelijke bestandskiezer.
De volgende oplossing werd bedacht: maak zelf een venster dat de belangrijkste
karakteristieken heeft van een gewone bestandskiezer en voed deze bestandskiezer met een
bestand van op de server dat de structuur van de map met medische beelden – welke mappen
hebben welke inhoud? – bevat. Mits de zelf geprogrammeerde bestandskiezer van de juiste
code te voorzien, moet het mogelijk zijn om op basis van dit document de bestandskiezer op
elk ogenblik de juiste mappen en bestanden te laten weergeven – in de typische bestandskiezer
structuur. Voor de duidelijkheid wordt in Figuur II-13 zo’n bestand afgebeeld, het draagt de
naam dirsAndFiles.txt. Er is niet veel fantasie nodig om in te zien dat een programma op basis
van een dergelijk document kan weten hoeveel bestanden er in een map aanwezig zijn, hoeveel
stack-mappen er zijn en hoeveel submappen deze
map bevat. Kort samengevat gaat het algoritme als
volgt
1. Lees de eerste regel van het bestand
dirsAndFiles.txt
2. Zolang de invoer niet gelijk is aan
LISTINGOFPRESENTSTACKS, voeg de
inhoud van de regel toe aan een array
van bestanden
3. Wanneer de inhoud van de regel gelijk
is aan LISTINGOFPRESENTSTACKS, ga
naar de volgende regel
4. Zolang de inhoud niet gelijk is LISTINGOFPRESENTDIR ECTORIES, voeg de
inhoud van de regel toe aan een array van stack-map pen
5. Wanneer de inhoud van de regel gelijk is aan
LISTINGOFPRESENTDIRECTORIES, ga naar de volgende re gel
6. Zolang de invoer niet gelijk is aan een witregel, v oeg de inhoud van de
regel toe aan een array van mappen
Figuur II-13: Voorbeeld van dirsAndFiles.txt
25
Dit algoritme resulteert in drie arrays. Één array bevat
de namen van de bestanden uit de doorzochte map,
één de namen van de stack-mappen en één de namen
van de reguliere submappen.
De implementatie had wel wat voeten in de aarde,
maar het was mogelijk om op basis van deze arrays
het centrale gedeelte van de zelfontworpen
bestandskiezer het vertrouwde uitzicht te geven, zoals
te zien is op Figuur II-14.
Echter daarmee was de taak nog lang niet volbracht, de volgende vraag liet nauwelijks op zich
wachten. Wie of wat zou dat bestand dirsAndFiles.txt, dat de inhoud van een map
inventariseert, op de server plaatsen? De eerste, meest voor de hand liggende oplossing zou
zijn om diegene die de beelden op de server plaatst, handmatig de lijst te laten aanpassen. Het
hoeft echter weinig betoog dat deze oplossing, niet volledig tot tevredenheid stemt. Deze taak
kan beter geautomatiseerd worden zodat vergissingen en vergetelheden tot een minimum
herleid worden. Na het zwalpen langs nog een paar omwegen, kwam ik uiteindelijk bij de
scripttaal PHP terecht om deze opdracht zonder externe hulp te volbrengen. De grootste reserve
tegenover het gebruik van PHP is, dat de server PHP-enabled moet zijn. Echter een kleine
speurtocht op het Internet, leert dat bijna alle gratis webspace PHP ondersteunt, waaruit we
mogen concluderen dat PHP dezer dagen onder servers gemeen goed is. Bovendien is PHP ook
beschikbaar op eduserv en dat in tegenstelling tot bijvoorbeeld ASP.
Figuur II-15 Deel van een webpagina die een overzicht geeft van de 10 meest recente hosts
Figuur II-14: Bestandskiezer horend bij dirsAndFiles.txt uit Figuur II-13
26
De webpagina waarop het applet staat, kan grosso modo in twee delen worden verdeeld
<PHP code>
<Applet>
Dit wil zeggen dat iedere keer de webpagina bekeken wordt, de PHP-code uitgevoerd wordt.
De volledige HTML-code kan u vinden in Appendix A.
Hoe slaagt PHP erin om zich op een degelijke manier van zijn taak te kwijten? Laten we
beginnen met de map met radiologische beelden op de server de naam RadiologyImages te
geven. De namen van eventuele submappen van deze map zijn volstrekt onbelangrijk, maar de
naam van de bovenste map wordt zowel in de PHP code als in de code van de bestandskiezer
gebruikt, deze naam ligt dus vast. PHP gebruikt deze naam om te
weten waar hij zijn werk met aanvatten: PHP begint met het
doorzoeken van deze bovenste map en houdt intussen drie arrays
bij: de eerste array bevat bestandsnamen, de tweede array bevat
de namen van mappen die beginnen met de vijf letters STACK,
de stack-mappen dus en de derde array tenslotte is bestemd voor de namen van gewone
mappen. Op het einde van zijn tocht doorheen de map, schrijft PHP de gevonden resultaten
weg naar een bestand met de naam dirsAndFiles.txt. Ook deze naam ligt op voorhand vast. Dit
wegschrijven gebeurt op een geëikte manier: eerst komen de gewone bestandsnamen onder
elkaar, gevolgd door het letterlijke woord LISTINGOFPRESENTSTACKS. Daaronder worden
de stack-mappen opgesomd, op hun beurt gevolgd door het woord
LISTINGOFPRESENTDIRECTORIES, waaronder de lijst met de namen van de gewone
mappen volgt. Er werd bewust voor de monsterwoorden LISTINGOFPRESENTSTACKS en
LISTINGOFPRESENTDIRECTORIES als markers gekozen, om de kans dat een bestand of
map toevallig deze naam zou dragen – en daarbij het uitgedokterde systeem zou verklooien –
tot bijna nihil te herleiden.
Op dit ogenblik is PHP klaar met het maken van het bestand dirsAndFiles.txt van de bovenste
map, maar waar moet het nieuwbakken bestand nu opgeslagen worden? Niet in de map
RadiologyImages zelf, de reden hiervoor komt straks aan bod. In plaats daarvan bouwt PHP op
de server zelf een ‘schaduwdirectory’ op met mappen die exact dezelfde naam zullen dragen
als de mappen in RadiologyImages met als enige verschil dat de hoofdmap VirtualImages heet,
en niet RadiologyImages: twee mappen met dezelfde naam in één en dezelfde map zijn nu
eenmaal niet toegelaten.
Als de nieuwe map is aangemaakt en het bestand dirsAndFiles.txt erin is weggeschreven,
begint PHP de eerste submap van RadiologyImages uit te vlooien, maakt een nieuw bestand
Figuur II-16 Voorbeelddirectory
27
dirsAndFiles.txt en schrijft dit weg in een nieuw aangemaakte map in de map VirtualImages. In
dit voorbeeld zou het gaan om een map met de naam CTScans. Indien hiermee klaar, wordt de
code opnieuw recursief opgeroepen voor de submappen van CTScans, totdat uiteindelijk alle
submappen van de map RadiologyImages zijn doorploegd.
Waarom werd er nu voor gekozen PHP een schaduwdirectory te laten opbouwen om daarin de
bestanden dirsAndFiles.txt te stockeren? Eerst en vooral omdat het opslaan van de bestanden
dirsAndFiles.txt bij de beelden zelf niet netjes zou zijn, naar de geest horen deze bestanden
daar niet thuis. Er is echter nog een tweede, belangrijkere reden: Iemand opent de webpagina,
dit wil zeggen achter de schermen worden de bestanden dirsAndFiles.txt opgebouwd en
weggeschreven naar de schaduwdirectory. Op het moment dat een gebruiker van het applet
klikt op de knop ‘Open New Stack’ van Figuur I-16, ligt in de code van de eigen gemaakte
bestandskiezer beschreven dat het bestand dirsAndFiles.txt van op de server uit de map
VirtualImages moet ingelezen worden en dat de inhoud van dit bestand moet getoond worden
in de bestandskiezer. Wat gebeurt er nu op het ogenblik dat iemand dubbelklikt op een map in
de bestandskiezer? Dan wordt het opschrift van de knop, want het centrale gedeelte van de
bestandskiezer is geïmplementeerd met behulp van JButtons, geconcateneerd aan de reeds
bestaande string VirtualImages en krijgen we bijvoorbeeld VirtualImages/DICOM, vervolgens
wordt er een verzoek gestuurd naar de server waarin gevraagd wordt naar het bestand
dirsAndFiles.txt uit de map VirtualImages/DICOM. Stel dat onze geneeskunde student
intussen is afgedaald naar de map VirtualImages/DICOM /Ledematen/Armen en eindelijk
gevonden heeft wat hij zoekt, namelijk het bestand GebrokenArm.jpg. In de bestandskiezer
dubbelklikt hij op GebrokenArm.jpg. De bestandskiezer weet – dat wordt intern namelijk
bijgehouden – dat het om een bestand gaat en niet om een map. Om het beeld binnen te halen
volstaat het om in het opgebouwde pad simpelweg VirtualImages vooraan te vervangen door
RadiologyImages en een verzoek te sturen naar de server om het bestand
Figuur II-17 Voorbeelddirectory met schaduwdirectory
28
RadiologyImages/DICOM/Ledematen/Armen/GebrokenArm.jpg op te halen. Precies daarom is
het zo nuttig dat PHP die schaduwdirectory maakt.
Er resten nog drie subtiliteiten die om wat opheldering vragen.
De eerste van de drie is de vraag wat er gebeurt in het volgende geval. Een gebruiker heeft de
bestandskiezer geopend en er is bijvoorbeeld keuze uit drie bestanden: Hoofd, Handen en
Voeten. Vooraleer verder te werken besluit de gebruiker echter een kop koffie te gaan halen en
hij blijft daarbij nog even hangen in de keuken. Aan de andere kant van de applicatie, aan de
serverzijde, heeft de professor intussen besloten dat Handen niet zo’n goed voorbeeld is, en
heeft het bestand verwijderd van de server. Na een tijd gaat de koffiedrinkende student weer
achter z’n PC zitten en beslist om uitgerekend het bestand Handen eens van naderbij te
bekijken. Dit is echter intussen verdwenen van de server. Om dit probleem op te lossen krijgt
de student een dialoogvenster te zien waarin hem wordt verteld dat het bestand niet meer
aanwezig is en waarin hem gevraagd wordt om de webpagina opnieuw te openen. Vooral dat
laatste is belangrijk want op dat ogenblik wordt de PHP code opnieuw uitgevoerd en worden
de oude bestanden dirsAndFiles.txt vervangen door nieuwe – bijgewerkte – bestanden.
Ook het omgekeerde probleem kan zich voordoen. Iemand start de applicatie – de PHP code
wordt uitgevoerd en de schaduwdirectory wordt opgebouwd – en werkt intussen noest verder
terwijl er in tussentijd extra beelden worden toegevoegd aan de mappen op de server. Zolang
de webpagina niet opnieuw geopend wordt, zullen de nieuwe beelden in de bestandskiezer niet
getoond worden aan deze gebruiker want de bestanden dirsAndFiles.txt worden enkel
bijgewerkt wanneer iemand het applet opent. Een eenvoudige oplossing voor dit probleem is
dan de vraag om, nadat er beelden zijn toegevoegd, de webpagina gewoonweg eens te
bezoeken. Het is bovendien weinig waarschijnlijk dat dit een frequent opduikend probleem zou
worden!
Het derde probleem uit deze trilogie is van toepassing wanneer twee studenten quasi simultaan
de webpagina zouden bezoeken. In dat geval zou het wegschrijven van de dirsAndFiles.txt
bestanden naar de server problemen kunnen opleveren. Daarom werd geprobeerd het schrijven
van de bestanden op de server te beveiligen met een semafoor zodat slechts één gebruiker
tegelijk kan schrijven naar de server, maar verschillende gebruikers probleemloos samen
dirsAndFiles.txt kunnen lezen van op de server. Helaas laat eduserv ons hier in de steek, want
blijkbaar worden semafoorfuncties niet ondersteund.
Daarmee zat de implementatie er echter nog niet op.
Toen de volledige en goed functionerende bestandskiezer er eindelijk was, stak een nieuw, en
nóg groter probleem de kop op. Bovendien was er deze keer weinig kruid tegen gewassen. Het
29
probleem waarvan hier sprake is de grootte van DICOM bestanden. Bestanden van meerdere
megabytes zijn geen uitzondering. Bestanden van die omvang binnen halen vraagt tot op de
dag van vandaag nog altijd, naar onze maatstaven, vrij veel tijd, variërend van twintig, dertig
seconden tot één of meerdere minuten. Dit is natuurlijk niet toelaatbaar. Om het probleem
gedeeltelijk het hoofd te bieden, werd nog een extra klasse geprogrammeerd die stapels
beelden zoveel mogelijk tracht te verkleinen. In het venster horend bij deze klasse wordt eerst
gevraagd om de te verkleinen beelden te selecteren. Vervolgens worden alle beelden
automatisch omgezet naar Jpeg bestanden. Daarna worden deze Jpeg’s verenigd in een Tiff-
stack en tenslotte wordt deze stack nogmaals gecomprimeerd. Op deze manier kan een bestand
van ongeveer drie Megabyte gereduceerd worden tot circa één Megabyte. De keerzijde van de
medaille ligt voor de hand: deze constructie komt de kwaliteit van het beeldmateriaal niet ten
goede.
30
III. Kritische studie III. 1. Inleiding Zoals reeds verteld in de inleiding, was deze scriptie tweeledig. Na het programmeergedeelte
volgde nog een onderzoeksgedeelte: hierin werd ImageJ aan een grondige studie onderworpen.
Hoewel het woord ImageJ her en der in deze tekst opduikt, is er in de gemaakte applicatie op
het eerste zicht geen spoor van ImageJ te ontdekken. Dit klopt! Er wordt enkel achter de
schermen gebruik gemaakt van ImageJ. Jammer genoeg, want de oorspronkelijke bedoeling
was om het applet als onderdeel van ImageJ te laten functioneren, zodat de studenten niet
alleen de beschikking zouden hebben over het voor hen geprogrammeerde applet, maar ook
over de functionaliteit zoals die al aanwezig is in ImageJ. Het systeem leek zich daar – van de
buitenkant althans – perfect toe te lenen: gebruik van plugin’s en macro’s wordt ondersteund,
er is zelfs een handleiding beschikbaar om het schrijven van deze plugin’s tot een goed einde te
brengen. Hoewel vol goede moed erin gevlogen, staken de eerste problemen al heel snel de
kop, namelijk toen ik zocht naar een manier om twee beelden naast elkaar in één venster te
plaatsen. Op het eerste zicht toch niet zo’n moeilijke opdracht. Omdat dit na veel geknoei maar
niet wou lukken, werd de broncode, die beschikbaar is via het Internet, geraadpleegd. Wat ik
daar vond, stond in schril contrast met de kip met gouden eieren die werd beloofd door de
website: een bijna onontwarbaar kluwen van in elkaar grijpende klassen, waarbij de uitbreiding
van één klasse een dijkbreuk van onbegrijpelijke fouten teweegbracht. Uit dit alles groeide het
verlangen om op gestructureerde manier ImageJ onder de loep te nemen. ImageJ werd daarom
bestudeerd op 3 vlakken. In een eerste kort gedeelte wordt de omkadering van ImageJ
onderzocht: daarin wordt besproken welke algemeenheden van ImageJ tegenvallen en wat er
mee valt. In het volgende deel wordt de lay-out van ImageJ onder de spots geplaatst. In dit deel
wordt een antwoord gezocht op de vraag of ImageJ qua gebruiksvriendelijkheid goed scoort en
waarom dat wel of dat niet zo is. In het derde en laatste deel tenslotte wordt de interne keuken
van ImageJ bekeken: gebeurde het programmeren van dit project rechttoe rechtaan of werden
de regels zoals die voorgeschreven worden voor goed object georiënteerd programmeren
conscencieus gevolgd?
III. 2. De omkadering
31
Vooraleer aan het echte werk te beginnen, werd dus eerst stilgestaan bij de vraag hoe de
globale omkadering van ImageJ wordt ervaren en, het moet gezegd, hier gooit ImageJ hoge
ogen.
Een eerste feit dat zonder meer vóór ImageJ pleit, is dat het ganse systeem volledig gratis ter
beschikking wordt gesteld. Het werk gebeurt in opdracht van de Amerikaanse overheid, dus er
is ook geen enkel spoor van vervelende sponsors of iets dergelijks te ontdekken. Tweede punt
dat voor ImageJ spreekt, zijn de ingebouwde mogelijkheden van het pakket, die zijn niet niks:
er kunnen op eenvoudige wijze beelden van een heleboel uiteenlopende formaten ingelezen
worden. Derde pluspunt – dit is één van de belangrijkste redenen waarom in dit eindwerk voor
ImageJ gekozen werd – ImageJ kan probleemloos gebruikt worden als applet, dit vereist geen
moeilijke of ingewikkelde constructies, het volstaat om de bibliotheek ij.jar mee te geven als
argument van de <archive> - tag in de HTML – code.
En de lofregen houdt maar niet op: ontwikkelaars die gebruik maken van ImageJ kunnen
rekenen op een zeer uitgebreide ondersteuning, te meer omdat het geheel gratis is, verdient dit
een bijzondere vermelding. Deze ondersteuning begint vanzelfsprekend met de website. In
Figuur III-1 is de startpagina van de webpagina te zien. Misschien valt de bijzonder sobere lay-
out op. Deze wordt doorheen de ganse website aangehouden (en is ook terug te vinden in het
programma zelf). De website is weliswaar
sober, maar werkelijk onmisbaar. Om te
beginnen is op de website de volledige
documentatie beschikbaar van alle
geïmplementeerde klassen, in typische Java –
stijl, wat deze documentatie bijzonder
toegankelijk maakt. Alsof dat nog niet genoeg
is, kan ook de volledige broncode online
geraadpleegd worden. Deze broncode is
bovendien goed gedocumenteerd. De
beschikbare code is waarschijnlijk wel wat
verouderd want doorheen de implementatie
van het applet viel het een zeldzame keer op
dat de code op het net onmogelijk de juiste
code kon zijn. Nog altijd onder de categorie
positief is de uitgebreide handleiding die
uitlegt hoe het programmeren van plugin’s in ImageJ best kan gebeuren. Zonder deze
Figuur III-1 Indexpagina website ImageJ
32
handleiding zouden de eerste stappen in het schrijven van plugin’s voor ImageJ zonder twijfel
veel moeilijker verlopen zijn.
Tot slot is de webpagina ook de plaats waar het werk van collega’s kan gedownload worden.
De plugin’s die door anderen geschreven worden, worden hier verzameld en kunnen opnieuw
volledig gratis door derden gebruikt worden. Van deze plugin’s is ook de broncode, op de
spreekwoordelijke uitzondering na, beschikbaar via de webpagina.
Er bestaat ook een mailing lijst waaraan druk geparticipeerd wordt, vaak door mensen met
ronkende titels voor hun naam. Vijf tot tien berichten per dag, vormen geen uitzondering. Ook
Wayne Rasband, de oorspronkelijke ontwerper van ImageJ, neemt actief deel aan de
discussies. Precies omwille van zijn bevoorrechtte positie kan hij soms antwoorden geven op
bijzonder specifieke vragen.
De mogelijkheid tot het schrijven van de plugin’s om tegemoet te komen aan specifieke
beeldverwerkingsproblemen, verdient ook een pluim. Het zijn precies deze plugin’s die ervoor
zorgen dat het systeem volop in ontwikkeling blijft en iedereen de kans bieden om ImageJ
zoveel mogelijk naar z’n eigen hand te zetten.
ImageJ heeft ook een ingebouwde editor en compiler onder de motorkap zitten, maar deze
eigenschap biedt nauwelijks toegevoegde
waarde. In Figuur III-2 is de editor afgebeeld.
Laten we eerlijk zijn, zelfs Kladblok maakt
een minder troosteloze indruk. Daarnaast is er
ook vanalles aan de hand met de editor. Zo
werken de toetsencombinatie Ctrl + C en Ctrl
+ V niet naar behoren: als je iets op die
manier kopieert en plakt, wordt het niet één
maar twee keer geplakt. Daarnaast gaat het
compileren bijzonder traag, soms is het ook
nodig om ImageJ volledig af te sluiten en
daarna weer op te starten vooraleer je het resultaat kan zien van een gecompileerde klasse. De
gebreken zijn schier eindeloos, je bent ondermeer verplicht om alle bestanden in één map te
stoppen, want de compiler weet geen gecompileerde klassen in submappen te vinden. Voorts
laat de formulering van fouten dikwijls te wensen over. Gelukkig kan je door het Classpath aan
te passen, met je vertrouwde Java-editor werken, want de ingebouwde editor annex compiler is
zeker geen optie.
Figuur III-2 De ingebouwde editor in ImageJ
33
III. 3. Studie van de lay-out III. 3. 1. Inleiding Het tweede deel van deze kritische studie van ImageJ betreft een evaluatie van de interface. De
vraag die dan spontaan rijst, is: “Hoe begin je daaraan?”. Gelukkig werd een helpende hand
gevonden in Usability Engineering.
In de hiernavolgende tekst wordt begonnen met nader toe te lichten wat Usability Engineering
exact inhoudt en hoe de studie precies werd aangepakt. Daarna worden de details van de
eigenlijke tests uit de doeken gedaan. Vervolgens worden de testresultaten besproken.
III. 3. 2. Wat is Usability Engineering?
Tegenwoordig is er geen ontkomen aan, iedereen wordt dagelijks geconfronteerd met allerlei
technische apparaten. Met de komst van deze apparaten en computers in het bijzonder is een
heel nieuw concept ontstaan: de gebruikersinterface. Deze interface biedt de gebruiker de
mogelijkheid om het apparaat te besturen. Naarmate apparaten steeds meer functies krijgen en
mensen met steeds minder technische kennis deze apparaten willen gebruiken, wordt het
moeilijker een goede, efficiënte en gebruiksvriendelijke interface te ontwikkelen. Vanuit deze
problematiek is een studie ontstaan om de efficiëntie van de interface en problemen in de
interface te evalueren: Usability Engineering. Usabilitity Engineering formuleert verschillende
methodes om op systematische wijze de gebruiksvriendelijkheid van digitale systemen te
onderzoeken. Voorbeelden van dergelijke methodes zijn Usability Inspection methodes en
Usability Testing methodes. Deze twee methodes worden in de twee volgende paragrafen wat
nader toegelicht.
Figuur III-3 Hoe kleine wijzigingen in de interface, de gebruiksvriendelijkheid aanzienlijk kunnen verhogen
34
III. 3. 3. Wat zijn Usability Inspection methodes?
Usability Inspection is de algemene verzamelnaam voor methodes waarbij aan mensen
gevraagd wordt een gebruikersinterface te bekijken, met als bedoeling gebruikersproblemen
die in het ontwerp geslopen zijn, op te sporen. Het ontwerp van de interface op zichzelf wordt
door de gebruikers beoordeeld zonder dat ze de applicatie als dusdanig als geheel uitproberen.
Bij Usability Inspection gaat het erom dat testgebruikers een aantal concrete – opgedragen –
acties ondernemen. Bij elke actie wordt dan nagegeaan of de interface op elk moment
voldoende informatie biedt om de opgelegde actie tot een goede einde te brengen. Hierin ligt
het belangrijke verschil met Usability Testing waarbij proefpersonen een “grote” taak krijgen
voorgeschoteld en er gecontroleerd wordt of ze eenvoudig zélf de juiste acties weten te vinden
om de taak te voltooien.
Het nut van Usability Inspection kan met een heel eenvoudig voorbeeld worden aangetoond.
Stel dat bedrijf X een nieuw kopieertoestel op de markt wil introduceren en nagelaten heeft te
vermelden op het toestel of het papier met de bedrukte zijde naar boven of naar onder op de
glasplaat moet gelegd worden. Op het ogenblik dat een proefpersoon gevraagd wordt de actie –
leg het papier op de glazen plaat – uit te voeren, weet hij niet hoe het papier erop te leggen en
komt de vergetelheid onmiddellijk aan het licht. Dit is precies waar het bij
Usability Inspection om draait.
Usability Inspection bestaat niet uit één methode, maar is een verzameling van
methodes. De bekendste en meest gebruikte van deze methodes is Heuristic
Evaluation. Deze methode werd in 1990 bedacht door Jakob Nielsen en Rolf
Molich. In 1994 werd de methode door Nielsen verder verfijnd. Het is een snelle, goedkope en
eenvoudige manier om een gebruikersinterface te evalueren. Bij Heuristic Evaluation gaan een
klein aantal mensen na of de interface in overeenstemming is met een aantal algemeen
aanvaarde principes over gebruiksvriendelijkheid, de heuristieken.
Een andere methode is Cognitive Walktrough. Cognitive Walkthrough is een evaluatiemethode
ontwikkeld door Clayton Lewis, Peter Polson, Cathleen Wharton, en John Rieman. De
methode ontdekt tekortkomingen, ‘fouten’, in een interface zonder hierbij eindgebruikers te
betrekken. Ervaren ontwerpers (niet de ontwerpers zelf!) nemen bepaalde taken van het
systeem door, zich de gedachten voorstellend van mensen die het systeem voor de eerste keer
gebruiken. Het doel van een Cognitive Walkthrough is het proberen begrijpen van de invloeden
die het ontwerp van de interface heeft op de gebruiker, zodat deze bepaalde acties tot een goed
Figuur III-4 Jakob Nielsen
35
einde zal brengen of niet. De ontwerpers van de interface zelf zijn te nauw betrokken bij de
interface om de Cognitive Walkthrough correct uit te voeren.
Nog een andere methode is Pluralistic Walkthrough. Hierin doorlopen eindgebruikers en
ontwikkelaars samen verschillende acties en geven de eindgebruikers onmiddellijk hun mening
over de interface aan de ontwerpers, waarna ze gezamenlijk het ontwerp bediscussiëren.
III. 3. 4. Wat zijn Usability Testing methodes?
Usability Testing methodes willen voornamelijk nagaan hoe vlot mensen met een website, een
interface, een toestel, … overweg kunnen: ze meten met andere woorden vooral de
gebruiksvriendelijkheid van een object. Het doel van deze testen is dus om te controleren of de
eindgebruikers bijvoorbeeld de meegeleverde instructies makkelijk zullen verstaan of
aangeboden feedback juist weten te interpreteren. Dergelijke testen zijn belangrijk omdat
ontwerpers nogal eens de neiging hebben te kiezen voor een zo “cool” mogelijk ontwerp in
plaats van voor de meer functionele versie. Er bestaan verschillende manieren om dergelijke
testen af te nemen. De eenvoudigste manier is zonder meer een test met pen en papier waarbij
testgebruikers aspecten aanduiden op papier. Een andere test bestaat erin om proefpersonen
luidop te laten nadenken terwijl ze opgelegde taken afwerken. Bij de meest geavanceerde tests
worden de beide ogen van de testpersoon door een camera gevolgd, op die manier kan men
nagaan welke de stimuli precies zijn die de gebruiker het meest beïnvloeden.
Hoeveel gebruikers aan zo’n testen dienen onderworpen te worden om tot een aanvaardbaar
resultaat te komen, ligt niet vast. In het begin ging men ervan uit dat 5 proefpersonen
voldoende was. Echter sinds begin de jaren 2000 zijn er empirische bewijzen dat 5 toch wat
aan de lage kant is, gewoon omwille van de enorme verscheidenheid die er bestaat tussen
mensen.
III. 3. 5. Usability Inspection en ImageJ
Het onderwerpen van ImageJ aan Usability Inspection werd beperkt tot de methode Heuristic
Evaluation. Bij de evaluatie werd er gebruik gemaakt van de volgende tien heuristieken [1]
1. Minimalistisch ontwerp
“Less is more”. Dialoogvensters bevatten best geen irrelevante informatie omdat het de
aandacht wegneemt van wat wel belangrijk is. Het onderstaande voorbeeld is het
dialoogvenster Opties van het programma MultiEdit 8.0. Dit is duidelijk een voorbeeld van hoe
36
het niet moet: het gebruik van de labels mét icoontjes en de harde kleuren creëren een visueel
monster en maken het moeilijk om de weg te vinden doorheen de verschillende mogelijkheden.
2. Spreek de taal van de gebruiker
Een ontwerp moet proberen zoveel mogelijk aansluiting te vinden bij de wereld waarmee z’n
gebruikers vertrouwd zijn, door middel van bijvoorbeeld een goede woordkeuze en het gebruik
van veelzeggende metaforen. De prullenbak is een bekend voorbeeld van zo’n
betekenisvolle metafoor.
Het ontwerp moet zoveel mogelijk georiënteerd zijn op de echte wereld en er
moet getracht worden om informatie op een natuurlijke en logische
manier voor te stellen.
De twee onderstaande dialoogvensters zijn afkomstig uit Easy CD
Creator. Links staat de boodschap afgebeeld die verschijnt als er iets is fout gegaan, rechts het
dialoogvenster om aan te geven dat het branden succesvol was. Een misplaatste subtiliteit in
het rechtse venstertje is verantwoordelijk voor een lichte verwarring.
3. Herkennen in plaats van herinneren
Er bestaat een bekende studie die zegt dat mensen slechts zeven dingen tegelijk kunnen
onthouden via het korte termijn geheugen. Het is daarom belangrijk voor GUI’s dat de
Figuur III-5 Een deel van het venster Opties in MultiEdit 8.0
Figuur III-6 Het pictogram Prullenbak
Figuur III-7 CD branden was niet succesvol Figuur III-8 CD branden was succesvol
37
verschillende opties of instructies goed zichtbaar of gemakkelijk te achterhalen zijn. In Figuur
III-9 wordt een bijna hallucinant voorbeeld van het tegendeel getoond. Het voorbeeld is
afkomstig van het dialoogvenster Opties uit CSE HTML Validator v3.05, een programma dat
gebruikt wordt om HTML – documenten te onderzoeken op syntactische fouten. De ‘flags’
worden gebruikt om bepaalde programma opties in te stellen, zo betekent het aanvinken van
flag 1 dat er moet gecontroleerd worden op HTML – tags eigen aan Internet Explorer en flag 2
dat er moet gecontroleerd worden op tags eigen aan Netscape Navigator. De gebruiker kan
deze informatie vinden in … de helpbestanden. Slechts doorwinterde gebruikers zullen zich
raad weten met dit venster.
4. Streef naar consistentie
Consistentie is één van de sleutelwoorden in een gebruiksvriendelijke lay-out. Zorg voor
consistentie in het gebruik van kleuren en lettertypes en in het afbeelden van menu’s en
dialoogvensters. Volg de conventies van het gebruikte besturingssysteem. In gelijklopende
situaties moeten gelijkaardige acties van de gebruiker verwacht worden. In Figuur III-10 is een
button met een onnatuurlijke functionaliteit te zien. In Figuur III-11 hebben de ontwerpers
geprobeerd om structuur aan te brengen in het ontwerp door Subscriber en Contact een randje
te geven, maar het mag geen verbazing wekken dat waarschijnlijk menigeen vruchteloos op
deze labels heeft geklikt.
5. Waardevolle feedback
Een programma moet de gebruiker constant op de
hoogte houden van wat er gebeurt door gebruik te maken van informatieve feedback. Als de
Figuur III-9 Een deel van het dialoogvenster Opties uit CSE HTML Validator v3.05
Figuur III-10 Een hybride Button
Figuur III-11 Labels die eruit zien als Buttons
38
gebruiker een actie heeft ondernomen, moet hij binnen redelijke tijd hetzij een resultaat, hetzij
een foutmelding, krijgen. Acties zouden nooit zonder gevolg mogen blijven. Het hierbij
horende voorbeeld van hoe dit fout kan lopen, is afkomstig van de installatie van Drawing
Board LT, een shareware CAD programma, waarbij er verschillende honderden bestanden
gekopieerd moeten worden naar de harde schijf. Als u het voorbeeld goed bekijkt, ziet u dat de
balk niet de vooruitgang van de volledige installatie aangeeft, maar slechts de vooruitgang van
het kopiëren van één enkel bestand. Het nut dit te weten is eerder nihil. Bovendien heeft dit
ontwerp tot gevolg dat de gebruiker gedurende de installatie absoluut in het ongewisse blijft
over hoelang de installatie nog zal duren.
6. Eenvoudige manieren om acties ongedaan te maken
Alle gebruikers, zelfs ervaren gebruikers, kiezen dikwijls per ongeluk voor een verkeerde
actie, bijvoorbeeld tekst in vet zetten terwijl het onderlijnd moest worden. Op zo’n ogenblik
moet het mogelijk zijn voor de gebruiker om gemakkelijk terug te keren op z’n stappen en de
vergissing ongedaan te maken, zonder daarvoor heksentoeren te moeten uithalen
7. Shortcuts
Laat meer ervaren gebruikers toe om mettertijd sneller te werken in het systeem bijvoorbeeld
door het voorzien van sneltoetsen. Het is ook bijzonder interessant om gebruikers te
mogelijkheid te bieden om vaak uitgevoerde acties te automatiseren met behulp van macro’s
of hen toe te laten om volledig nieuwe acties te definiëren.
Figuur III-12 De voortgang in de installatie van Drawing Board LT
39
8. Betekenisvolle foutboodschappen
Een goede foutboodschap is eerst en vooral geschreven in begrijpelijke taal, dus taal die ook
door niet expert gebruikers eenvoudig wordt begrepen. Daarnaast omschrijft de betere
foutboodschap niet alleen klaar en duidelijk het probleem, de foutmelding biedt liefst ook een
suggestie om tot een oplossing te komen of om de fout weer ongedaan te maken.
Vergelijk bijvoorbeeld onderstaande twee foutboodschappen.
9. Foutpreventie
Nog beter dan het geven van waardevolle foutboodschappen, is het programma zo te
ontwerpen dat de gebruiker geen fouten kan maken. Vaak is het beter om de gebruiker iets te
laten selecteren in plaats van het zelf te laten invullen. Ook kunnen lange invulformulieren
beter ingedeeld worden in verscheidene kortere deelformulieren zodat bij een fout er niet te
veel werk moet opnieuw worden begonnen, daarbij moet de gebruiker wel geïnformeerd
worden dat hij slechts aan een deel werkt en dat er nog onderdelen zullen volgen. In Figuur III-
15 is er in dit opzicht nog veel ruimte voor verbetering, zo was het beter geweest om de leeftijd
via een keuzelijst te laten ingeven. Daarnaast is het feit dat zowel Female als Male kunnen
geselecteerd worden absoluut ontoelaatbaar. Té is natuurlijk ook niet goed, zoals in Figuur III-
16. Stel u voor dat u op een sociaal secretariaat werkt en een honderdtal dergelijke nummers
moet ingeven. Er was wellicht een betere manier te bedenken om zowel aan foutpreventie te
doen als de gebruiksvriendelijkheid te bewaren.
Figuur III-13 Een betekenisvolle foutboodschap met voorstel tot actie
Figuur III-14 Een betekenisvolle foutboodschap met goed voorstel tot oplossing
Figuur III-15 GUI zonder afdoende foutpreventie
Figuur III-16 Foutpreventie is één ding, gebruiksvriendelijkheid weer een ander
40
10. Help en documentatie
In een goed ontworpen systeem zou de helpfunctie in principe overbodig moeten zijn.
Ditzelfde goed ontworpen systeem laat zich echter kenmerken door een helpfunctie waarin
informatie gemakkelijk kan opgezocht worden en waarin gefocust wordt op de taak die de
gebruiker wil uitvoeren en bijvoorbeeld een korte lijst van concrete stappen aanbiedt om een
opdracht te volbrengen.
III. 3. 6. Usability Testing en ImageJ
In de voorgaande paragraag werden de tien heuristieken besproken waaraan ImageJ in het
kader van Usability Inspection zal worden getest. Om de gebruiksvriendelijkheid van ImageJ te
testen, werden twee andere testen op het getouw gezet. De beide testen werden door vijf
proefpersonen uitgevoerd. Hun profiel vindt u in Tabel III-1. Vijf testgebruikers is theoretisch
gezien niet voldoende voor een sluitende test, maar het schept toch al een duidelijk beeld.
De eerste test was een test met behulp van pen en papier, zoals die in Figuur III-17 staat
afgebeeld. De opdracht luidde als volgt: “U ziet bovenaan de menubalk van ImageJ staan.
Daaronder staat een lijst met de verschillende functies van ImageJ. Probeer de onderstaande
functies bij het juiste menu-item te plaatsen.” De functies variëren bewust van standaard tot
gespecialiseerd. De reden daarvoor komt bij de bespreking van de resultaten aan bod.
Eigenschap Bereik Aantal 0 – 18 jaar 1 19 – 29 jaar 1
Leeftijd
30 – 40 jaar 3 Middelbaar onderwijs 1 Bachelor 3
Opleidingsniveau
Master 1 Weinig 1 Matig 1
Computerervaring
Veel 3 Ja 2 Ervaring met
beeldverwerkingsprogramma’s Nee 3 Gebruikelijke besturingssysteem
MS Windows 5
Uitproberen 5 Externe hulp vragen 0
Gebruikelijke manier om nieuwe programma’s te leren
Documentatie lezen 2
Tabel III-1 Het profiel van de vijf proefpersonen
41
Figuur III-17 Test met pen en papier
In de tweede test werd aan de vijf gebruikers gevraagd om een reeks korte opdrachten uit te
voeren gebruik makend van drie foto’s: Tulpen.jpg, Poes.gif en Peer.bmp. De opdrachten staan
in Tabel III-2 afgebeeld. Zoals duidelijk te zien is, verschillen ook de opdrachten in
moeilijkheidsgraad van elkaar. Terwijl de proefpersonen aan het werk waren, vertelden ze
luidop wat ze dachten, wat ze verwachtten dat er zou gebeuren en gaven ze continu hun
mening over het systeem. Deze meningen werden genoteerd en vervolgens geanalyseerd. In
Appendix B vindt u het volledige verslag van één van de ondervragingen.
42
Tabel III-2 De opdrachten horend bij de Usability Test
1. Open de bestanden Tulpen, Poes en Peer vanuit de map Mijn documenten
2. Doe het volgende voor het bestand Tulpen
Dupliceer het bestand
Maak een rechthoekige selectie binnen deze figuur en kopieer deze selectie naar een
volledig nieuwe foto
Sla de nieuwe foto op in de map Mijn documenten onder de naam Tulpen Selectie
3. Laat een histogram zien van de foto Tulpen
4. Zoom in op de afbeelding Peer. Probeer daarna weer uit te zoomen
5. Vergroot de afbeelding Tulpen met 10 px rondom
6. Verklein de afbeelding Tulpen met 10 px rondom
7. In ImageJ is een functie aanwezig waarmee u de afbeeldingspartikels kan analyseren.
Probeer de functie te vinden. Voer de functie uit gebruik makend van de afbeelding Peer.
Normaal krijgt u nu een foutboodschap. Probeer het nodige te doen om alsnog verder te
kunnen.
8. Open de afbeelding met URL http://www.geocities.com/sabdevreese/Excel/Auto.jpg
9. Draai de afbeelding Auto 90° naar rechts. Zoek de functie Treshold en pas deze functie toe
op de afbeelding
10. Pas op de afbeelding Peer eerst de functie Smooth toe en daarna de functie Find edges.
Probeer tenslotte de oorspronkelijke foto terug te krijgen
11. De functie Measure wordt gebruikt om berekeningen, zoals de oppervlakte, te maken.
Maak gebruik van deze functie om een oppervlakte te berekenen en sla de resultaten op in
een tekstbestand met de naam Oppervlakte in de map Mijn documenten
12. Probeer de functie Plot Profile te vinden en toe te passen
13. Typ een tekst in de foto Tulpen en sla de wijzigingen op in Tulpen
14. Zoek naar de functie die Brightness/Contrast aanpast
15. Duid 2 punten aan in een willekeurige foto en probeer de afstand te berekenen
43
III. 3. 7. Usability Inspection en ImageJ: de resultaten In dit onderdeel wordt besproken of ImageJ overeind blijft, wanneer het tegen het licht van de
tien heuristieken wordt gehouden.
1. Minimalistisch ontwerp
In nevenstaande figuur is
bovenaan het venster te zien
dat je krijgt wanneer je
ImageJ opstart. Het minste
dat je kan zeggen dat het
ontwerp bescheiden is, in dit
geval misschien zelfs net iets
té bescheiden. Er is geen
mogelijkheid om het
venstertje te maximaliseren
en het feit dat er geen groot,
schermvullend venster
aanwezig is, zoals bij zowat
alle andere toepassingen, wordt wel degelijk gemist, op deze manier blijven storende
pictogrammen op het bureaublad immers zichtbaar.
2. Spreek de taal van de gebruiker
Positief in dit verband zijn de pictogrammen onder de menubalk. Voor zowat alle icoontjes is
het duidelijk waarvoor ze staan.
Een eerste zondiging tegen deze regel echter treedt op wanneer
men probeert tekst te plaatsen op een figuur. Logischerwijs
tekent men eerst een tekstvak, typt men vervolgens de tekst en
klikt men daarna buiten het tekstvak. In ImageJ wordt dit
laatste vervangen door Ctrl + D.
Dit is echter nog maar klein bier in vergelijking met de vragen
die rijzen op het ogenblik dat sommige functies gebruikt
worden. De dialoogvensters waarin ons om bepaalde parameters gevraagd wordt, zijn duidelijk
enkel voer voor experten. In Figuur III-20 is het dialoogvenster afgebeeld dat men krijgt als
Figuur III-18 Het hoofdvenster van ImageJ
Figuur III-19 Tekst plaatsen op een figuur
44
men de bewerking Image – Type – 8-bit Color doet. Er wordt blijkbaar verwacht dat we een
waarde ingeven tussen 2 en 256, maar waarvoor deze waarde
staat is helemaal niet duidelijk. Ook de titel van het venstertje
kan weinig soelaas brengen. In Figuur III-21 is het
dialoogvenster afgebeeld dat je krijgt als je de bewerking
Image – Type – 16-bit doet. Opnieuw is dit voer voor
specialisten.
3. Herkennen in plaats van herinneren
Zoals ook mag blijken uit de 2 afbeeldingen behorend bij het
vorige puntje, wordt er blijkbaar een heleboel kennis verwacht
rond de verschillende beeldformaten zoals 8-bit, 16-bit en
32-bit
In Figuur III-22 wordt het dialoogvenster getoond dat hoort bij de functie Analyze Particles.
Van de gebruiker wordt merkelijk verwacht dat hij (nog) weet waarvoor alle verschillende
opties staan. Het probleem beperkt zich niet tot dit ene minder geslaagde dialoogvenster, dit is
jammer genoeg veeleer de trend die heerst binnen ImageJ.
Een ander voorbeeld doet zich voor indien de gebruiker
een selectie wil kopiëren naar een nieuw bestand, toch
een vrij alledaagse bewerking: de gebruiker begint met
het maken van de selectie – moet dan op de statusbalk de
grootte van de selectie snel aflezen, want als de muis
wordt bewogen verdwijnen de afmetingen weer van de
statusbalk – schrijft deze afmetingen best op – zoekt op
welke het type is van het bronbestand (8-bit, 16-bit, …) –
maakt een nieuw bestand met de verzamelde gegevens –
plakt de selectie in het nieuwe bestand. Een instructie in
de aard van ‘Plakken in – Nieuw bestand’ zou hier zeker
niet misstaan.
Figuur III-20 Voorbeeld van een dialoogvenster
Figuur III-21 Voorbeeld van een ander dialoogvenster
Figuur III-22 Dialoogvenster dat hoort bij de functie Analyze Particles
45
4. Streef naar consistentie
Hoewel dit op het eerste zicht de meest triviale regel lijkt, is het precies deze regel die in
ImageJ het vaakst met de voeten wordt getreden. ImageJ zondigt dikwijls tegen algemeen
aanvaarde regels. Hieronder zijn een aantal voorbeelden opgesomd.
• Zoals ook te zien op Figuur III-18 wordt de statusbalk niet alleen gebruikt om de staat van
het huidige proces aan te geven, maar wordt ze ook gebruikt om de functie van de knoppen
op de werkbalk te omschrijven en om bijvoorbeeld de afmetingen van de selectie te tonen
• De sluitknoppen rechtsbovenaan de dialoogvensters kunnen niet gebruikt worden om het
dialoogvenster te sluiten, er gebeurt simpelweg niets
• Wanneer de gebruiker een bewerking heeft uitgevoerd op een foto en hij de sluit de foto,
komt er geen dialoogvenster om te vragen of de wijzigingen moeten worden opgeslagen
• Als je een bestand vroeger al hebt opgeslagen en je kiest daarna weer voor File – Save, krijg
je normaal niets. In ImageJ daarentegen verschijnt de onderstaande, ongebruikelijke
melding
• Ook de functie File – Save As ziet er wat ongebruikelijk uit (Figuur III-24)
• De kroon wordt echter gespannen door het vreemde gebruik van vensters.
Er is een belangrijke eigenaardigheid geslopen in het programmeren van de vensters. Elk
venster leidt namelijk een min of meer zelfstandig leven. Bekijk hiertoe Figuur III-25. Aan
de linkerkant van de figuur staat Adobe Photoshop. Er zijn momenteel 3 foto’s geopend.
Aan de rechterkant van de schermafdruk staat ImagJ. Ook hierin zijn 3 foto’s geopend. De
lay-out is lichtjes verschillend tussen beide programma’s maar tot dusver geen enkel groot
Figuur III-23 Dialoogvenster dat hoort bij de functie Save
Figuur III-24 De functie Save As
46
probleem. Wanneer men echter een blik op de taakbalk werpt, wordt de verschillende
benadering van de twee programma’s met betrekking tot de foto’s eensklaps wel duidelijk.
Daar waar Photoshop de foto’s opent in subvensters – geen extra knop op de taakbalk per
foto – worden de foto’s in ImageJ in hoofdvensters – wél een extra knop op de taakbalk –
geopend. De keuze in ImageJ om alle foto’s te openen in hoofdvensters – die normaal
gezien enkel gereserveerd worden voor applicaties – is volledig in strijd met de
consistentieregel en heeft bovendien soms vreemde gevolgen.
Een eerste van deze gevolgen is te zien op Figuur III-26. In deze figuur werd ImageJ
geminimaliseerd: het hoofdvenster van ImageJ rechts bovenaan is niet langer zichtbaar. De 3
figuren die geopend waren in ImageJ zijn daarentegen gewoon blijven bestaan. Dit is op zijn
minst vervelend te noemen. Sommige foto’s staan als het ware verdwaald op het scherm. Het
omgekeerde is evengoed waar, nadat ImageJ verborgen werd achter een schermvullende
toepassing, moeten ImageJ en élk van de openstaande foto’s elk afzonderlijk terug zichtbaar
gemaakt worden door ze te activeren in de taakbalk.
Figuur III-25 Photoshop en ImageJ naast elkaar. In de beide programma’s zijn 3 foto’s geopend
47
Een andere repercussie van het uitzonderlijke gebruik van vensters wordt duidelijk gemaakt
aan de hand van Figuur III-27 en
Figuur III-28.
In Figuur III-27 staan de
afbeeldingen PET-scan en
Clown. Door middel van
Analyze – Histogram werd het
histogram van de Clown
opgevraagd. Het resultaat
verschijnt – hoe kan het ook
anders – in een ander venster.
Voor dit soort vensters werd er
geen gebruik gemaakt van een
traditioneel dialoogvenster, neen,
dit is opnieuw een hoofdvenster mét knop op de taakbalk én mogelijkheid tot minimaliseren en
maximaliseren.
Het wordt nog leuker als we er eventjes met ons gedachten niet bij zijn. We besluiten wat ruis
toe te voegen aan PET-scan, maar vergeten om de foto eerst te selecteren. In Figuur III-28 ziet
u het resultaat. Zoek het verschil!
Figuur III-26 Photoshop en ImageJ naast elkaar. ImageJ is geminimaliseerd
Figuur III-27 ImageJ, 2 foto’s en een histogram
48
5. Waardevolle feedback
Hier kunnen we gelukkig gematigd positief zijn. Er werden een beperkt aantal functies
gevonden die gewoon zonder resultaat blijven – er verandert zichtbaar niets aan de foto, noch
verschijnt er een foutmelding – maar dit zijn de uitzonderingen.
6. Eenvoudige manieren om acties ongedaan te maken
Dit is nog een heikel punt binnen ImageJ. De klassieke
bewerking Ongedaan maken bestaat, maar kan niet meer dan
één stap terugkeren. Bovendien werkt Ongedaan maken na
sommige bewerkingen niet. In nog andere gevallen wordt het
vooraf gemeld dat Undo achteraf niet kan uitgevoerd worden.
De functie Redo of Opnieuw uitvoeren is helemaal afwezig
7. Shortcuts
Er zijn behoorlijk wat sneltoetsen aanwezig, ook de klassiekers zoals Ctrl + N, Ctrl + O,
Ctrl + V, … ontbreken niet.
Daarnaast bestaat de mogelijkheid om macro’s te schrijven en last but not least zijn er de
plugin’s die virtueel elk fotobewerkingsprobleem uit de wereld zouden moeten kunnen helpen.
Figuur III-28 ImageJ, 2 foto’s en een histogram
Figuur III-29 Undo is niet beschikbaar
49
8. Betekenisvolle foutboodschappen
De feedback bij fouten is bondig, maar doorgaans ‘to the point’
9. Foutpreventie
Op het vlak van foutpreventie laat ImageJ weer wat steken
vallen. Zoals reeds vermeld in puntje vier, wordt er onder andere niet gevraagd of wijzigingen
moeten opgeslagen worden wanneer een foto (per ongeluk) wordt gesloten. Ook wordt er
nagelaten om functies die niet kunnen toegepast worden op de actieve foto te desactiveren, in
plaats daarvan krijgt men een foutmelding zoals bijvoorbeeld deze uit Figuur III-30 . Het valt
ook voor dat de gebruiker eerst nog een dialoogvenster krijgt waarin parameters moeten
ingevuld worden en pas nadat op OK geklikt werd in dit venster, verschijnt de melding dat
deze functie op de foto niet toepasbaar is.
10. Help en documentatie
Door te klikken op de Help knop, komt men op de website terecht. Deze website is niet
onmiddellijk een schoolvoorbeeld van de pérfecte helpfunctie, maar met wat goede wil, moet
het toch lukken om het nodige te vinden.
III. 3. 8. Usability Testing en ImageJ: de resultaten In deze paragraaf worden de resultaten van Usability Testing versus ImageJ beschreven. We
beginnen met de pen en papier test. De gedetailleerde resultaten van de test met pen en papier
zijn ondergebracht in Tabel III-3 In de tabel zijn de functies, die aan de testgebruikers werden
voorgelegd, onderverdeeld in drie groepen: basis – geavanceerd – super. De eerste groep – de
basis groep – wordt uitgemaakt door elementaire functies zoals openen en sluiten. De tweede
groep – de groep geavanceerd – telt functies zoals Fill, Draw, Rotate en Duplicate onder zijn
leden. Dit zijn functies die typisch aanwezig zijn in beeldverwerkingsprogramma’s, maar door
hun aanschouwelijke aard ook bevattelijk zijn voor mensen met niet meer dan gebruikelijke
PC-kennis. De derde groep tenslotte bestaat uit Histogram, Find Edges, … hier gaat het om
sterk gespecialiseerde functies. Waarom wordt deze onderverdeling in groepen gemaakt?
Gewoonweg omdat het niet correct is om bijvoorbeeld een persoon met weinig PC-kennis
ImageJ te laten gebruiken, tot de conclusie te komen dat deze persoon het er niet zo best van
afbrengt en dan de schuld bij ImageJ te leggen. Anders geformuleerd: we willen nagaan of de
weinig ervaren gebruiker de standaardfuncties goed weet te plaatsen, of de meer ervaren
Figuur III-30 Foutboodschap in ImageJ
50
gebruikers ook de meer geavanceerde functies kunnen thuisbrengen en tot slot of diegenen met
ervaring in een ander fotobewerkingsprogramma ook de zeer gespecialiseerde functies op de
juiste plaats weten neer te zetten.
Welke conclusies kunnen op basis van deze eenvoudige en beperkte test getrokken worden?
Al bij al bleek het achteraf niet zo eenvoudig om de gegevens verkregen met deze test juist te
interpreteren, omdat uit de resultaten niet duidelijk naar voor kwam waarom de testgebruikers
welke functie bij welk menu-item geplaatst hadden.
Één conclusie ligt wel voor de hand: de standaardfuncties, zoals openen en opslaan, zitten op
de juiste plaats, want bijna alle gebruikers hadden deze functies juist.
Maar wat met de andere functies? De twee proefpersonen met wat ervaring in Photoshop,
Persoon 4 en 5, deden het opvallend beter dan hun ervaringsloze collega’s. De vraag die zich
daardoor opwierp, was, of de test misschien wat te hoog gegrepen was voor de drie anderen:
“Hadden deze personen wél de correcte antwoorden gevonden bij een ander
fotobewerkingsprogramma?” Hier schiet de pen en papier test duidelijk te kort.
Valt er dan werkelijk bijna niets te besluiten uit de test? Misschien wel. We mogen ervan
uitgaan dat de test voor Persoon 4 en 5 niet te moeilijk was en dat daarom hun resultaten
betrouwbaar zijn. Dan luidt de eenvoudige conclusie dat de functies die beide proefpersonen
bij het juiste menu-item plaatsten, zo goed als zeker daar op de juiste plaats zitten en dat de
functies die ze beiden verkeerd plaatsten even zeker, beter bij een ander menu-item een
onderkomen zouden zoeken. Deze conclusie is echter niet volledig hard te maken, want het
blijft een open vraag in welke mate Persoon 4 en 5 “geconditioneerd zijn door Photoshop” en
precies daarom “gelijkaardig gedrag vertonen”. Kort samengevat heeft de pen en papier test
weinig bruikbaars opgeleverd.
Bij de tweede deel van de Usability Test werd van de vijf deelnemers verwacht dat ze een
aantal opdrachten uitvoerden, onderwijl hun commentaren spuiend. Een deel van hun
bevindingen werd reeds verwerkt in de tekst over Usability Inspection. Algemeen kan gezegd
worden dat de testpersonen behoorlijk wat moeite hadden om de opdrachten tot een goede
einde te brengen. Bovendien viel het op dat men er naar het einde toe minder zin in had omdat
men vond dat het systeem niet “meewerkte”. Hieronder staat een korte opsomming van de
belangrijkste grieven van de testpersonen.
1. De lay-out van het hoofdvenster is ongewoon
2. Save en Save As vertonen afwijkend gedrag
51
Functie Persoon 1 Persoon 2 Persoon 3 Persoon 4 Persoon 5 Antwoord
Open � � � � � File
Quit � � � � � File
Select All � � � � � Edit
About ImageJ
� � � � � Help
Fill � � � � � Edit
Draw � � � � � Edit
Duplicate � � � � � Image
Rotate � � � � � Image
Add noise � � � � � Process / Add Noise
Brightness / Contrast
� � � � � Image / Adjust
Restore selection
� � � � � Edit
Measure � � � � � Analyze
Math � � � � � Process
Histogram � � � � � Analyze
Find edges � � � � � Process
Save x y coordinate
� � � � � Analyze / Tools
Convolve � � � � � Process / Convolve
Calibrate � � � � � Analyze
Shadows � � � � � Process
Compile And Run
� � � � � Plugins
Stack / Add Slice
� � � � � Image / Stack / Add Slice
Tabel III-3 Resultaten van de test met pen en papier
52
3. Zomaar afsluiten van een gewijzigde foto is ongehoord
4. Er wordt teveel kennis verwacht omtrent beeldverwerking om vlot met ImageJ overweg
te kunnen
5. De foutboodschappen zijn soms te technisch en geven niet altijd aan wat er moet gedaan
worden om het probleem te verhelpen. Soms gebeurt er simpelweg niets.
6. Kopiëren en plakken van een selectie in een nieuwe foto zou veel eenvoudiger moeten.
(Geen enkele van de testpersonen bracht deze opdracht tot een goed einde)
7. Het gebruik van Ctrl + D om tekst toe te voegen is omslachtig
8. De functie Ongedaan maken moet absoluut uitgebreid worden naar meerdere stappen
9. Het is heel moeilijk om te onthouden welke functies zich in welk menu bevinden
III. 3. 9. Besluit Van de drie methodes die gebruikt werden om de gebruiksvriendelijkheid van de lay-out van
ImageJ te testen, waren vooral de gestructureerde evaluatie aan de hand van de tien
heuristieken en de test waarbij gebruikers luidop nadachten, de meest interessante. De
resultaten bekomen uit beide testen bevestigden elkaar. Aangezien de groep testpersonen nogal
klein was, is de test niet volledig betrouwbaar, en daarom zullen sommige onvolkomenheden
nog niet aan de oppervlakte zijn gekomen. De test met pen en papier verschafte weinig nieuwe
inzichten.
De globale conclusie die uit deze drie testen naar voor komt, is dat ImageJ het zeer zeker niet
moet hebben van z’n ‘great looks’. Dat staat al vast van het ogenblik dat men het programma
opent. De schrijver van dit programma is teveel programmeur en te weinig ontwerper geweest.
Er zijn onder andere de kleine gebreken
zoals een vreemd aandoende lay-out of
een gebrekkige Save of Save As. Het is
echter het uitgesproken technisch-
wetenschappelijke karakter van ImageJ,
het zijn de moeizaam te begrijpen
dialoogvensters en de voortdurende
confrontatie met is-het-nu-8-bit,-16-bit-
of-32-bit, die gebruikers het vaakst de
wenkbrauwen doen fronsen.
Figuur III-31 Usability Engineering
53
III. 4. Studie van de implementatie III. 4. 1. Inleiding De oorspronkelijke doelstelling bij de implementatie van het applet werd niet volledig gehaald.
Het initiële doel was om de applet te laten fungeren als onderdeel van ImageJ. Achter de
schermen wordt in het huidige applet nog altijd volop gebruik gemaakt van ImageJ, maar dat
de studenten ook de beschikking zouden hebben over het venster van ImageJ met de eraan
verbonden functies werd noodzakelijkerwijs uit het project geschrapt. Dat gebeurde natuurlijk
niet zomaar. In dit laatste deel wordt duidelijk waarom het eens zo veelbelovende systeem
meer dan eens een koppige ezel bleek.
De hiernavolgende tekst vangt aan met uitleg over de 10 heuristieken die werden gebruikt om
de kwaliteit van de implementatie van ImageJ na te gaan. Vervolgens wordt ImageJ aan elk
van deze heuristieken stap voor stap getoetst. Tenslotte wordt een korte suggestie geformuleerd
over hoe de structuur van ImageJ er beter had kunnen uitzien.
III. 4. 2. Heuristieken voor goed object georiënteerd ontwerp Elke programmeur is vertrouwd met de symptomen van slecht geschreven software: één
ogenschijnlijk minuscule ingreep blijkt een zondvloed van errors op gang te brengen, de taak
die je eerst dacht in twee uur te klaren, krijg je met moeite klaar in twee dagen. Of het
oplappen van één klasse vertaalt zich in het disfunctioneren van een andere klasse. Om zich
tegen zoveel onheil te behoeden, bestaan er gelukkig een aantal regels [2] over hoe een goed
object georiënteerd ontwerp er moet uitzien. Deze regels zijn niet afkomstig van één persoon,
maar zijn het resultaat van de door de decennia heen opgebouwde ervaring van tientallen
software experten. Mits toepassing ervan zouden de hiervoor beschreven kwellingen
achterwege moeten blijven, of toch zo goed als.
1. Open en gesloten
Van alle bekende principes in object georiënteerd ontwerp is dit principe zonder twijfel het
belangrijkste. Elke module – hoe klein ook – moet zo geschreven worden dat ze eenvoudig kan
uitgebreid worden zónder dat ze daarvoor moet aangepast worden. De idee hierachter is
eenvoudig: het is beter dat veranderingen geen invloed hebben op reeds bestaande code: als je
de al goed functionerende code namelijk niet wijzigt, is er nauwelijks kans dat er alsnog fouten
in deze code sluipen.
54
Hoe moet dit, op het eerste zicht contradictorische principe, gerealiseerd worden? Abstractie
blijkt hier hét toverwoord. Zowel eenvoudige abstractie via overerving als verregaande
abstractie via polymorfie zijn aan de orde.
2. Het substitutieprincipe van Liskov
Dit principe kan het best als volgt in object georiënteerde taal omschreven worden: “De
methodes van een basisklasse moeten ook vlot gebruikt kunnen worden
door instanties van de afgeleide klassen.” Dit lijkt evident, maar toch
kunnen subtiliteiten soms roet in het eten gooien. Een bekend voorbeeld
hiervan is het verhaal van de ellips en de cirkel. Van in de lagere school
wordt verteld dat een cirkel niets anders is dan een bijzondere ellips.
In Java gaat die vlieger slechts gedeeltelijk op. Bekijk daartoe
onderstaande code.
public class Ellips { Point brdptA; Point brdptB; double lengteGroteAs; public Point getBrdptA () {return brdptA;} public Point getBrdptB () {return brdptB;} public double getLengteGroteAs () {return lengte GroteAs;} public setBrdptAEnB (Point a, Point b) {brdptA = a; brdptB = b;} }
Voor de cirkel zijn er geen twee brandpunten nodig, dus besluiten we de volgende klasse te
schrijven
public class Cirkel extends Ellips{ public setBrdptAEnB (Point a, Point b) {brdptA = a; brdptB = a;} }
Tenslotte kan een eenvoudige testmethode natuurlijk niet ontbreken public void test (Ellips e){ Point a = new Point (-1,0); Point b = new Point (1,0); e.setBrdptAEnB(a,b); if (a == e.getBrdptA && b == e.getBrdptB) { . .. } }
Zolang aan de methode test een echte instantie van de klasse Ellips , en dus geen Cirkel ,
meegegeven wordt als parameter, zal alles naar wens verlopen. Op het ogenblik echter dat de
Figuur III-32 Cirkel is een afgeleide klasse van Ellips
55
parameter een instantie is van de klasse Cirkel , zal het programma onverwachts vreemd
reageren.
3. Inverse afhankelijkheid
Dit principe beschrijft de globale structuur die een goed ontworpen OO-applicatie moet
hebben. Deze regel kan het eenvoudigst visueel voorgesteld worden. Tussen klassen bestaan er
onderlinge afhankelijkheden. In een ideale situatie zien deze afhankelijkheden eruit zoals in
Figuur III-33.
Dit is een bijzonder draconisch principe en in de praktijk zijn er vaak verzachtende
omstandigheden om de regel al eens met de voeten te treden. Toch is het een goed idee om de
regel zo vaak als ook maar enigszins mogelijk te volgen. Abstracties worden op deze manier
namelijk als het ware de breekpunten van het ontwerp: dit zijn plaatsen waar het ontwerp
uitgebreid kan worden, bijvoorbeeld door middel van een nieuwe implementatie van de
abstractie, of gewijzigd kan worden, zonder daarom het globale systeem overhoop te gooien.
4. Gesegregeerde interfaces
In grote projecten komt het vaak voor dat sommige klassen fungeren als werkpaarden,
bijvoorbeeld om berekeningen uit te voeren die nodig zijn, en waarvan de resultaten daarna
met behulp van andere klassen aan de gebruiker getoond worden. Er bestaat nogal vlug de
neiging om van deze klassen echte Brabantse trekpaarden te maken: berekeningen tot het
bekomen van resultaat A hangen namelijk dikwijls nauw samen met deze tot het verkrijgen van
resultaat B of C, of ze maken bijvoorbeeld gebruik van dezelfde data. Wanneer een klasse op
een gegeven ogenblik een heleboel methodes implementeert ten behoeve van verschillende
Figuur III-33 Ideale structuur van een goed OO-ontwerp
56
client-klassen, is het vaak niet meer duidelijk welke methodes van de serverklasse initieel voor
welke client werden geïmplementeerd. Methodes die misschien oorspronkelijk bedoeld waren
voor client A, worden nu ook gebruikt voor client B. Wijzigingen in de methodes in functie
van client A, kunnen daarom onverwachts ook nare gevolgen hebben voor instanties van klasse
B. Om dit probleem te voorkomen en toch gebruik te kunnen maken van zo’n monsterklasse, is
het beter om te kiezen voor de aanpak zoals voorgesteld in Figuur III-35.
Het verdient voorspraak om de clients de serviceklasse te laten benaderen via interfaces. De
afzonderlijke methodes die elke groep van samenhorende klassen (Client A, Client B, …)
nodig heeft, worden in interfaces ondergebracht en de serviceklasse implementeert dan elk van
deze interfaces. Het grote voordeel van deze gesegregeerde aanpak is dat wijzigingen
aangebracht in methodes voor groep A veel minder vaak de methodes nodig voor B kunnen
beïnvloeden want elk beschikt over zijn eigen specifieke methodes zoals vastgelegd door de
interfaces. Toch kan alles samengebracht worden in één klasse.
De voorgaande vier regels zijn geldig op het niveau van de klassen. In talen zoals Java is echter
ook het gebruik van packages evident. Meestal zijn packages niets anders dan een verzameling
klassen met samenhangende functionaliteit.
In het licht van goed OO-ontwerp is het de afhankelijkheidsrelatie tussen twee packages die
ons interesseert. We spreken van zo’n afhankelijkheidsrelatie vanaf het moment dat er een
relatie bestaat tussen twee klassen uit verschillende packages. Het doel van goed OO-ontwerp
is niet zozeer te verhinderen dat er nog ‘inter-packages’ relaties optreden, dit kan simpelweg
niet vermeden worden. Het doel bestaat er wel in om de afhankelijkheden in de juiste richting
te laten wijzen.
Figuur III-34 De klasse Service implementeert functionaliteit voor Client A en Client B
Figuur III-35 De klasse Service implementeert functionaliteit voor Client A, Client B en Client C via interfaces
57
De vraag die zich nu stelt, luidt: “Bestaan er regels om de juiste klassen in de juiste packages
onder te brengen?” Zeer zeker, niet minder dan zes! De eerste drie van deze zes principes
geven in het bijzonder richtlijnen over hoe klassen best in packages ingedeeld kunnen worden.
5. Eenheid van release = eenheid van hergebruik
Wat verstaan we onder het hergebruik van code? Hoegenaamd niet het knippen en plakken van
code van een ander naar eigen programma’s, op deze manier wordt de verkregen code immers
eigen code. Het is degene die knipt en plakt die verantwoordelijk wordt voor de code en die
moet instaan voor fouten of onvolkomenheden die in de code aanwezig zouden zijn. Dit alles
in tegenstelling tot écht hergebruik van code, waarbij de oorspronkelijke ontwerper de code
verder bijwerkt en gebruikers op de hoogte brengt van nieuwe – betere – versies. Deze nieuwe
versies worden vanzelfsprekend niet klasse per klasse gepubliceerd, maar in grotere gehelen.
Omdat er binnen zo’n geheel vaak een verband bestaat tussen de klassen, is het als
hergebruiker van de code niet mogelijk om enkel die klasse uit het geheel te lichten, die je
nodig hebt. Precies daarom zijn de eenheden code die één kan hergebruiken in zijn eigen code
noodzakelijk gelijk aan de eenheden waarin nieuwe versies van de herbruikbare code ter
beschikking gesteld worden.
6. Samen wijzigende klassen verenigen in één package
Een groot project wordt om begrijpelijke redenen vaak onderverdeeld in samenwerkende
packages. Het testen en beheren van deze verschillende packages is een niet-triviale klus. Hoe
meer packages wijzigen bij elke nieuwe release, des te meer werk er is om de nieuwe versie
klaar te stomen en te testen. In dat licht zou het handig zijn om de klassen dusdanig in
packages onder te brengen dat het aantal packages dat wijzigt bij een nieuwe release tot een
minimum beperkt blijft. De idee is niet zo moeilijk, de uitvoering daarentegen is niet
vanzelfsprekend. De klassen waaruit een programma is opgebouwd, wijzigen – vaak toenemen
– nu eenmaal na verloop van tijd. Men moet daarom eigenlijk trachten te anticiperen op
eventuele aanpassingen die in de toekomst zouden kunnen gebeuren. Omdat het al met al toch
wat natte vingerwerk is om op voorhand te weten wat later eventueel samen zal veranderen,
kan men de regel vereenvoudigen door gewoon deze klassen die nú samen veranderen in
packages samen te brengen.
58
7. Samen gebruikte klassen vereningen in één package
Deze regel is een mogelijk alternatief voor de twee voorgaande principes. De regel leert dat een
package enkel zou mogen bestaan uit klassen die samen gebruikt worden.
En ook voor deze regel kan een goede reden aangehaald worden: op die manier worden
gebruikers immers niet om de haverklap gedwongen om nieuwe releases te installeren.
Stel dat een software ingenieur een heel groot package gemaakt heeft, dat heel uiteenlopende
functionaliteit implementeert, dan moet de gebruiker iedere keer er een nieuwe versie
verschijnt, een upgrade doen, ook als er enkel iets verandert aan functies waarvan hij nooit
gebruik maakt. Dit in tegenstelling tot wanneer er niet één groot package is, maar er
verschillende kleinere packages bestaan: dan moet er enkel een update geïnstalleerd worden op
het ogenblik dat er vernieuwingen zijn voor het door hem gebruikte kleinere package, wat
normaliter veel minder vaak het geval zal zijn dan bij het gebruik van één groot package.
Het probleem dat bij het gebruik van bovenstaande regels opduikt, is dat ze mekaar soms
tegenwerken. Zo zegt de tweede regel dat
klassen die samen veranderingen zullen
ondergaan samen moeten gebracht worden
in een package, terwijl regel drie spreekt
over klassen met gelijklopende
functionaliteit en er op hamert dat
packages zeker niet te groot mogen
gemaakt worden. Dit is natuurlijk geen
reden om de drie regels zomaar overboord
te gooien.
8. Geen cyclische afhankelijkheden
Zoals hierboven reeds gezegd, is het zo dat packages vaak klassen bevatten die functioneel
afhankelijk zijn. Wanneer ingenieurs klaar zijn met de nodige wijzigingen aan te brengen in
een package, moet het getest worden in combinatie met de andere packages, waarvan het
afhankelijk is. Het is evident dat deze klus gemakkelijker te klaren is wanneer het package
afhangt van slechts een beperkt aantal andere packages. Bekijk daartoe bijvoorbeeld
Figuur III-37. Wat zal er gebeuren wanneer het package Protocol werd gewijzigd? Het package
moet samen met het package Communicatie Errors getest worden. Dit is fijn: slechts één extra
package is nodig.
Figuur III-36 De Triad Driehoek
59
Bekijk nu echter Figuur III-38. Een programmeur die werkte aan het package Communicatie
Errors besliste om een foutboodschap uit te schrijven op het scherm. Aangezien het scherm
gecontroleerd wordt door het package GUI, wordt het package Communicatie Errors op die
manier afhankelijk van het package GUI. Het probleem dat hieraan zijn ontstaan dankt wordt
zichtbaar wanneer er een nieuwe versie van bijvoorbeeld het package Protocol moet getest
worden. Nu moet niet één maar, maar moeten alle packages betrokken worden in de test. Cycli
moeten daarom ten alle prijze vermeden worden.
Figuur III-37 Mogelijke package structuur
Figuur III-38 Package structuur die cyclus bevat
60
9. Afhankelijk van stabiele packages
Wanneer is iets stabiel? We kunnen zeggen dat iets stabiel is, wanneer het moeilijk is om te
veranderen. In een software omgeving zeggen we dat één package moeilijk te veranderen, of
stabiel, is wanneer veel andere packages ervan afhankelijk zijn. Zoals afgebeeld in
Figuur III-39. Drie packages zijn afhankelijk van package X, dit zijn drie goede redenen om
package X ongemoeid te laten.
Dit principe lijkt misschien in
strijd met de voorgaande
principes die een manifest zijn
voor makkelijk veranderbare
software, maar is het niet: er zal
nog blijken dat het een goede
zaak is dat sommige delen van
de software zeer stabiel zijn en dat andere delen onstabiel zijn.
10. Stabiele abstracte packages
Het begint langzaam aan duidelijk te worden hoe de globale structuur van een goed ontworpen
systeem er moet uitzien: één toepassing is een verzameling van intergerelateerde packages met
instabiele packages bovenaan de structuur en stabiele packages onderaan. In dit beeld wijzen
de afhankelijkheidsrelaties van boven naar onder. De vraag die nu nog rest is: “Zijn we wel
compleet gelukkig met deze stabiele maar moeilijk te veranderen packages onderaan de
structuur?” Hoe meer packages er moeilijk te veranderen zijn, des te minder flexibel zal ons
systeem zijn. De vluchtweg uit dit tweespalt brengt ons terug bij de eerste van deze tien regels.
Als de packages onderaan erg abstract zijn, dan zijn ze misschien wel moeilijk intern te
veranderen, maar kunnen ze wel makkelijk uitgebreid worden. Anders geformuleerd wil dit
zeggen dat een goed opgebouwde toepassing bestaat uit instabiele, makkelijk aanpasbare
packages bovenaan en stabiele, makkelijk uitbreidbare packages onderaan.
III. 4. 3. Heuristieken voor goed object georiënteerd ontwerp en ImageJ Intussen hebben we een meer dan voldoende idee gekregen van hoe een goede OO-architectuur
er dient uit te zien, laten we nu ImageJ hiermee confronteren.
Figuur III-39 Drie packages zijn afhankelijk van package X
61
Vooraleer ImageJ op de rooster te leggen, worden eerst in het kort een aantal belangrijke
klassen uit ImageJ omschreven, die in de vervolgtekst frequent zullen opduiken.
• ImageWindow = extensie van java.awt.Frame, dit is het venster dat ImageJ gebruikt om een
foto in te tonen. In Figuur III-40 is een ImageWindow te zien.
• StackWindow = extensie van ImageWindow, dit is het venster
waarin een stapel foto’s getoond wordt, dit venster heeft onderaan
een schuifbalk (Zie Figuur I-15)
• Roi = de klasse die een selectiekader bijhoudt, dit selectiekader
kan een rechthoek, een ovaal, een punt, … zijn
• ImageCanvas = extensie van java.awt.Canvas, hierop wordt de
foto getekend
• ImageProcessor = dit is zonder meer dé basisklasse te noemen, deze klasse bevat onder
andere de array van pixels die een foto eigenlijk is
• ImagePlus = de representatie van een foto in ImageJ. Dit is een object dat de foto bevat (een
instantie van ImageProcessor) + het bijhorende venster (een instantie van ImageWindow) +
de eventuele selectie (een instantie van Roi)
1. Open en gesloten
Als we dit eerste principe toepassen op ImageJ en tegelijk weten dat dit het belangrijkste
principe is, dan laat de rest al niet veel goeds meer vermoeden. Volgens dit principe is
abstractie de heilige graal van goed OO-ontwerp en in ImageJ tellen we slechts zes interfaces
op net geen honderd klassen. Abstractie komt nauwelijks aan bod in ImageJ. De enige
belangrijke uitzondering hierop is de abstracte klasse ImageProcessor. Het is een goede zaak
dat deze klasse abstract werd gemaakt. Zo kan, in theorie, van deze klasse een nieuwe klasse
afgeleid worden, bijvoorbeeld ten behoeve van een nieuw type beeldformaat. Hierdoor kan de
functionaliteit van ImageJ uitgebreid worden zonder dat er wijzigingen moeten aangebracht
worden in andere klassen die instanties van de klasse ImageProcessor gebruiken.
2. Het substitutieprincipe van Liskov
Het lijkt erop dat ook dit principe het niet gehaald heeft. Dit principe zegt dat de methodes van
een basisklasse ook vlot moeten gebruikt kunnen worden door instanties van afgeleide klassen.
Één voorbeeld dat dit in ImageJ niet het geval is, wordt gevonden in de klasse Roi. Van deze
klasse worden de klassen OvalRoi, PolygonRoi, FreehandRoi, … afgeleid.
Figuur III-40 Selecties in ImageJ
62
Het begint al in de definitie van de klasse Roi, waarin de verschillende types gedefinieerd
worden. In de figuur hieronder ziet u een deel van de broncode zoals deze op het Internet te
vinden is.
En zoals was te verwachten, vinden we in de code de typische if – else constructies terug
en wat verder iets soortgelijks
Hieruit volgt duidelijk dat de afgeleide klassen geen volledige substituten zijn van de
basisklasse: de implementatie is anders naargelang het om de basisklasse dan wel om één van
de afgeleide klassen gaat.
3. Inverse afhankelijkheid
Dit is het principe dat zegt dat afhankelijkheden best kunnen wijzen in de richting van een
interface. In de nevenstaande figuur worden de afhankelijkheden tussen de vijf belangrijkste
klassen van ImageJ visueel weergegeven.
Het mag wel duidelijk zijn dat deze structuur in niets
gelijkt op de ideale structuur zoals voorgesteld in
Figuur III-33. De enige abstracte klasse in deze figuur
is de klasse ImageProcessor. De regel zegt dat élke
afhankelijkheid binnen een ontwerp zich zou moeten
richten naar een interface, of een abstracte klasse en dat
geen enkele afhankelijkheid zich zou mogen richten
naar een concrete klasse. Weer een principe dat met
andere woorden niet werd gevolgd.
Figuur III-41 Afhankelijkheden tussen de belangrijkste klassen van ImageJ
63
4. Gesegregeerde interfaces
Over de toepassing van dit principe valt er nauwelijks iets te zeggen. Het is nergens terug te
vinden in ImageJ.
De volgende zes heuristieken hebben betrekking op de packages waaruit een systeem bestaat.
Voor de duidelijkheid worden daarom hier eerst de verschillende packages van ImageJ
opgesomd, met een kort woordje uitleg.
ImageJ bestaat uit precies elf packages:
• Package ij = bevat onder andere de klassen ImageJ (het hoofdvenster), ImagePlus,
ImageStack en WindowManager
• Package ij.gui = bevat – zoals de naam het zelf zegt – alle klassen die van ver of van dicht
iets te maken met GUI’s, zoals ImageCanvas, ImageWindow, Roi, MessageDialog
• Package ij.io = bevat klassen voor input en output, zoals FileOpener, FileSaver, Opener, …
• Package ij.macro = bevat klassen die de macrofunctie ondersteunen, zoals MacroRunner
• Package ij.measure = de belangrijkste klasse hieruit is de klasse Calibration
• Package ij.plugin = bevat plugin’s die standaard met het systeem meegeleverd worden
(daarnaast kan je nog extra plugin’s downloaden van op de website)
• Package ij.plugin.filter = dit zijn extra filters die onder de vorm van plugin’s
geïmplementeerd zijn
• Package ij.plugin.frame = dit zijn extra vensters die onder de vorm van plugin’s
geïmplementeerd zijn
• Package ij.process = bevat klassen zoals ImageProcessor, dit package is dé basis van het
systeem
• Package ij.text = bevat de klassen TextPanel en TextWindow
• Package ij.util = bevat een aantal tools zoals de klasse StringSorter
5. Eenheid van release = eenheid van hergebruik
6. Samen wijzigende klassen verenigen in één package
7. Samen gebruikte klassen verenigen in één package
Deze drie regels kunnen samen behandeld worden, omdat ze toch hetzelfde op het oog hebben,
namelijk bepalen volgens welke verdeelsleutel klassen in packages moeten ingedeeld worden.
Als we de inhoud van de packages van ImageJ, en de namen ervan in het bijzonder, bekijken,
dan worden de klassen hoogstwaarschijnlijk op basis van hun functionaliteit gegroepeerd in
64
packages. Dit blijkt duidelijk uit het package ij.text met enkel de klassen TextPanel en
TextWindow of het package ij.process met klassen zoals ImageProcessor of ImageConverter.
Het lijkt er daarom op dat principe 7 het gehaald heeft. Dat mag ook niet zo verwonderlijk
heten. Het gaat hier uiteindelijk om een volledig open systeem, dat vrij mag hergebruikt
worden. In dat opzicht is het verstandig om klassen die bijvoorbeeld verantwoordelijk zijn voor
basisbewerkingen, zoals ImageProcessor, in één package op te nemen. Iemand kan dan enkel
dit package hergebruiken en er zelf een nieuwe omkadering rond bouwen.
Je zou echter ook een rol kunnen toebedelen aan principe 6, dat zegt dat samen wijzigende
klassen samen horen in één package. Zo is het bijvoorbeeld veel minder waarschijnlijk dat er
nog aanpassingen gebeuren aan het package ij.process, dat echt de kern uitmaakt van het
geheel, dan bijvoorbeeld aan het package ij.gui: veranderingen aan het uitzicht van ImageJ of
eventueel aan het uiterlijk van de dialoogvensters, zijn niet uit te sluiten.
Welke regel precies gevolgd werd, is niet belangrijk. We mogen wel besluiten dat de klassen
niet willekeurig in packages werden ondergebracht.
8. Geen cyclische afhankelijkheden
Dit principe bindt de strijd aan met cycli die in het ontwerp sluipen, maar heeft hier duidelijk
de strijd verloren. In Figuur III-42 ziet u de
afhankelijkheden tussen de vier belangrijkste
packages. Zoals duidelijk te zien is zijn er
verschillende cyclussen aanwezig. De rode
uitroepingstekens houden verband met het
volgende principe
9. Afhankelijk van stabiele packages
Nog even herinneren dat dit principe pleit voor een (beperkt) aantal stabiele klassen.
De stabiliteit van een systeem kan eenvoudig berekend worden. Stel
=Co Het aantal klassen buiten het package die afhangen van klassen in het package
=Ci Het aantal klassen buiten het package waar klassen binnen het package van gebruik
maken
CoCi
CiI
+= = Instabiliteit. Instabiliteit heeft een waarde die ligt in het interval [ ]1,0
Figuur III-42 Afhankelijkheden tussen de belangrijkste packages van ImageJ
65
Aan de hand van deze metriek kunnen we dit principe als volgt herformuleren: “Packages
moeten afhankelijk zijn van packages met een instabiliteit die lager is dan de eigen
instabiliteit.”
Aan de hand van de broncode werd per package nagegaan hoeveel klassen er buiten het
package afhangen van klassen binnen het package. Deze aantallen ziet u in Tabel III-4.
Nog door middel van de broncode werd per package geteld van hoeveel klassen buiten het
package, klassen van binnen het package afhangen. De resultaten hiervan ziet u in Tabel III-5.
In Tabel III-6 tenslotte ziet u de, op basis van bovenstaande tabellen, berekende instabiliteit.
Op Figuur III-42 wijzen de rode uitroepingstekens op een afhankelijkheid waar er gezondigd
wordt tegen deze regel.
Tabel III-4 Het aantal klassen buiten een package die afhangen van klassen binnen het package
ij ij.gui ij.io ij.macro ij.measure ij.process ij.text Ci
ij 15 4 1 1 9 2 32
ij.gui 4 1 1 3 7 1 17
ij.io 3 7 0 1 6 2 19
ij.macro 2 13 2 2 4 2 25
ij.measure 1 1 0 0 0 2 4
ij.process 2 2 0 0 1 0 5
ij.text 1 0 2 0 1 0 4
Tabel III-5 Het aantal klassen buiten een package waar klassen van het package gebruik van maken
ij ij.gui ij.io ij.macro ij.measure ij.process ij.text Co
ij 15 3 3 1 5 2 29
ij.gui 6 4 1 1 1 0 13
ij.io 4 0 0 0 0 0 2 6
ij.macro 2 1 0 0 0 0 3
ij.measure 1 8 2 0 4 1 16
ij.process 6 13 2 1 0 0 22
ij.text 2 2 1 1 1 0 7
66
Co Ci I
ij 29 32 0,52
ij.gui 13 17 0,56
ij.io 6 19 0,76
ij.macro 3 25 0,89
ij.measure 16 4 0,2
ij.process 22 5 0,18
ij.text 7 4 0,36
Tabel III-6 Instabiliteit van de verschillende packages van ImageJ
10. Stabiele abstracte packages
Volgens dit principe bestaat een goed OO-ontwerp uit stabiele, makkelijk uitbreidbare
packages en uit instabiele, makkelijk veranderbare packages.
De abstractheid van een package kan ook eenvoudig berekend worden. Stel
=Na Aantal abstracte klassen in het package
=Nc Aantal klassen in het package
==Nc
NaA Abstractheid. Abstractheid heeft een waarde die ligt in het interval [ ]1,0
In Tabel III-7 kan u per package aflezen hoeveel abstracte klassen er binnen dit package
gedefinieerd zijn en uit hoeveel klassen dit package bestaat. Daaruit wordt in de meest rechtse
kolom per package de abstractheid berekend
Na Nc A
ij 1 15 0,06
ij.gui 0 29 0
ij.io 2 25 0,08
ij.macro 0 19 0
ij.measure 1 6 0,16
ij.process 0 2 0
ij.text 0 3 0
Tabel III-7 Abstractheid van de verschillende packages van ImageJ
67
Deze regel kan vertaald worden in termen van I en A. I moet stijgen als A daalt, of nog,
packages met veel concrete klassen zouden instabiel moeten zijn, terwijl abstracte packages
stabiel moeten zijn. In FiguurIII-43 werden de ImageJ packages uitgezet tegenover I en A.
In de rechterbovenhoek van de nevenstaande grafiek worden
packages gevonden die erg abstract zijn, maar waar geen klassen van
afhangen: dit zijn dus nutteloze packages. In de linkerbenedenhoek
daarentegen, liggen de concrete packages met heel veel inkomende
afhankelijkheden. Aangezien het hier om concrete elementen gaat,
zullen ze nauwelijks kunnen uitgebreid worden. Omdat ze bovendien
ook heel veel inkomende afhankelijkheden hebben, zal het bijzonder
moeilijk zijn om de elementen te veranderen.
Idealiter liggen packages op de rechte die de punten (0,1) en (1,0) verbindt. Indien een package
zich daar bevindt wil dit zeggen dat het package voldoende abstract is in verhouding tot het
aantal inkomende afhankelijkheden en voldoende concreet is in verhouding tot het aantal
uitgaande afhankelijkheden.
We willen nog afsluiten met een laatste metriek, met name een metriek die ons leert hoe ver
packages verwijderd zijn van het ideale geval. Stel
2
1−+=
IAD = Afstand. Afstand heeft een waarde die ligt in het interval [ ]707.0,0 .
1−+=′ IAD = Genormaliseerde Afstand. Deze metriek is meer conventioneel omdat hij een
bereik heeft tussen [ ]1,0 .
A I D′
ij 0,06 0,52 0,42
ij.gui 0 0,56 0,44
ij.io 0,08 0,76 0,16
ij.macro 0 0,89 0,11
ij.measure 0,16 0,2 0,64
ij.process 0 0,18 0,82
ij.text 0 0,36 0,64
Tabel III-8 De genormaliseerde afstand van de packages van ImageJ tot het ideale geval
Figuur III-43 Grafiek Instabiliteit - Abstractheid
68
III. 4. 4. Suggestie Na een heleboel pagina’s onafgebroken te hebben ingebeukt op
de implementatie van ImageJ, wordt in deze paragraaf een
bescheiden alternatief voorgesteld. In Figuur III-44 ziet u
hiervan een grafische voorstelling. De structuur is geeneens zo
moeilijk. De belangrijkste bedoeling is om komaf te maken
met het quasi onveranderlijke kluwen van klassen dat ImageJ
nu is en interfaces te voorzien waardoor de structuur ook
makkelijk uitbreidbaar wordt.
Het hoogste niveau package noemen we Process en bezit onder meer een klasse Processor. Dit
zou een bij voorkeur volledig generische structuur moeten zijn die de pixels van de foto
opslaat. Hiervan kunnen dan eventueel nieuwe interfaces of abstracte klassen afgeleid worden.
Daarnaast is er ook een package GUI voorzien. Dit package bevat interfaces en klassen om de
foto naar buiten toe voor te stellen. In dit package vinden we bijvoorbeeld de interface
ImagePanel en eventueel verschillende klassen die deze interface op uiteenlopende wijze
implementeren. Ook zou het package over een klasse ImageFrame kunnen beschikken, dit is
een klasse die ImagePanels op een Frame plaatst.
Tenslotte mag een package IO niet ontbreken. Dit package bevat interfaces en klassen om
beelden in te lezen en op te slaan.
III. 4. 5. Besluit Het heeft er alle schijn van dat de basisidee achter ImageJ de OO-principes van dichtbij
benaderde. Zo is de klasse ImageProcessor een bijna volledig – op één ongelukkig detail na –
op zichzelf staande abstracte klasse, dus feitelijk zoals het hoort bij de implementatie van
hoog-niveau functionaliteit. Wat er daarna precies gebeurd is, is niet duidelijk. Sommige
implementatiebeslissingen zijn werkelijk onbegrijpelijk. Waarom werden ImageCanvas en
ImageWindow bijna onlosmakelijk met elkaar verbonden? Waarom werd het reuzenobject
ImagePlus in het leven geroepen?
Van abstractie is doorheen de volledige implementatie nauwelijks sprake. De klassen en
bijgevolg ook de packages zijn ongezond nauw met elkaar verweven.
Het resultaat van dit alles is een weliswaar zeer stabiel, maar erg moeilijk uitbreidbaar en
nauwelijks veranderbaar systeem.
Figuur III-44 Hoe ImageJ er misschien beter had kunnen uitzien
69
IV. Besluit
Op het einde van deze vaak moeilijke, en daarom dikwijls leerrijke tocht, is het tijd om de
balans voor ImageJ op te maken. En het kan niet anders of een gevoel van teleurstelling
besluipt mij. De hoge verwachtingen van in het begin ten aanzien van ImageJ werden
gedurende de tocht ingeruild voor een minder fraaie werkelijkheid. Naarmate er dieper werd
gegraven in het systeem, vielen de maskers één voor één af. Daar waar de webpagina een
gouden kalf had beloofd, bracht de aanblik en het gebruik van ImageJ, met z’n niet eens zo
grote onvolkomenheden, ons weer met de voeten op de grond. De inspectie van de broncode
tenslotte vermorzelde ineens alle resterende illusies.
Alles samen schuilt er een belangrijke ambiguïteit in ImageJ. Er is als het ware geprobeerd om
een volledig open systeem te creëren dat vlot aanpasbaar is aan ieders wensen door middel van
macro’s en plugin’s, terwijl intern, door de strikte onderlinge verwantschap tussen de klassen,
er nauwelijks manoeuvreerruimte is en de kleinste wijziging een hopeloze opdracht wordt.
Desondanks, is het oorspronkelijke doel, het schrijven van een applet die een radiologie
omgeving simuleert, gerealiseerd.
70
Appendix A
<html> <head> <title>Medical Images</title> </head> <body> <?php $dir3 = "./VirtualImages"; $dir4 = "./RadiologyImages"; makeFiles($dir3,$dir4,$dir3."/"."dirsAndFiles.txt"); function makeFiles ($dir1, $dir2) { $mappen = array(); $files = array(); $stacks = array(); $handle=opendir($dir2); while (($file = readdir($handle)) != null) { if($file != '.' && $file != '..'){ if(is_file ($dir2."/".$file)){ $files[] = $file; } else{ $lengte = strlen($file); if ($lengte >= 5) { $substring = substr($file,0,5); $upcasestring = strtoupper($substring); $basis = "STACK"; $result = strcmp($basis,$upcasestring); if ($result == 0) { $substring2 = substr($file,0,5); $stacks[] = $file;} else {$mappen[] = $file;} } else { $mappen[] = $file; } } } } closedir($handle); sort($mappen); sort($files); sort($stacks); if (file_exists($dir1) == false)
71
{mkdir($dir1,0777); chmod($dir1,0777); $handle2 = opendir($dir1);} else {$handle2 = opendir($dir1);} /* $MY_KEY = 30; $sem_id = sem_get($MY_KEY); sem_acquire($sem_id); */ $fp = fopen($dir1."/"."dirsAndFiles.txt","w"); for($i=0;$i<count($files);$i++){ fwrite($fp, $files[$i]); fwrite($fp, "\n"); } fwrite($fp,"LISTINGOFPRESENTSTACKS"); fwrite($fp,"\n"); for($i=0;$i<count($stacks);$i++){ fwrite($fp, $stacks[$i]); fwrite($fp, "\n"); } fwrite($fp, "LISTINGOFPRESENTDIRECTORIES"); fwrite($fp,"\n"); for($i=0;$i<count($mappen);$i++){ fwrite($fp, $mappen[$i]); fwrite($fp, "\n"); } fclose($fp); /* sem_release($sem_id); */ for ($i=0;$i < count($stacks);$i++){ makeFiles($dir1."/".$stacks[$i],$dir2."/".$stacks[$i]); } for($i=0;$i<count($mappen);$i++){ makeFiles($dir1."/".$mappen[$i],$dir2."/".$mappen[$i]); } closedir($handle2); } ?> <APPLET CODE = "WebApplet.class" archive="ij.jar" WIDTH = 750, HEIGHT =250> </APPLET> </body> </html>
72
Appendix B
1. Open de bestanden Tulpen, Poes en Peer vanuit de map Mijn documenten
Normaal gezien verwacht je niet dat in het dialoogvenster Open ook nog andere bestanden –
andere dan foto’s – zoals Worddocumenten of Excel werkmappen kunnen geselecteerd
worden.
Het is niet mogelijk om de 3 bestanden tegelijk te selecteren met behulp van Shift
2. Doe het volgende voor het bestand Tulpen
Dupliceer het bestand
Maak een rechthoekige selectie binnen deze figuur en kopieer deze selectie naar een
volledig nieuwe foto
Sla de nieuwe foto op in de map Mijn documenten onder de naam Tulpen Selectie
Het blijkt dat de dialoogvenstertjes niet sluiten door op het kruisje rechts bovenaan te klikken
De opgave is niet eenvoudig. De foto dupliceren is niet echt een probleem, maar om de selectie
te kopiëren naar de nieuwe foto is een echte kalvarietocht, omdat de afmetingen niet kloppen.
Na wat zoeken blijkt dat de afmetingen van de selectie onderaan op het hoofdvenster te zien
zijn en dat je op basis daarvan eerst een nieuwe afbeelding moet maken. Nieuw probleem!
Vanaf het ogenblik dat je de muis beweegt, verdwijnen de afmetingen, dus moet je die eerst
opschrijven. Je moet ook nog eens weten welk type bestand het bestand is waarvan je vertrekt,
want dat wordt gevraagd in het dialoogvenster om een nieuw bestand maken
3. Laat een histogram zien van de foto Tulpen
Histogram staat goed onder Analyze
4. Zoom in op de afbeelding Peer. Probeer daarna weer uit te zoomen
Inzoomen is geen enkel probleem, maar hoe moet je in godsnaam uitzoomen? Undo werkt
niet!!
5. Vergroot de afbeelding Tulpen met 10 px rondom
Size en Image Size zitten onder het menu Image – Adjust. Het zou beter zijn moesten ze
onmiddellijk in het menu Image zouden zijn opgenomen, en niet in het submenu Adjust.
Bovendien begint dit submenu met Brightness/Contrast en op die manier denk je zeker dat het
73
over een submenu gaat waarmee je helderheid en contrast, niveaus, kleurbalans en zo meer kan
veranderen. Ook de opmerking dat Undo onmogelijk is daarna, is een beetje vreemd.
6. Verklein de afbeelding Tulpen met 10 px rondom
Er stond daarstraks al dat je geen Undo kon doen, gewoon weer de size verkleinen en de klus is
geklaard. Ze hadden dát beter vermeld, dat je moest aftrekken, in plaats van te zetten dat Undo
niet mogelijk is.
7. In ImageJ is een functie aanwezig waarmee u de afbeeldingspartikels kan analyseren.
Probeer de functie te vinden. Voer de functie uit gebruik makend van de afbeelding
Peer. Normaal krijgt u nu een foutboodschap. Probeer het nodige te doen om alsnog
verder te kunnen.
De functie Analyze Particles staat daar wel goed. Ik weet wel niet wat we in dat dialoogvenster
moeten invullen.
OK, klopt, d’r is inderdaad een fout. Het is wel niet duidelijk wat er nu moet gebeuren, ’t moet
een grijs bestand worden, maar ik heb niet echt een idee hoe dat moet gebeuren. De afbeelding
moet omgezet worden naar 8 – 16 of 32 pixels. Maar hoe. Het was beter geweest om dit ook te
vermelden in de foutmelding. Ik zou gedacht hebben dat het commando om de conversie uit te
voeren misschien te vinden was onder Process, want Process bevat de opdrachten die de foto
veranderen, maar niets te vinden. Misschien onder Image? Color misschien? Neen ook niet.
Edit – Options – Conversions nog eens uitproberen maar dit doet niets en hetgeen ze vragen is
duidelijk voer voor specialisten want er staat geen uitleg bij hetgeen je daar allemaal kan
kiezen. Dat is raar, als je in Office werkt, dan krijg je meestal een venster met daarin vragen en
opties als antwoorden op die vragen, maar hier? Hier zijn het opties zonder vragen.
Laat ik Image – Type van RGB eens proberen om over te gaan naar een ander type. Amai, ’t
enige wat je krijgt is tabel van de mogelijke conversies. ’t Is zo’n lange tabel dat ik geeneens
goesting heb om te gaan zoeken of RGB ertussen zit. Nog eens proberen en nu veranderen naar
8-bit. Gelukt, nog eens die functie Analyze Particles uitvoeren. Wéér een foutmelding. Daar
versta ik niets van.
8. Open de afbeelding met URL http://www.geocities.com/sabdevreese/Excel/Auto.jpg
’t Moet zeker via Open en dan via Import, da’s niet zo moeilijk
74
9. Draai de afbeelding Auto 90° naar rechts. Zoek de functie Treshold en pas deze
functie toe op de afbeelding
Draaien is niet moeilijk, dat staat goed onder Image. – Na lang zoeken werd de functie
Threshold gevonden – Geen idee wat de bedoeling van deze functie kan zijn. De schuivers
maken een raar lawaai, ‘k denk dat ik iets verkeerd doe, maar d’r gebeurt niets.
10. Pas op de afbeelding Peer eerst de functie Smooth toe en daarna de functie Find
edges. Probeer tenslotte de oorspronkelijke foto terug te krijgen
De functies Smooth en Find Edges zijn gemakkelijk te vinden.
De eerste keer lukt het wanneer je undo probeert, maar daarna probeer je nog een keer, maar je
kan niet zeker zeggen of er nu iets veranderd is of niet. Kan je geen redo doen om te zien
hoeveel stappen dat je al bent teruggekeerd?
11. De functie Measure wordt gebruikt om berekeningen, zoals de oppervlakte, te maken.
Maak gebruik van deze functie om een oppervlakte te berekenen en sla de resultaten
op in een tekstbestand met de naam Oppervlakte in de map Mijn documenten
Valt in vergelijking met de rest nog mee. Measure staat daar op de goede plaats.
’t Is weer raar dat er vanonder geen extensie staat.
12. Probeer de functie Plot Profile te vinden en toe te passen
Niet moeilijk, dat staat onder Analyze. Ach je moet eerst een selectie maken.
Hier werkt het kruisje rechtsboven blijkbaar wel.
13. Typ een tekst in de foto Tulpen en sla de wijzigingen op in Tulpen
Da’s wel raar dat je moet klikken op Ctrl + D. Ik zou meer verwachten dat je gewoon buiten
het tekstvak moet klikken. Kan je het kleur of de grootte van de tekst aanpassen?
Dat opslaan is weer raar, da’s anders normaal.
14. Zoek naar de functie die Brightness/Contrast aanpast
Niet moeilijk
75
15. Duid 2 punten aan in een willekeurige foto en probeer de afstand te berekenen
Je kan wel een lijn tekenen en dan de lengte aflezen. Je kan ook 2 punten zetten, dan moet je er
wel aan denken dat je Shift moet gebruiken voor het tweede punt, dan kies je voor
Measurements, maar dat geeft gewoon de x en y coordinaten en niet echt de afstand. Geen
functie te vinden die de echte afstand geeft.
76
Bibliografie [1] http://courses.iicm.edu/hci/hci.pdf geraadpleegd op 07-07-2006 [2] http://www.objectmentor.com/publications/Principles%20and%20Patterns.PDF#search=%22principles%20package%20architecture%22 geraadpleegd op 20-07-2006
77