czwartek, 28 maja 2009

XML i YAML w OpenCV

Czasu ostatnio niewiele (zaliczenia i te sprawy), a na blogu zastój. W OpenCV pracuję nad czymś "grubszym" dlatego od czasu do czasu zarzucę jakąś krótszą notką, żeby sprawić wrażenie, że blog jeszcze żyje :P

Dzisiaj będzie o XML/YAML. Najczęściej wykorzystujemy tego typu pliki do przechowywania parametrów lub ustawień programu. Zapis do pliku wygląda następująco:

// otwieramy plik do zapisu
CvFileStorage * fs = cvOpenFileStorage("conf.xml",0,CV_STORAGE_WRITE);

// zapisujemy dane
cvWriteInt(fs,"wysokosc", 480);
cvWriteInt(fs,"szerokosc", 640);

// zwalniamy zasoby
cvReleaseFileStorage(&fs);


i w ten sposób otrzymujemy plik conf.xml:



480
640



lub, zmieniając rozszerzenie, plik conf.yml:

%YAML:1.0
wysokosc: 480
szerokosc: 640


Odczyt danych wygląda podobnie do zapisu:
// otwieramy plik do odczytu
CvFileStorage * fs = cvOpenFileStorage("conf.xml", 0, CV_STORAGE_READ);

// odczytujemy dane
int wysokosc = cvReadIntByName(fs, 0, "wysokosc");
int szerokosc = cvReadIntByName(fs, 0, "szerokosc");

// zwalniamy zasoby
cvReleaseFileStorage(&fs);


To właściwie tyle z podstaw :) Oczywiście OpenCV daje więcej możliwości manipulowania danymi. Zamiast zapisywać wartości oddzielnie, możemy to zrobić w ciągu:
cvWriteInt(fs,"fps",30);
// zapisujemy strukture
cvStartWriteStruct(fs,"rozmiar",CV_NODE_SEQ);
cvWriteInt(fs,0, 480);
cvWriteInt(fs,0, 640);
cvEndWriteStruct(fs);


Otrzymamy pliki:


30

480 640


%YAML:1.0
fps: 30
rozmiar:
- 480
- 640


taką strukturę odczytujemy tak:

// otrzymujemy sekwencje - podobnie jak w detekcji twarzy
CvSeq* seq = cvGetFileNodeByName(fsr,0,"rozmiar")->data.seq;

int wysokosc = cvReadInt((CvFileNode*)cvGetSeqElem(seq,0));
int szerokosc = cvReadInt((CvFileNode*)cvGetSeqElem(seq,1));


Do plików XML/YAML możemy zapisywać także inne rzeczy:
CvMat* macierz = cvCreateMat(5,6,CV_32F);
cvZero(macierz);

// zapisujemy komentarz...
cvWriteComment(fs,"Komentarz",0);
// ...napis...
cvWriteString(fs,"napis","zapisany lancuch znakow");
// ...liczbe rzeczywista...
cvWriteReal(fs,"liczba",3.14);
// ...strukture (np. macierz)...
cvWrite(fs,"macierz",macierz);




"zapisany lancuch znakow"
3.1400000000000001

5
6
f
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.

%YAML:1.0
# Komentarz
napis: zapisany lancuch znakow
liczba: 3.1400000000000001
macierz: !!opencv-matrix
rows: 5
cols: 6
dt: f
data: [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0. ]


odczyt:
CvMat* macierz = (CvMat*) cvReadByName(fs,0,"macierz");
double liczba = cvReadRealByName(fs,0,"liczba",0.0);
const char* napis = cvReadStringByName(fs,0,"napis","domyslny");


Do plików tych można zapisywać także skomplikowane struktury drzewiaste. Wspomnę o tym gdy będę opisywał takie struktury :)

5 komentarzy:

Anonimowy pisze...

o, miłe, nie widziałem tego nigdy wcześniej a może się przydać :)

btw: subskrybuje Cię od jakiegoś czasu via rss i mam nadzieję, że nie zamierzasz przestawać pisać :)

Łukasz pisze...

oczywiście zamierzam nadal pisać, jak często znajdę czas/odpowiedni temat :)

Łukasz pisze...
Ten komentarz został usunięty przez autora.
Anonimowy pisze...

mam pytanie, bo to co tutaj piszesz nadpisuje plik xml, jak trzeba wywołać funkcje żeby dodawała kolejne dane na koniec pliku, kolejne węzły?

Łukasz pisze...

Można zamiast CV_STORAGE_WRITE otwierać do zapisu z opcją CV_STORAGE_APPEND. Poniżej przykład:

CvFileStorage * fs = cvOpenFileStorage("conf.xml",0,CV_STORAGE_WRITE);
cvWriteInt(fs,"wysokosc", 480);
cvWriteInt(fs,"szerokosc", 640);
cvReleaseFileStorage(&fs);

fs = cvOpenFileStorage("conf.xml",0,CV_STORAGE_APPEND);
cvWriteInt(fs,"wysokosc2", 240);
cvWriteInt(fs,"szerokosc2", 320);
cvReleaseFileStorage(&fs);

fs = cvOpenFileStorage("conf.xml",0,CV_STORAGE_READ);

cout << "wysokosc " << cvReadIntByName(fs, 0, "wysokosc") << endl;
cout << "szerokosc " << cvReadIntByName(fs, 0, "szerokosc") << endl;
cout << "wysokosc2 " << cvReadIntByName(fs, 0, "wysokosc2") << endl;
cout << "szerokosc2 " << cvReadIntByName(fs, 0, "szerokosc2") << endl;