Technical specification
PicSearch -- Interactive Picture Searcher
http://
Last modified .
Contents
Summary
1. Johdanto
2. Järjestelmän yleiskuvaus
3. Arkkitehtuurin kuvaus
4. Rajapinnat
5. Alijärjestelmäkuvaukset
6. Modulien toteutuksen kuvaus
PicSearch is an application, which can be used to search for
images based on their content. The system provides a graphical
user interface (GUI) and uses a simple database implementation for
storing data.
PicSearch is implemented using C++ and Tcl/Tk (for the GUI). The
system should be very portable to any platform having these tools
and threads (either part of the operating system or as a separate
library). The system is divided into logical subsystems:
- A common C++ class library PicLib provides numerous generally
useful classes and for example a standard way of handling errors.
For source code documentation,
click here.
- GUI-part PicGUI is made of
Tcl/Tk-scripts (which describe the outlook of the user interface
and its basic functionality) and C++ programming interface for
the main program.
For source code documentation,
click here.
- Main program PicCore functions as the engine of the system. PicCore
has multiple threads. The main thread is usually executing inside
the Tcl-interpreter and enters into C++ code to perform different
tasks. For a long task such as a query, a separate thread is
launched.
For source code documentation,
click here.
- Database part PicDb takes care of storing data into database.
PicDb provides a programming interface for the main program
to read and write data. PicDb also includes a simple database
implementation for purposes of this project.
For source code documentation,
click here.
- Algorithm part PicAlg includes all the algorithm implementations
and similar basic blocks of the system. PicAlg is made up of a
number of C++ classes with no policy-making functionality, i.e.
the actual "program" is in PicCore.
For source code documentation,
click here.
Practically all the operating system dependent parts of the system are
isolated in PicLib (file operations, threads, semaphoras, etc.).
Other parts are as far as possible independent of the underlying
operating system. The Tcl/Tk-part of PicGUI should also make no
presumptions about the operating system.
PicSearch on sovellus, jolla voidaan hakea kuvia niiden sisällön
perusteella. Kuvien etsiminen tapahtuu valitsemalla hakualgoritmi ja
antamalla ohjelmalle esimerkkikuva (piirtämällä / tiedostosta lukemalla)
joka pyrkii esittämään haettua kuvaa. Esimerkkikuvasta lasketaan signature
käyttäjän valitsemalla algoritmilla ja tietokannasta etsitään kuvat, jotka
vastaavat mahdollisimman hyvin tätä signaturea.
Signature tarkoittaa kuvasta laskettua kompaktia esitystä, johon
algoritmi pyrkii tiivistämään kuvan olennaiset ominaisuudet.
Järjestelmän tuntemat kuvat ovat talletettuna tietokantaan ja
niistä on laskettu valmiiksi signaturet kaikilla järjestelmän
tuntemilla algoritmeilla.
- Tcl/Tk on Sun Microsystems:n kehittämä vapaassa levityksessä
oleva tulkattava ohjelmointikieli. Tcl on varsinainen tulkattava
scriptikieli ja Tk tämän laajennusosa graafisten käyttöliittymien
toteuttamiseen.
- Alijärjestelmällä tarkoitetaan loogisesti oman
kokonaisuutensa muodostavaa järjestelmän osaa. Alijärjestelmät
eivät PicSearch:n tapauksessa toimi omina prosesseinaan, vaan
ovat kaikki osina samassa ohjelmassa.
- Säie eli thread tarkoittaa saman ohjelman (prosessin)
sisällä olevaa itsenäistä "suorituspolkua". Säikeitä voi olla
käynnissä useita ja niillä kaikilla on oma pino (stack). Ohjelman
globaali data on yhteistä kaikille säikeille.
- Semaphoralla tarkoitetaan tässä dokumentissa säikeiden synkronointiin
käytettävää objektia. Semaphora voi kuulua kullakin ajan hetkellä
korkeintaan yhdelle säikeelle. Varattuna olevan semaphoran
varausyritys keskeyttää varausta yrittäneen säikeen suorituksen. Säie
voi jatkaa suoritustaan, kun semaphoran omistaja vapauttaa varauksensa
ja semaphora myönnetään odottamassa oleelle säikeelle.
- Kuvalla tarkoitetaan tässä dokumentissa oliota, joka
käsittää kuvadatan ja joukon parametreja.
Kuva voi olla myös tyhjä, jolloin kuvadataa ei ole.
- Kuvan parametreilla tarkoitetaan erilaisia kuvaan liittyviä
tietoja (esim. nimi, korkeus, leveys), ei kuitenkaan signatureja
tai segmenttejä.
- Tietokanta-id:llä tarkoitetaan yksiselitteistä tunnistenumeroa,
jolla tietokannassa olevat kuvat identifioidaan.
- Esimerkkikuva on kuva, jota käytetään vertailukuvana
tietokantahauissa ratkaisemaan haettavien kuvien paremmuusjärjestyksen.
- Signature on kuvasta laskettu kompakti esitys,
joka pyrkii tiiviisti kuvaamaan kuvan tai osakuvan sisältöä.
- "Hakualgoritmi"-sanaa käytetään tässä dokumentissa
tarkoittamaan sekä kuvasta signaturen laskevaa algoritmia että
ko. algoritmin laskemien signaturejen vertailumetodia, jolla
määritellään, kuinka hyvin kaksi signaturea vastaa toisiaan.
- Kuvankäsittelyalgoritmi on algoritmi, joka muokkaa
kuvan sisältöä jollakin tavalla.
- Segmentointialgoritmi on algoritmi, joka laskee kuvasta
segmentit, ts. jakaa sen loogisiin osiin.
Tässä dokumentissa on kuvattu järjestelmän tekninen toteutustapa.
Järjestelmän yleiskuvaus
-luvussa kuvataan järjestelmän toimintaympäristö ja yleiset
reunaehdot.
Arkkitehtuurin kuvaus -luvussa kuvataan
järjestelmän perusarkkitehtuuri sekä tietokanta.
Rajapinnat -luvussa esitellään alijärjestelmien
ydinohjelmalle tarjoamat rajapinnat.
Alijärjestelmäkuvaukset -luvussa kuvataan
yksityiskohtaisemmin kukin alijärjestelmä tekniseltä pohjalta.
Modulien toteutuksen kuvaus -luvussa
hahmotellaan kunkin järjestelmän osan toteutustapa (esim. millaisia
C++ -luokkia).
PicSearch on sovellus, jolla voidaan hakea kuvia niiden sisällön perusteella.
Järjestelmää käytetään graafisen käyttöliittymän kautta ja se käyttää
tietojensa tallennukseen yksinkertaista tietokantaa. Tarkempi kuvaus
löytyy Toiminnallinen määrittely -dokumentista.
PicSearch toteutetaan käyttäen C++ -ohjelmointikieltä sekä
käyttöliittymän tekoon Tcl/Tk:ta. Tämä mahdollistaa
siirrettävyyden ympäristöihin joissa nämä välineet (sekä säikeet
ja semaphorat) ovat käytettävissä.
Järjestelmä toimitetaan ja testataan LINUX:ssa, mutta ei-formaalisti
myös 32-bittisessä Windows:ssa ja UNIX:ssa TKK:n Alpha-koneissa (alpha.hut.fi).
Järjestelmä on jaettu loogisiin alijärjestelmiin, joista kunkin
toteutuksesta vastaa yksi vastuuhenkilö. Alijärjestelmät liittyvät
toisiinsa rajapintojen kautta. Järjestelmä liittyy ympäristöönsä
käyttöliittymän, tiedostojärjestelmän ja tietokannan kautta. Toimitettavassa
järjestelmässä fyysinenkin tietokanta on toteutettu osaksi järjestelmää.
3.1 Ratkaisuperiaatteet
Järjestelmä on jaettu modulaarisiin alijärjestelmiin, joista kukin
kätkee tietyn osa-alueen toteutuksen ja näin ollen rajaa jatkokehityksessä
tarvittavat muutokset pienelle alueelle. Järjestelmä koodataan
oliotekniikkaa käyttäen, minkä tärkeys korostuu erityisesti uusien
algoritmien lisäämisen helppoutena (johda kanta-algoritmiluokasta uusi
luokka, ohjelmoi algoritmi sopivaan C++:n virtuaaliseen funktioon,
rekisteröi algoritmi, käännä ohjelmisto).
3.2 Ohjelmistoarkkitehtuuri
Alijärjestelmät
Järjestelmä koostuu neljästä suhteellisen erillisestä
alijärjestelmästä:
- Ydinohjelma (PicCore) kontrolloi järjestelmän toimintaa,
suorittaa tietokantahaut yms. PicCore koostuu useasta
säikeestä ja se liittyy muihin alijärjestelmiin
näille määriteltyjen rajapintojen kautta.
- Algoritmiosuus (PicAlgorithm) liittyy läheisesti
ydinohjelmaan eikä se pyöri omana säikeenään.
Alijärjestelmä muodostuu järjestelmään ohjelmoiduista
algoritmeista, joita ydinohjelma kutsuu rajapinnan kautta.
PicCore käyttää algoritmeja mekaanisesti ottamatta kantaa
niiden toimintaan tai tietosisältöön.
- Käyttöliittymäosuus (PicGUI) on ydinohjelmasta selkeästi
erillään oleva kokonaisuus, joka huolehtii tiedon välityksestä
käyttäjän ja ydinohjelman välillä. Tämä osuus on
toteutettu valtaosin Tcl/Tk:lla, mutta sisältää myös
C++ -rajapinnan, jonka välityksellä ydinohjelma toimii
yhdessä Tcl-kielisen osuuden kanssa. Myöskään PicGUI ei
pyöri omana prosessinaan / säikeenään vaan suoritus siirtyy
Tcl:n puolelta aina tarvittaessa ydinohjelman puolelle.
- Tietokantaosuus (PicDb) käsittää kaikki toiminnot, jotka
tarvitaan tietojen pysyvyyden ylläpitoon. PicDb huolehtii
kuvien ym. tietojen fyysisestä tallennuksesta ja tarjoaa
ydinohjelmalle rajapinnan jonka kautta tietoja voi
tallettaa / lukea. Varsinainen "hakukone" kuuluu
ydinohjelmaan, jossa se pyörii omana säikeenään.
Järjestelmän toteutuksessa käytetään säikeitä.
Säikeitä voi olla yhtä aikaa käynnissä 1-4. Suurin osa
toiminnoista toteutetaan pääsäikeessä (MainThread). Pääsäie
voi käynnistää hakusäikeen (QueryThread) suorittamaan
hakua tietokannasta. Lisäksi voidaan käynnistää kuvien
massasyöttösäie (MassInsertThread), joka lisää kuvia
tiedostoista tietokantaan muun toiminnan kanssa
rinnakkaisesti. Järjestelmän käynnistyessä voidaan myös
joutua käynnistämään tietokannan päivityssäie (DbUpdateThread),
jos järjestelmään on lisätty uusia algoritmeja (tietokannan
kuville on tällöin laskettava signaturet näillä algoritmeilla).
3.3 Tietokanta-arkkitehtuuri
Järjestelmän tietokanta-arkkitehtuuri pohjautuu relaatiotietokantamalliin.
Käytettävä tietomalli on esitetty allaolevassa E-R mallissa.
Tietokantaan tallennettava tieto on jaettu relaatiotauluihin E-R mallin
perusteella. Entiteeteistä, eli E-R mallin laatikoista, tehtiin omat taulunsa
ja kaikki relaatiot, eli E-R mallin salmiakkikuviot, sisällytettiin näihin
tauluihin paitsi moni-moni relaatiot, joista tehtiin omat taulunsa
(Segmentation, Signature ja SegmSignature).
Relaatiotaulut ja niiden sisällöt on esitetty tarkemmin seuraavassa taulukossa.
Kunkin taulun
ikonilla merkityt kentät
ovat taulun avainkenttiä, jotka yksikäsitteisesti tunnistavat taulun
jokaisen rivin.
ikonilla merkityt
kentät taas kuvaavat avainkentistä funktionaalisesti riippuvia
kenttiä.
Taulukossa on esitetty jokaisen kentän tietotyyppi, nimi ja lopuksi lyhyt
selitys. Tietotyypeistä INT tarkoittaa vähintään 32 bitin tarkkuudella
talletettua kokonaislukua, CHAR mielivaltaisen pituista
merkkijonoa ja BIN mielivaltaisen kokoista, binäärityyppistä tietoa
sisältävää, kenttää.
ImageInfo |
|
Kuvan yleiset tiedot |
INT |
id |
Kuvan ID-numero |
CHAR |
name |
Kuvan nimi / lyhyt kuvaus |
CHAR |
par1 |
Vapaavalintainen merkkijono 1 |
CHAR |
par2 |
Vapaavalintainen merkkijono 2 |
ImageData |
|
Normaalikokoisen kuvan data |
INT |
imageId |
Kuva, jolle kuvadata kuuluu |
INT |
width |
Kuvan leveys |
INT |
height |
Kuvan korkeus |
INT |
formatId |
Kuvaformaatti |
CHAR |
filename |
Tiedoston nimi, jos kuvadata tallennettu tiedostoon |
BIN |
data |
Kuvadata (jos tiedoston nimeä ei annettu) |
ScaledImageData |
|
Skaalatun kuvan data |
INT |
imageId |
Kuva, jolle kuvadata kuuluu |
INT |
width |
Kuvan leveys |
INT |
height |
Kuvan korkeus |
INT |
formatId |
Kuvaformaatti |
BIN |
data |
Kuvadata |
ImageFormat |
|
Kuvan tallennusformaatti |
INT |
id |
Kuvaformaatin ID-numero |
CHAR |
name |
Formaatin nimi |
SearchAlgorithm |
| Kuvahakualgoritmi |
INT
| id |
Hakualgoritmin ID-numero |
CHAR |
name |
Algoritmin nimi |
Signature |
| Kuvalle laskettu signature |
INT |
imageId |
Kuva, josta signature on laskettu |
INT |
algorithmId |
Algoritmi, jolla signature on laskettu |
BIN |
signature |
Signature data |
SegmAlgorithm |
| Kuvan segmentoinnin suorittava algoritmi |
INT |
id |
Segmentointialgoritmin ID-numero |
CHAR |
name |
Algoritmin nimi |
Segmentation |
| Kuvalle suoritettu segmentointi |
INT |
imageId |
Kuva, jolle segmentointi on suoritettu |
INT |
algorithmId |
Käytetty segmentointialgoritmi |
INT |
segments |
Segmenttien lukumäärä |
Segment |
| Kuvan segmentti |
INT |
imageId |
Kuva, josta segmentti on laskettu |
INT |
algorithmId |
Käytetty segmentointialgoritmi |
INT |
segmentNbr |
Segmentin numero (1...segmenttien lkm.) |
BIN |
data |
Segmenttidata |
SegmSignature |
| Kuvasegmentistä laskettu signature |
INT |
imageId |
Kuva, josta segmentti on irroitettu |
INT |
segmAlgId |
Käytetty segmentointialgoritmi |
INT |
segmentNbr |
Segmentin numero (1...segmenttien lkm.) |
INT |
searchAlgId |
Hakualgoritmi, jolla signature on laskettu |
BIN |
signature |
Signature data |
Parameter |
| Parametrimääritys |
CHAR |
name |
Parametrin nimi |
CHAR |
value |
Parametrin arvo |
Järjestelmän relaatiotauluista muodostuvaa tietokantaa käytetään
PicDb-API tietokantarajapinnan kautta.
4.1 Käyttöliittymärajapinta
PicGUI-API
PicGUI-alijärjestelmä koostuu käytännössä
kahdesta osasta, Tcl/Tk:lla ohjelmoidusta ulospäin näkyvästä
käyttöliittymästä ja C++:lla ohjelmoidusta API:sta
käyttöliittymän ja ydinohjelman välissä. Vaikka
Tcl/Tk onkin alunperin luotu C:llä, se on kuitenkin täysin oma
kielensä (oikeastaan kaksi kieltä, "ohjelmointikieli"
Tcl ja käyttöliittymänrakennuskieli Tk) ja tämän
takia käyttöliittymämoduli on pyritty pitämään
mahdollisimman paljon omana itsenäisenä palasenaan, joka vain
tarpeen vaatiessa kommunikoi muun järjestelmän kanssa PicGUI:n
C++ -osan kautta.
Yksi ohjelmiston toiminnan kannalta tärkeimmistä teknisistä
määrityksistä on em. Tcl/Tk -käyttöliittymän
ja C++:lla ohjelmoitujen järjestelmän muiden osien välinen
kommunikointi, koska lähes kaikki järjestelmän toiminnan
kannalta kriittinen tieto kulkee tämän yhteyden kautta. Toteutus
on seuraavanlainen:
- Tcl/Tk on helposti laajennettava kieli, eli C/C++:lla voidaan määritellä
uusia Tcl-funktioita. Tiedonsiirtoa suunnassa käyttöliittymä
=> muu ohjelma varten on siten määritelty Tcl-funktio "transmit",
joka saa argumenteikseen kulloinkin siirrettävän tiedon "komennon"/määrityksen
(esim. startQuery) ja siihen liittyvät dataparametrit (esim. kyseltävä
kuva ja hakualgoritmin parametrit). Nämä argumentit näkyvät
sitten C++:n puolella "transmit" -funktion määritysfunktiossa
argc,argv -muodossa. Määritysfunktio käsittelee argumentit
ja niiden perusteella edelleen aktivoi systeemin muita osia.
- Tiedonsiirto suunnassa C++ => käyttöliittymä toimii
siten, että Tcl/Tk:n puolella on jatkuvasti käynnissä odotusfunktio,
joka aktivoituu saadessaan jonkun uuden komennon käsiteltäväkseen
(odotusmuuttuja muuttuu). Komennot ja niiden parametrit kirjoitetaan C++:n
puolelta suoraan Tcl:n globaaleihin muuttujiin.
C++ osa koostuu siis edellisen nojalla "transmit" Tcl-komennon
toteutusfunktiosta (ja tämän apukomentojen toteutusfunktioista)
sekä muiden järjestelmän osien käytössä olevasta
joukosta funktioita, joiden avulla voidaan lähettää tietoa
käyttöliittymälle.
Järjestelmä käyttää tietokantaa
PicDb-API:n avulla. Rajapinta koostuu muutamasta luokasta, ja näiden
tarjoamista metodeista.
Tietokantarajapintaa käytetään luomalla instanssi PicDbConnection luokasta.
Tämän jälkeen luodaan yhteys kantaan kutsumalla connect
metodia. Käyttämällä luokan jäsenfunktioita voidaan suorittaa tietokantaan
haku, lisäys, päivitys, poisto tai koko tietokannan reorganisointi, eli
uudelleenjärjestäminen, jolloin tietokannan fyysinen tallennus optimoidaan
tilankäytön suhteen. Viimeisenä toimenpiteenä yhteys kantaan pitää aina
katkaista disconnect metodilla. Muita luokan metodeita ovat commit ja rollback,
joilla sitoudutaan suoritettuun transaktioon tai perutaan se.
Useimmat luokan jäsenfunktiot ottavat parametrikseen referenssin TableEntry
luokasta johdettuun luokkaan, joka samalla määrää relaatiotaulun, johon
toimenpide kohdistetaan. Nämä kutakin relaatiotaulua kohden johdetut
luokat sisältävät muuttujat, joihin voidaan tallettaa kyseisen taulun yhden
rivin tiedot. Näin luokkia käytetään esim. välittämään kantaan lisättävän
rivin tiedot, tai antamaan haussa käytettävät hakuarvot. Esim. id:llä haku
ImageInfo taulusta tapahtuu seuraavasti (taulun ainoalla avainkentällä haku
ei tietysti löydä kuin korkeintaan yhden rivin, muuten fetchNext metodilla
iteroitaisiin rivi riviltä loputkin saman id:n omaavat taulun rivit):
PicDbConnection connection;
ImageInfoEntry entry; // search from ImageInfo table
PicIntSet fields;
connection.connect();
fields.add(1); // "id" is the search field
entry.id = 123; // search for id 123
if (connection.query(entry, fields)) // Perform the query and get the
// first matching row.
{
do
{
...
} while (connection.fetchNext(entry)) // iterate...
}
connection.commit()
connection.disconnect();
PicDbConnection luokan muita tietokantaoperaatioita käytetään vastaavalla
periaattella.
Ydinohjelma käyttää järjestelmään ohjelmoituja algoritmeja
suoraan näiden C++ -luokkien metodeja kutsumalla. Tieto algoritmien
olemassaolosta on globaalina datana ohjelmaan käännettynä.
Ydinohjelma käyttää kullekin algoritmityypille (haku-, segmentointi-
ja kuvankäsittelyalgoritmit) näiden kantaluokkaa kaikissa
operaatioissaan. Uusien algoritmien käyttö edellyttää ainoastaan
uuden luokan johtamista kantaluokasta ja toiminnallisuuden
ohjelmoimista tarvittaviin metodeihin.
Hakualgoritmeille tarvittavia metodeja ovat:
- Signaturen laskeminen kuvasta
- Kahden signaturen vertailu
- Algoritmin parametrien asetus / luku
Segmentointialgoritmeille tarvittavia metodeja ovat:
- Segmenttien laskeminen kuvasta
- Algoritmin parametrien asetus / luku
Kuvankäsittelyalgoritmeille tarvittavia metodeja ovat:
- Kuvan käsittely
- Algoritmin parametrien asetus / luku
Lisäksi tarvitaan funktiot kuvien skaalaukseen sekä muuntoon
kuvaformaatin (JPEG, PPM ja SunRaster) ja raakakuvan välillä (RGB-dataa).
Yleiskuvaus
PicLib ei ole varsinainen alijärjestelmä, vaan järjestelmän
kaikkien osien yhteisessä käytössä oleva luokkakirjasto.
Modulijako
PicLib koostuu n. sadasta C++ -luokasta, joiden toteutus
on omissa tiedostoissaan ja jotka käännetään osaksi järjestelmää.
Muut järjestelmän osat käyttävät PicLib:n luokkia
sisällyttämällä koodiinsa sopivat tarjotuista header-tiedostoista.
PicLib käyttää omia toimintojaan melko paljon ristiin, joten
kirjaston koko on hieman suurempi kuin järjestelmän toteutus
vaatisi (kirjasto on suurelta osin vanhaa jo testattua koodia).
Attribuutit
Kirjaston toimintaa ei parametroida ulkoisesti mitenkään,
vaan kaikki parametrit ovat oletusarvoissaan.
Toiminnot
PicLib tarjoaa mm. seuraavat palvelut:
- turvalliset luokkakonversiot (typecast) luokkahierakian kantaluokan avulla
- dynaaminen merkkijonojen käsittely
- "kokoelmaluokat": kantaluokasta johdettujen luokkien objektikokoelmat,
ts. lista, taulukko, luvulla indeksoitu taulu, nimellä (merkkijonolla)
indeksoitu taulu
- standarditavan virheiden käsittelyyn ja esittämiseen (esim. lokiin
kirjoittaminen)
- "stream-luokat" tekstin lukuun, kirjoitukseen ja formatointiin, myös
tiedostosta
- käyttöjärjestelmän eristävät luokat: tiedostojen käsittely,
säikeet ja semaphorat
Poikkeustilanteiden käsittely
PicLib tarjoaa standarditavan virheiden ja poikkeustilanteiden käsittelyyn.
Jokainen C++ -luokka määrittelee joukon toimintaansa liittyviä
virhekoodeja ja näille sanallisen virheilmoitusviestin. Luokan
toteutuksessa virhetilanteen sattuessa "nostetaan" sopiva virhe päälle.
Virheen nostaminen aiheuttaa sen tallettumisen aktiiviseen ErrorContext-
luokan instanssiin. Näitä voi olla useita pinossa, jolloin päästään
eroon globaalin errno-muuttujan haitoista. Luokan palvelun kutsuja
voi valintansa mukaan käsitellä virheen tai antaa sen kulkeutua
ErrorContext-pinossa ylöspäin. Virheet
kirjoitetaan oletusarvoisesti lokiin. Tätä voidaan laajentaa siten,
että virheet tulevat myös esim. PicSearch:ssä pääikkunan info-ruutuun.
Jos virhettä nostettaessa se määritellään fataaliksi, lakkaa ohjelman
suoritus.
Testattavuus
Kirjasto on pitkälti jo valmista hyvin testattua koodia. PicSearch:n
tarpeita varten muutetut osat voidaan testata luokka kerrallaan
varmistamalla yksinkertaisilla "assert"-lauseilla kunkin funktion
toimivuus. Käyttöjärjestelmäkohtaiset osat on syytä testata erikseen
kussakin ympäristössä.
Yleiskuvaus
PicCore toimii järjestelmän ydinohjelmana. Se alustaa järjestelmän
käynnistyksen yhteydessä ja käynnistää Tcl-tulkin ja aktivoi siten
käyttöliittymän. Käyttäjän toiminnan mukaan suoritus siirtyy ohjelman
Tcl-osasta PicGUI:n rajapintafunktioiden kautta PicCoreen. Ydinohjelma
suorittaa tarvittavat toiminnot käyttäen varsinaiseen laskentaan yms.
algoritmi- ja tietokantaosien palveluja. Ajallisesti pitkien operaatioiden
suorittamiseen ydinohjelma käynnistää sopivia säikeitä ennen pääsäikeen
suorituksen paluuta Tcl-osaan.
HUOM. Koska Tcl/Tk-tulkki ei ole thread-safe, joudutaan muiden kuin
pääsäikeen tiedonsiirto GUI:n suuntaan synkronoimaan pakottamalla
pääsäikeen suoritus määrävälein C++:n puolelle, jolloin muut
säikeet voivat kutsua sopivia PicGUI:n funktiota.
Attribuutit
Ydinohjelma ylläpitää käytännöllisesti katsoen kaikkea globaalia
dataa. Tähän kuuluvat muistissa olevat kuvat, signaturet, ohjelman
tilatiedot jne. Usean säikeen kesken jaettu data synkronoidaan
aina semaphoria käyttäen. PicGUI pitää Tcl/Tk:n puolella omissa
muuttujissaan suurelta osin samoja tietoja kuin ydinohjelma.
Toiminnot
Ydinohjelma suorittaa valtaosan järjestelmän toiminnoista. Varsinainen
implementaatio on monissa tapauksissa PicAlg, PicDb ja PicLib -osissa
ja ydinohjelma vain käyttää näiden palveluja mekaanisesti ottamatta
kantaa tietosisältöön.
Säikeiden toiminnoista tarkemmin
3.2 Ohjelmistoarkkitehtuuri -luvun kohdassa Säikeet.
Testattavuus
Ydinohjelma voidaan testata yksittäisten toimintojen kautta. Kunkin
toiminnon oikein aktivoituminen ja järkevä käyttäytyminen
poikkeustilanteissa varmistavat tämän osan ydinohjelman toteutuksesta.
Erityisesti on testattava säikeiden välinen synkronointi. Tämän johdosta
kaikki ne toiminnot joiden toimintaan tai dataan säie voi vaikuttaa,
eri suorituksessa olevien säikeiden kombinaatioilla.
Pääsäikeen on kyettävä tarvittaessa keskeyttämään apusäikeet eikä
yhteinen data saa koskaan joutua epämääräiseen tilaan.
Kommunikointi
Ydinohjelma käyttää muiden alijärjestelmien palveluja näiden tarjoamien
rajapintojen kautta. Apusäikeet ja pääsäie kommunikoivat tarvittaessa
keskenään jaettujen muuttujien kautta.
Ohjeita toteutusta varten
Ydinohjelman tulee olla mahdollisimman irrallaan ohjelman tietosisällöstä
("Separate policy and implementation"). Ydinohjelma jaotellaan säikeiden
mukaan omiin luokkiinsa ja toimintojen mukaan omiin funktioihinsa.
Yleiskuvaus
PicGUI-alijärjestelmä sisältää sekä varsinaisen
käyttäjälle näkyvän Tcl/Tk:lla tehdyn käyttöliittymän
että tämän ja ydinjärjestelmän välillä
tapahtuvan kommunikoinnin toteuttavan C++-luokan. Käyttöliittymä
pyrkii toimimaan itsenäisesti aina kuin mahdollista, eli liikenne
sen ja ytimen välillä pyritään rajaamaan vain välttämättömiin
viesteihin. Toisaalta, ylläpidettävä tieto halutaan pitää
vain yhdessä paikassa koodia (ohjelman ytimessä), joten käyttöliittymä
ei erikseen pidä yllä yleistä tietoa, vaan kysyy tarvitsemansa
asiat ohjelman ytimeltä.
Modulijako
Kuten edellä on jo mainittu, PicGUI-alijärjestelmä jakautuu
kahteen selkeään osaan; Tcl/Tk-käyttöliittymään
ja C++-osaan. C++ -osa on varsin suppea koostuen yhdestä ainoasta
PicGUI-luokasta jäsenfunktioineen. Käyttöliittymä on
yksi kokonainen moduli, jonka ikkunat ja ikkunoiden osaset on Tcl:n tyyliin
toteutettu strukturoidusti mahdollisimman selkeän esitystavan saavuttamiseksi.
Tämä tarkoittaa sitä, että pääikkunasta avautuvat
ali-ikkunat ovat myös toteutuksellisesti pääikkuna-objektin
aliobjekteja ja ikkunoiden osaset (buttonit jne.) kyseisten ikkunoiden
aliobjekteja. Hierarkia näkyy erityisesti nimeämisessä (win; win.subwin; win.subwin.button).
Toiminnot
PicGUI:n käyttöliittymäosa sisältää valtaosan
toiminnallisessa määrittelyssä
kuvatuista toiminnoista (käytännössä kaiken,mitä
käyttäjä voi interaktiivisesti "tehdä").
PicGUI:n C++ -luokka sisältää joukon funktioita, jotka mahdollistavat
tiedonsiirron käyttöliittymän ja ydinjärjestelmän
välillä.
Poikkeustilanteiden käsittely
C++-osan suhteen mahdolliset poikeustilanteet ovat tunnistamaton kommunikointitapahtuma
tai virheellinen määrä parametreja/virheellinen parametrin
sisältö tapahtumassa. Tällaisen sattuessa tapahtuma keskeytetään
ja viesti virheestä kirjoitetaan virhelokiin ja mahdollisesti inforuutuun,
mikäli debug-optio on PicGUI:n osalta päällä. Itse
käyttöliittymän mahdollisia poikkeustilanteita ovat käyttäjän
antamat virheelliset syötteet sellaisissa kohdissa, joissa käyttäjä
itse voi syöttää dataa järjestelmään. Näistä
virheistä informoidaan inforuudussa tai erillisellä dialogi-ikkunalla.
Testattavuus
C++-osan yleinen toimivuus on varsin helppo testata tekemällä
mikä tahansa toiminto, joka aiheuttaa kommunikointia ydinohjelman
kanssa. Sen sijaan kaikkien kommunikointitapahtumien yksityiskohtaisen
toimivuuden tarkistaminen vaatii järjestelmällisen toimintojen
läpikäynnin. Tosin eri kommunikointitapahtumat pyritään
ohjelmoimaan teknisesti niin samankaltaisiksi, että muutaman kommunikointitapahtuman
testaaminen tuo jo melkoisen varmuuden toiminnasta.
Käyttöliittymän testaamiseen riittää käyttöliittymän
sisällä olevien datarakenteiden toimivuuden ja ajantasalla olemisen
testaus, sillä muut käyttöliittymässä mahdollisesti
olevat virheet näkyvät suoraan käyttäjälle ohjelman
ulkonäössä.
Kommunikointi
PicGUI:n C++ -osa on lähes pelkästään kommunikoinnin
toteutusta käyttöliittymän ja ydinohjelman välillä.
Tätä kommunikointia tapahtuu luonnollisesti molempiin suuntiin.
Kommunikoinnin yksityiskohtaisempi toteutuskuvaus on löytyy kohdasta
4.1 Käyttöliittymärajapinta PicGUI-API.
Mahdolliset kommunikointitapahtumat ja niissä siirtyvät parametrit
on listattu seuraavassa suunnittain. Listaustapa on:
- Tapahtuma
- Tapahtumaan liittyvät parametrit
A. Käyttöliittymältä pääohjelmaan
- Kyselyn lähettäminen
- Algoritmin nimi, esimerkkikuva(t).
- Kyselyn keskeytys
- Kyselyn jatkaminen keskeytyksen jälkeen
- Esimerkkikuvan lataus tiedostosta
- Kuvan tiedostonimi polkuineen, kuvaindeksi
- Esimerkkikuvan tallennus levylle
- tiedostonimi polkuineen, kuvaindeksi
- Massainsertointi tietokantaan
- Tiedostonimi polkuineen/polku filttereineen (esim. /pic/*.jpg)
- Esimerkkikuvan insertointi tietokantaan
- Esimerkkikuva, kuvaindeksi
- Tietokantakuvan kopiointi esimerkkikuvaksi
- Tietokantakuvan id, kuvaindeksi
- Tietokantakuvan poistaminen
- Kyselyn tulosten selaus
- Selaussuunta ja selauksen määrä
- Kuvan parametrien asettaminen
- Ohjelman yleisoptioiden asetus
- Ohjelman yleisoptioiden kysyminen
- Piirtokuvan käsittely
- Kuvankäsittelyalgoritmi ja sen mahdolliset parametrit, kuvan indeksi
- Kuvankäsittelyalgoritmien parametrien kysyminen
- Hakutyypin vaihto
- Uuden hakukuvan luonti
- Hakukuvan tyhjennys
- Hakukuvan poisto
- Ilmoitus käyttöliittymän käynnistymisestä
- Hakualgorimin parametrien kysyminen
- Hakualgoritmin parametrien asettaminen
- Algoritmin nimi, parametrit
- Pääikkunan koon muuttaminen
- Tietokantakuvakehysten lukumäärä
- Ohjelman sammuttaminen
- Signaturen kysyminen
- Algoritmin nimi, kuvaindeksi
- Kuvan segmentointi
- Algoritmin nimi, kuvan nimi ja kuvaindeksi
- Segmentaatioparametrien kysyminen
- Segmentaatioparametrien asetus
- Algoritmin nimi, parametrit
- Segmentin kysyminen
- Algoritmin nimi, kuvaindeksi, segmentin numero
B. Pääohjelmalta käyttöliittymälle
- Kyselyn etenemisen ilmaisu
- Kyselyn tulos
- Tuloskuvat kaikkine parametreineen + hyvyysluvut
- Hakutyyppien lähetys
- Hakualgoritmien lähetys
- Segmentaatioalgoritmien lähetys
- Segmentaatioalgoritmit (nimet)
- Kuvankäsittelyalgoritmien lähetys
- Kuvankäsittelyalgoritmit (nimet)
- Käyttöliittymän käynnistäminen
- Mahdolliset käynnistysparametrit
- Inforuutuun kirjoitus
- Yleisdialogin luontikehotus
- Dialogin tyyppi, nimi, sisältö ja nappuloiden tekstit
- Esimerkkikuvan lataus tiedostosta (vastaus)
- Tietokantakuvan kopiointi esimerkkikuvaksi (vastaus)
- Esimerkkikuvan segmentaatio (vastaus)
- Piirtokuvan käsittely (vastaus)
- Kuvan parametrien korjaus (vastaus)
- Yleisoptioiden lähetys (vastaus)
- Kuvankäsittelyalgoritmien parametrien lähetys (vastaus)
- Hakualgoritmin parametrien lähetys (vastaus)
- Segmentointialgoritmien parametrien lähetys (vastaus)
Ohjeita toteutusta varten
Teknisessä mielessä PicGUI:n C++-osa on varsin simppeli joskin
"rönsyilevä" kommunikointitapahtumien määrästä
johtuen. Järjestelmällisyys on siis tärkeää toteutuksessa,
että jokainen kommunikointivaihtoehto tulee koodiin oikein mukaan.
Samoin Tcl/Tk-puolella tulee käyttää järjestelmällisyyttä
aina objektien ja muuttujien nimeämisestä lähtien, sillä
ikkunoita/dialogeja ja järjestelmän tilatietoja ylläpitäviä
dataobjekteja on melkoinen määrä.
Yleiskuvaus
Algoritmiosuus sisältää järjestelmän algoritmien toteutukset sekä
kuvaformaattien käsittelyt. Algoritmeja on kolmea tyyppiä:
hakualgoritmeja (signaturen lasku ja vertailu), segmentointialgoritmeja
sekä kuvankäsittelyalgoritmeja. Kuvia voidaan myös skaalata
sekä muuntaa kuvaformaatin (JPEG, PPM ja SunRaster) ja raakakuvan välillä
(RGB-dataa).
Kustakin algoritmityypistä toteutetaan vähintään yksi algoritmi
(segmentoinnista ainoastaan "dummy").
Modulijako
Modulijako suoritetaan algoritmeittain siten että kunkin
algoritmin toteutus on omassa modulissaan. Kuvien skaalaus on omassa
modulissaan samoin kuin kuvaformaattien toteutukset.
Attribuutit
Kullakin algoritmilla voi olla joukko parametreja.
Hakualgoritmien osalta nämä jakautuvat käyttäjän muutettavissa oleviin
(näillä ei ole vaikutusta signature-arvoihin vaan vertailu-osaan)
sekä kovakoodattuihin (vaikuttavat mahdollisesti signature-arvoihin,
jolloin näiden muuttaminen vaatisi koko tietokannan päivityksen).
Segmentointialgoritmeilla parametrit noudattavat samanlaista kahtiajakoa.
Kuvankäsittelyalgoritmeilla tällä kahtiajaolla ei ole merkitystä, koska
tietokannassa ei ole mitään kuvankäsittelyyn liittyvää dataa.
Toiminnot
- Signature - lasketaan signature kuvadatasta
- Vertailu - verrataan signatureja samankaltaisuuden tutkimiseksi
- Segmentointi - ositetaan kuva
- Kuvankäsittely - manipuloidaan kuvaa
- Kuvan skaalaus
- Kuvan muunto kuvaformaatista kuvadataksi (RGB)
- Kuvadatan (RGB) muunto kuvaformaattiin (PPM, JPEG ja SunRaster)
Poikkeustilanteiden käsittely
PicAlgorithm-osuudessa on vain muutamassa paikassa sellaisia kohtia,
joissa voi syntyä jokin poikkeustilanne. Tällöin poikkeustilanteen
käsittely ohjataan PicCoren käsiteltäväksi. Jotkin PicLibin metodit
saattavat myös aiheuttaa poikkeustilanteita, mutta nämä PicCore hoitaa
ilman eri ohjausta.
Testattavuus
Signature ja vertailu
Näitä on vaikea testata muutoin kuin debuggaamalla melkeinpä rivi
riviltä, että toimivatko jäsenfunktiot oikein. Pelkkä ajo ei nimittäin
mitenkään paljasta, onko signature tai vertailu tehty oikein. Tarvittaisiin
toimiva implementaatio, johon voisi verrata modulien toimivuutta, mutta
sellaista implentaatiota ei ole saatavilla. Kuvaa voidaan kuitenkin
verrata itseensä jolloin (millä tahansa järkevällä algoritmilla)
vastaavuus on täydellinen.
Segmentointi
Testataan ainoastaan segmenttien tallentuminen "dummy"-algoritmin avulla.
Kuvankäsittely
Nämä algoritmit ovat helpompia testattavia, koska tulokset näkyvät ja
niistä voidaan usein todeta toiminta/toimimattomuus. (Esim. negatiivin
teko ja skaalaus)
Kommunikointi
Kaikkia PicAlgorithm-moduleja kutsutaan ydinohjelmasta, jonne myös
mahdolliset paluuarvot annetaan. Vaikka esim. signaturen laskeminen
saattaa koskea joskus kaikkia tietokannan kuvia, niin tämäkin
toiminta ohjataan kokonaan ydinohjelmasta.
Ohjeita toteutusta varten
- Signature ja vertailu: Wavelet-algoritmi :
Jacobs et al.: Fast Multiresolution Image Querying
- Kuvankäsittely: Tutustutaan valmiisiin implementaatioihin sekä
tutkitaan esim. kirjallisuudesta kuvankäsittelyalgoritmeja.
Yleiskuvaus
PicDb -alijärjestelmä on melko itsenäinen järjestelmän osa. Se
tarjoaa järjestelmälle tietokantapalveluja
PicDb-API -rajapinnan kautta. Rajapinta
kattaa tiedon tallettamiseen, hakemiseen, poistamiseen ja päivittämiseen
tarvittavat palvelut.
PicDb:n palveluilla toteutetaan järjestelmän kuvien fyysinen tallennus.
Tietokannassa pidetään myös muuta järjestelmän tarvitsemaa pysyvää tietoa,
kuten erilaisia ohjelman toimintaan vaikuttavia parametreja.
Itse tietokantamoottori, jota rajapinnan kautta käytetään,
on mahdollisimman yksinkertainen relaatiotauluperiaatetta noudattava
tiedonhallintajärjestelmä. Tämä tarkoittaa sitä, että kukin tietokannan
relaatiotaulu sijaitsee omassa tiedostossaan, jossa tietueet,
eli relaatiotaulun rivit, on tallennettuna peräkkäin.
PicDb käyttää suorasaantia tietueiden hakemiseen fyysiseltä
tallennusmedialta, jolloin yksittäinen tietua saadaan tiedostosta
käymättä läpi suurinta osaa tiedoston tietueista. Suorasaanti
toteutetaan käyttämällä erillistä indeksitiedostoa kullekin relaatiotaululle.
Modulijako
PicDb -alijärjestelmä jakautuu seuraaviin moduleihin:
- PicDb-API on alijärjestelmän rajapinta muulle osalle
järjestelmää.
- PicDbEngine on tietokantamoottori, jota käytetään PicDb-API:lla.
Se tarjoaa yksinkertaisen rajapinnan matalan tason
tietokantaoperaatioihin, joiden avulla PicDb-API operoi tietokantaa.
Attribuutit
PicDb on itsenäinen järjestelmän osa, eikä sen toiminta riipu mistään PicDb
osuuden kannalta ulkoisesta järjestelmän parametrista. Kommunikaatio PicDb:n
ja järjestelmän muun osan kanssa tapahtuu vain ja ainoastaan PicDb-API:n
kautta (pois lukien debug-viestit). Relaatiotaulut, niiden kentät
tietotyyppeineen ja avainkentät on kovakoodattu, eikä niihin voi siis
vaikuttaa PicDb-API:n kautta.
Toiminnot
Järjestelmän tietokantaosuuden, PicDb:n, kaikki toiminnot ovat käytettävissä
PicDb-API:n kautta. Kaikki rajapinnan toiminnot ovat siis PicDb:n toimintoja:
- Yhteyden luominen ja katkaiseminen tietokantaan.
- Haun lähettäminen.
- Haun tuloksien iteroiminen yksi tietue kerrallaan.
- Tiedon lisääminen tietokantaan.
- Tiedon päivittäminen tietokantaan.
- Tiedon poisto tietokannasta.
- Sitoutuminen kantaan tehtyihin muutoksiin ja niiden peruminen.
- Kannan reorganisointi, eli uudelleenjärjestäminen.
- Tietokannan koko sisällön, paitsi binäärityyppisten kenttien osalta
ainoastaan tallennetun datan koko tavuissa, tulostaminen testausta ym.
varten.
Poikkeustilanteiden käsittely
PicDb tietokantaosuudessa virhe- ja poikkeustilanteet käsitellään PicLib:n
tarjoamilla tarkoitukseen sopivilla toiminnoilla. Useimmat PicDb-API
tietokantarajapinnan järjestelmälle tarjoamat funktiot palauttavat kutsujalleen
boolean tyyppisen paluuarvon, jonka kutsujan pitäisi aina
tarkistaa kutsun jälkeen. Normaalisti paluuarvo tosi tarkoittaa, että
PicDb:n suorittama toiminto on sujunut virheettömästi, epätosi taas palautetaan
virhe- tai poikkeustilanteissa. Poikkeuksena haku-, päivitys- ja -poisto-
operaatiot, joissa paluuarvo kertoo haettavan, päivitettävän tai poistettavan
tietueen tai tietueiden löytymisestä, jota kielteisessä tapauksessa ei voi
pitää varsinaisena virhetilanteena.
Testattavuus
PicDb -alijärjestelmää testataan PicSearch sovelluksen kautta käyttämällä
PicSearch:n tietokantaa hyödyntäviä toimintoja. Testauksessa voi seurata
PicDb -alijärjestelmän tulostamia debug-viestejä, jotka voi asettaa
päälle PicSearch:n pääikkunan Options -valikosta. Myös tietokannan sisällön
tulostaminen (tarkoitukseen varattu komentorivioptio) voi osoittautua
hyödylliseksi.
Kommunikointi
Ydinohjelma kommunikoi PicDb tietokantaosuuden kanssa tietokantarajapinnan
PicDb-API:n avulla. PicDb-API käyttää puolestaan matalan tason
tietokantarajapintaa kommunikoidessaan PicDbEngine tietokantamoottorin kanssa.
PicDb-API:n ja PicDbEngine:n välinen rajapinta ei ole yhtä selkeä ja
tarkasti rajoitettu kuin PicDb-API:n tarjoama rajapinta järjestelmälle.
6. Modulien toteutuksen kuvaus
6.1 Peruskirjasto -- PicLib
Source code documentation
PicLib-luokkakirjasto koostuu alla esitetyn listan mukaisista
luokista. # merkitsee abstraktia kantaluokkaa, sisennys kuvaa
mistä kantaluokasta kukin luokka on johdettu, hakasuluissa esitetty
luokan sisältämät attribuutit
BaseDate [PICUSHORT theYear, theMonth, theDay]
BaseTime [PICUSHORT theHour, theMinute, theSecond]
BaseDateTime [BaseDate date, BaseTime time]
BaseReal [PICFLOAT imp, PICUSHORT flags]
BaseString [PICSIZE alloc, size, count, char *rep]
PicClass [const char *className, PICUSHORT instSize]
PicVirtClass [PicVirtClass *base, *derived, *nextSibling, *prevSibling]
PicObjectClass [PICFCREATENEW *createNew]
#PicVirtObject
#PicObject
#PicPrimitive
PicDate : publib BaseDate
PicDateTime [ BaseDateTime dt ]
PicInteger [PICLONG imp, PICBOOL isNullInteger]
PicLogic [PICSHORT val]
PicTime : publib BaseTime
PicString : publib BaseString
PicAssoc [PICINDEX ind, PicObject* obj]
#BaseCollection [PicGenArrayInfo *info, char *content, PICSIZE alloc, ub]
BaseStringArray
PicObjectPtrArray
PicAssocArray
PicNamAssocArray [NameBuffer *names]
#PicObject
#PicCollection
#PicIxCollect
#PicKeyIxCollect
#PicIxMapObject [PicAssocArray assocs]
PicIxMap
PicSortedIxMap [PICIXSORTER* order]
#PicSeqIxCollect
#PicArrayObject [PicObjectPtrArray array]
PicArray
PicSortedArray [PICOBJSORTER* order]
#PicNmCollect
#PicNmMapObject [PicNamAssocArray assocs]
PicNmMap
PicSortedNmMap [PICNMSORTER* order]
PicIterator [PICLONG current]
PicIteratorImp
PicIntSet [PicIntSetData* content]
PicIntArray [PICINT* content, PICSIZE allob, lb, ub]
PicErrorText [BaseString errorText, PicClass* errorClass,
PICUSHORT errorStatus, errorLine,
char* errorFile]
PicFmtErrorText [PicStringStream strStream, PicFmtText fmtText]
PicRaiseFmtError
PicHoldFmtError
PicRaiseFatalError
PicError [BaseString errorText, PicClass* errorClass,
PICUSHORT errorStatus, errorLine, errorNum,
char* errorFile, PicErrorManager* manager,
PicError* next, *last]
PicErrMgrParam
#PicNotifier
PicDefaultNotifier
PicErrorContext [PicErrorContext* previous, PicError* error]
PicTestContext
#PicErrorManager [PICBOOL memoryError, PicErrorContext* currentContext,
PicNotifier* pNotifier]
PicL1ErrorManager
PicErrorLog
#PicVirtObject
#PicStream
PicChainStream [PicChainStream* chain, PicStream* stream]
PicInStringStream [BaseString *stream, PICPOSITION current]
PicStringStream
PicInCharStream [char* stream, PICSIZE stmSize, PICOFFSET current]
PicCharStream
#PicBufferStream [char* buffer, PICOFFSET bufPtr, PICSIZE bufSize]
PicFileStream [PicFile theFile, PICHFILE fHandle
PICBOOL endOfFile, PicOpenMode saveOpenFlags]
PicTextFmt [PicStream *stream, char* format, PICSIZE indent]
PicText [PicStream *theStream]
PicFmtText [char* fmt, PicWrObjArray* pending, PICSIZE indentSize]
BaseString
PicStringText [PicStringStream strStream, PicFmtText fmtText]
PicEnvironment
PicFile [BaseString fName]
PicFileIterator [PicFile file, [OS-depedent handle], PICUINT attr]
PicSemaphore [[OS-depedent data]]
PicThread [PicSemaphore semMutex, PicSemaphore semReady,
PICUSHORT useCount, PICTHREADRESULT res,
PicThreadState tState, PicPriority priority,
PICUSHORT tId, [OS-depedent data]]
PicThreadPointer [PicThread *t]
PicCritSec [PicSemaphore* sem]
6.2 Ydinohjelma -- PicCore
Source code documentation
Pääohjelma alustaa ohjelman luomalla tarvittavat yleiset muuttujat.
Seuraavaksi käynnistetään käyttöliittymä kutsumalla PicGUI-objektin
start-metodia. GUI:n käynnistyttyä luodaan yhteys tietokantaan.
Jos järjestelmässä on ohjelmoituna algoritmeja, joita ei
tietokannan mukaan ole, lisätään näistä tieto tietokantaan ja
käynnistetään tietokannan päivityssäie (DbUpdateThread).
Tämän jälkeen toiminta jatkuu PicGUI:n viestien
välityksellä PicMain-objektin metodeissa. PicMain-luokka on
pääpiirteiltään seuraavan mukainen:
class PicMain
{
public:
PicMain();
PICBOOL startGUI(int argc, char *argv[]);
static void guiHasStarted(void);
static PICBOOL changeSearchType(BaseString searchTypeName);
static PICBOOL newExampleImage(PICULONG listIndex);
static PICBOOL exImageClosed(PICULONG listIndex);
static PICBOOL exImageCleared(PICULONG listIndex);
static PICBOOL setImageAttributes(PicIxCollect ¶ms,
PICULONG listIndex);
static PICBOOL loadImage(BaseString filename,
PicPicture &resultImage,
PICULONG listIndex,
PICBOOL updating);
static PICBOOL saveImage(BaseString filename,
PicPicture &image,
PICULONG listIndex,
PICUSHORT buttonNbr);
static BaseString getSignatureImage(BaseString algName,
PICULONG listIndex);
static PICBOOL getSegmAlgParams(BaseString algName,
PicIxCollect ¶ms);
static PICBOOL setSegmAlgParams(BaseString algName,
PicIxCollect ¶ms);
static PICBOOL segmentImage(BaseString algName,
PicPicture &image,
PICULONG listIndex);
static BaseString getSegment(BaseString algName,
PICULONG listIndex,
PICUSHORT &segNum);
static PICBOOL getImProcAlgParams(BaseString algName,
PicIxCollect ¶ms);
static PICBOOL processImage(BaseString algName,
PicPicture &image,
PicIxCollect ¶ms,
PICUSHORT buttonNbr);
static PICBOOL getSearhAlgParams(BaseString algName,
PicIxCollect ¶ms);
static PICBOOL setSearhAlgParams(BaseString algName,
PicIxCollect ¶ms);
static PICBOOL query(BaseString algName,
PicSeqIxCollect *exImages);
static PICBOOL browseQueryResults(PICUSHORT numOfFirst);
static PICBOOL suspendQuery();
static PICBOOL resumeQuery();
static void setNumOfDbFrames(PICUSHORT frames);
static PICBOOL insertImageToDb(PicPicture &image,
PICULONG listIndex,
PICUSHORT buttonNbr);
static PICBOOL readImageFromDb(PICULONG imageId,
PICULONG listIndex,
PicPicture &resultImage);
static PICBOOL deleteImageFromDb(PICULONG imageId,
PICUSHORT buttonNbr);
static PICBOOL batchInsert(BaseString filename,
PICUSHORT buttonNbr);
static PICBOOL getParams(PicIxCollect ¶ms);
static PICBOOL setParams(PicIxCollect ¶ms);
static PICBOOL exitProgram(PICUSHORT buttonNbr);
static PicMainSharedData globData;
private:
static PicArray examplePics;
static PicArray exampleListIndexes;
static PicGUI gui;
static PicMainDbUser db;
static PicQueryThread queryThread;
static PicMassInsertThread batchThread;
static PicDbUpdateThread dbUpdateThread;
};
6.3 Käyttöliittymäosuus -- PicGUI
Source code documentation
PicGUI koostuu kahdesta päämodulista: Tcl/Tk-käyttöliittymästä
ja C++-luokasta. C++:n PicGUI-luokan konstruktori luo ja käynnistää
Tcl/Tk-tulkin, joka puolestaan suorittaa määrätyt valmistelut
Tcl/Tk:ta varten (uusien käskyjen määrittelyt, tarvittavien
muuttujien trace jne.), lukee sisään Tcl/Tk-koodin ja tulkkaa
sen.
Luokan muut jäsenfunktiot toteuttavat kommunikaation käyttöliittymän
ja ydinohjelman välillä. On huomattava, että kommukaatio
suunnassa käyttöliittymä => ydinohjelma toteutetaan itse
luodulla uudella Tcl-käskyllä, joten tämän käskyn
toteutusfunktio tulee laittaa luokan yksityiseksi jäseneksi, koska
käyttöliittymän Tcl/Tk-koodi (tai käytännössä
tulkki) on ainoa, jolla on lupa käyttää tätä funktiota.
Samoin tämän uuden käskyn C++ - puolen alifunktiot ovat
yksityisiä jäseniä. Ohjelmoitavat kommunikaatiotapahtumat
ja niissä käytettävät parametrit näkyvät
luvun 5.3 Käyttöliittymäosuus -- PicGUI
kohdassa "kommunikointi". PicGUI-luokka on pääpiirteiltään
seuraavan mukainen:
class PicGUI
{
public:
PicGUI();
~PicGUI ();
PICBOOL start(int argc, char *argv[]);
static PICBOOL sendQueryAdvance(PICUSHORT percentage);
static PICBOOL sendQueryResults(const PicIxCollect &pics);
static PICBOOL infoPrint(BaseString message);
static PICUSHORT simpleDialog(BaseString type, BaseString title, \
BaseString text, BaseString bnames);
static PICBOOL setSearchTypes(BaseStringArray &names);
static PICBOOL setSearchAlgorithms(BaseStringArray &names);
static PICBOOL setSegmentationAlgorithms(BaseStringArray &names);
static PICBOOL setImageProcessingAlgorithms(BaseStringArray &names);
private:
static PICINT transmitCmd(ClientData clientdata, Tcl_Interp *interp, \
PICINT argc, char *argv[]);
static void tr_query(PICINT argc, char *argv[]);
static void tr_load(char *fullname, char *listindex, char *uflag);
static void tr_save(char *fullname, char *listindex, char *dflag);
static void tr_insert(char *name, char *listindex, char *dflag);
static void tr_copy(char *imageid, char *listindex);
static void tr_delete(char *imageid);
static void tr_scroll(int argc, char *argv[]);
static void tr_imageAttr(char *listindex, char *imageparams);
static void tr_options_set(int argc, char *argv[]);
static void tr_options_get(void);
static void tr_process(char *algname, char *picname, \
char *algparams, char *pflag);
static void tr_processParams(char *algname);
static void tr_started(void);
static void tr_algParams_get(char *algname);
static void tr_algParams_set(char *algname, char *algparams);
static void tr_segalgParams_get(char *algname);
static void tr_segalgParams_set(char *algname, char *algparams);
};
Tcl/Tk-koodi on jaoteltu alimoduleihin siten, että pääikkuna
muodostaa yhden hierarkisen kokonaisuuden (picsearch.tk & geometry.tk),
piirtoikkuna on toinen alimoduli (editor.tk) ja muut pienemmät ikkunat/dialogit
kolmas alimoduli (subwins.tk). Tämä jaottelu vastaa siis pääpiirteittäin
koodin tiedostoihinjakoa (edellämainittujen tiedostojen lisäksi
on olemassa subprocs.tk, joka sisältää yleisfunktioita ja
pääikkunan toimintafunktioita). Itse käyttöliittymän
toteutus Tcl/Tk:lla on varsin mekaaninen toimenpide, eikä näin
vaadi erityistä teknistä dokumentointia. Käyttöliittymän
ulkonäkö, toiminnot ja toimintojen sijoittelu näkyvät
Toiminnallinen määrittely -dokumentissa.
Mainittakoon tässä kuitenkin, että käyttöliittymäobjektien
sijoittelussa käytetään kauttaaltaan "place" -geometriamanageria,
koska tämä sallii objektien sijoittelun pikselin tarkkuudella
ja näin antaa siisteimmän lopputuloksen. Käyttöliittymässä
käytetään tavallisia Tk4.1-widgettejä.
6.4 Algoritmiosuus -- PicAlgorithm
Source code documentation
Kuvaformaateista
Ohjelmaan ohjelmoidaan tuki JPEG-, PPM- ja SunRaster-kuvaformaateille.
Kuvaformaatit ovat pääpiirteiltään seuraavanlaisesta kantaluokasta johdettuja:
class PicImageFormat : public PicObject
{
public:
virtual PicRawPicture *readPicture(BaseString filename);
virtual PICBOOL writePicture(BaseString filename, PicRawPicture *);
virtual PicRawPicture *readPicture(PicStream &from, PICULONG size) = 0;
virtual PICBOOL writePicture(PicStream &to, PicRawPicture *) = 0;
BaseString name;
PICULONG id;
BaseStringArray fileExtensions;
PICBOOL isLossy;
};
Fyysisesti kuvadata pidetään PicRawPicture-objekteissa.
class PicRawPicture : public PicObject
{
public:
PICUSHORT getWidth() const;
void setWidth(PICUSHORT newWidth);
PICUSHORT getHeight() const;
void setHeight(PICUSHORT newHeight);
unsigned char* getDataPtr() const;
void setDataPtr(unsigned char* newPtr);
private:
Tk_PhotoImageBlock rawImage; // defined in tk.h
};
Loogiset kuvat ovat pääpiirteiltään seuraavanlaisessa luokassa:
class PicPicture : public PicObject
{
public:
PICBOOL loadFromFile(BaseString filename);
PICBOOL writeToFile(BaseString filename);
void setRaw(PicRawPicture *newRaw);
PICULONG id;
BaseString name;
BaseString par1;
BaseString par2;
BaseString filename;
PicArray signatures;
PicArray segmentations;
PicImageFormat *format;
PicRawPicture *raw;
PicBin origData;
PICBOOL identicalToFilename;
BaseString matchRate;
PICUSHORT matchRanking;
};
Algoritmeista
Hakualgoritmit ovat pääpiirteiltään seuraavanlaisesta kantaluokasta johdettuja:
class PicSearchAlgorithm : public PicObject
{
public:
BaseString name;
PICULONG id;
virtual PICBOOL getParams(PicIxCollect ¶ms)=0;
virtual PICBOOL setParams(PicIxCollect ¶ms)=0;
virtual PICUSHORT compare(PicSignature &firstSig, PicSignature &secSig)=0;
virtual PicSignature *computeSignature(PicPicture &pic)=0;
};
Kullekin hakualgoritmille luodaan normaalisti oma signature-luokka
pääpiirteiltään seuraavanlaisesta kantaluokasta johdettuma:
class PicSignature : public PicObject
{
public:
virtual char *getBin(PICULONG &size) const = 0;
virtual PICBOOL setBin(const char *data, PICULONG size) = 0;
virtual PICULONG algId() const = 0;
virtual BaseString getImage() const;
};
6.5 Tietokantaosuus -- PicDb
Source code documentation
6.5.1 PicDb-API
PicDb-API:n kuvaus on pohja modulin
toteutukselle. TableEntry johdetaan PicObject luokasta, jolloin
TableEntry:n aliluokkien instansseista voidaan milloin tahansa
ottaa selville instanssin luokka käyttämällä tähän tarkoitettua
PicObject luokan metodia. Näin esim. PicDbConnection luokan
"query" funktio tunnistaa operaation kohteena olevan relaatiotaulun luokasta,
jota parametrina annettu "entry" on. "query" funktio lähettää
PicDbEngine:lle
pyynnön hakea "entry" parametrin määrittämästä taulusta "searchKeyFields"
parametrin kertomista kentistä "entry" parametrin vastaavissa jäsenmuuttujissa
olevia arvoja. Ensimmäinen mahdollisesti löytyvä rivi palautetaan "entry"
parametrin muuttujissa.
"fetchNext" metodi hakee "entry" parametriin seuraavan hakuehdot täyttävän
rivin.
"insert" funktio lisää "entry" parametrin
määräämään relaatiotauluun sisältämänsä rivin.
"remove" funktio toimii vastaavasti kuin "query" funktio, mutta poistaa
löytyneet rivit relaatiotaulusta.
"update" funktio toimii niinikään vastaavasti kuin "query", mutta löytyneet
relaatiotaulun rivit, eli tietueet, päivitetään annetuilla parametreilla.
"reorganize" järjestää tietokannan levyllä uudestaan. "update" ja "remove"
funktioiden jäljiltä relaatiotaulujen tietueet sisältävissä tiedostoissa
saattaa olla "aukkoja", eli käyttämättömiä alueita. Tiedostot järjestetään
uudelleen, siten että aukot poistuvat. Samalla indeksitiedostot päivitetään
vastaavasti.
"connect" ja "disconnect" toteutettavassa, äärimmäisen yksinkertaisessa,
tietokantajärjestelmässä ovat lähinnä muodon vuoksi, koska yhteyden voi
luoda vain yhteen ja samaan tietokantaan. Nämä metodit ovatkin mukana
lähinnä tulevaisuutta ajatellen, jos halutaan siirtyä kehittyneempään
tietokantajärjestelmään, jossa voi olla useita tietokantoja.
"commit" ja "rollback" toteutetaan käyttämällä lokitiedostoja, joihin
kaikki kantaan kohdistetun muutokset talletetaan. "commit" ja "rollback"
aiheuttavat joko lokitiedostoissa olevien tietueiden tallentamisen
tietokantaan tai lokitiedostojen tietueiden hylkäämisen.
Näiden operaatioiden toteuttaminen projektin puitteissa yksinkertaistettuun
tietokantamoottoriin saattaa osoittautua liian työlääksi verrattuna
saavutettavaan hyötyyn. Operaatioita käytetään joka tapauksessa ydinohjelmassa
tulevaisuuden varalta, jolloin tietokanta mahdollisesti korvataan näitä
operaatioita tukevalla tietokannalla.
6.5.2 PicDbEngine
PicDbEngine moduli käsittelee
relaatiotauluja erillisiä taulun rivejä, eli tietueita, sisältävänä
tiedostona. Kutakin tietuetta käsitellään binääristä
dataa sisältävänä lohkona, joka voi siis olla mielivaltaisen kokoinen.
PicDbEngine
ei ota mitään kantaa tietueen sisäiseen esitysmuotoon, kenttien
määrään tietueessa jne.
Jokaista relaatiotaulun tietueita sisältävää tiedostoa kohti
PicDbEngine
ylläpitää toista tiedostoa, indeksitiedostoa. Siinä on kutakin
relaatiotaulun tietuetta kohden indeksiarvo, eli yhdiste avainkenttien
arvoista, sekä kyseisen tietueen pituus ja sijainti varsinaisessa
tietokantatiedostossa. Näin tietueet voidaan hakea tiedostoista suorasaannilla.