15. OpenCV шаг за шагом. Сохранение данных в XML

1. OpenCV шаг за шагом. Введение.
2. Установка.
3. Hello World.
4. Загрузка картинки.
5. Вывод видео
6. Ползунок
7. Захват видео с камеры
8. Запись видео
9. События от мышки
10. Обработка изображения — сглаживание
11. Обработка изображения — изменение размеров
12. ROI — интересующая область изображения
13. Типы данных OpenCV
14. Матрица
15. Сохранение данных в XML

Придётся сделать ещё одну остановку перед рассмотрением действительно интересных функций компьютерного зрения.
Рассмотрим функции OpenCV для сохранения/считывания данных в файлы.

OpenCV имеет механизмы сериализации/десериализации данных и возможность сохранять/считывать эти данные из XML-файлов.

Вот две самых удобных функции:

CVAPI(void) cvSave( const char* filename, const void* struct_ptr,
                    const char* name CV_DEFAULT(NULL),
                    const char* comment CV_DEFAULT(NULL),
                    CvAttrList attributes CV_DEFAULT(cvAttrList()));
— сохранение объекта в файл
filename — название файла
struct_ptr — указатель на объект для сохранения
name — название объекта (если NULL — будет сформировано из названия файла filename)
comment — комментарий для размещения в начале файла
attributes — атрибуты передаваемые функции cvWrite()

CVAPI(void*) cvLoad( const char* filename,
                     CvMemStorage* memstorage CV_DEFAULT(NULL),
                     const char* name CV_DEFAULT(NULL),
                     const char** real_name CV_DEFAULT(NULL) );
— считывание объекта из файла
filename — название файла
memstorage — хранилище памяти для динамических структур типа CvSeq (не используется для матриц или изображений)
name — название объекта (если NULL — самый первый объект будет загружен)
real_name — выходной параметр, который будет содержать название загруженного объекта (полезно в случае name=NULL)

функция загружает и возвращает объект из файла (обёртка вокруг cvRead()).

Простой пример использования — сохранение/загрузка данных матриц.
В приведённой программе сначала создаётся матрица, затем она сохраняется в xml-файл, а затем другая матрица загружается из этого файла.

//
// пример сохранения/загрузки
// данных из XML-файла
// и 3 способа получения элементов матрицы
//

#include <cv.h>
#include <highgui.h>
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char* argv[])
{
	// массив, содержащий данные матрицы
	float kernel[9];
	kernel[0]=1;
	kernel[1]=0;
	kernel[2]=0;

	kernel[3]=0;
	kernel[4]=2;
	kernel[5]=0;

	kernel[6]=0;
	kernel[7]=0;
	kernel[8]=3;

	// создаём матрицу
	CvMat kernel_matrix=cvMat(3,3,CV_32FC1,kernel);

	// сохраняем матрицу в XML-файл
	cvSave("kernel.xml", &kernel_matrix);

	// а теперь загрузим данные из XML-файла
	CvMat* matrix = (CvMat*)cvLoad("kernel.xml");

	// покажем содержимое матрицы
	//
	int i=0, j=0;

	// 1 вариант: с использованием макроса CV_MAT_ELEM
	for(i=0; i<matrix->rows; i++){
		for(j=0; j<matrix->cols; j++){
			printf("%.0f ", CV_MAT_ELEM( *matrix, float, i, j));
		}
		printf("\n");
	}
	printf("-----\n");
	// 2 вариант: с использованием cvGet2D(), cvGetReal2D()
	for(i=0; i<matrix->rows; i++){
		for(j=0; j<matrix->cols; j++){
			printf("%.0f ", cvGet2D(matrix, i, j));//cvGetReal2D(matrix, i, j));
		}
		printf("\n");
	}
	printf("-----\n");
	// 3 вариант: прямой доступ к элементам
	for(i=0; i<matrix->rows; i++){
		float* ptr = (float*)(matrix->data.ptr + i*matrix->step);
		for(j=0; j<matrix->cols; j++){
			printf("%.0f ", ptr[j]);
		}
		printf("\n");
	}

	// освобождаем ресурсы
	cvReleaseMat(&matrix);

	return 0;
}


вот как выглядит получившийся XML-файл:
<?xml version="1.0"?>
<opencv_storage>
<kernel type_id="opencv-matrix">
  <rows>3</rows>
  <cols>3</cols>
  <dt>f</dt>
  <data>
    1. 0. 0. 0. 2. 0. 0. 0. 3.</data></kernel>
</opencv_storage>


Ниже приведены другие функции для работы с файловыми хранилищами.

// чёрный ящик файлового хранилища
typedef struct CvFileStorage CvFileStorage;

CVAPI(CvFileStorage*)  cvOpenFileStorage( const char* filename,
                                          CvMemStorage* memstorage,
                                          int flags );
— открытие файлового хранилища для чтения/записи данных
filename — название файла
memstorage — хранилище памяти, используемое для временных данных и для сохранения динамических структур (CvSeq). Если NULL, то создаётся временное хранилище.
flags — флаг:
#define CV_STORAGE_READ          0 // открыть для чтения
#define CV_STORAGE_WRITE         1 // открыть для записи
#define CV_STORAGE_WRITE_TEXT    CV_STORAGE_WRITE
#define CV_STORAGE_WRITE_BINARY  CV_STORAGE_WRITE
#define CV_STORAGE_APPEND        2


тип чтения/записи определяется расширением файла xml/yml

CVAPI(void) cvReleaseFileStorage( CvFileStorage** fs );
— освобождает файловое хранилище
fs — двойной указатель на файловое хранилище

CVAPI(void) cvWrite( CvFileStorage* fs, const char* name, const void* ptr,
                         CvAttrList attributes CV_DEFAULT(cvAttrList()));
— записывает пользовательский объект
fs — файловое хранилище
name — название записываемого объекта (должно быть NULL, если родительская структура — последовательность)
ptr — указатель на объект
attributes — аттрибуты (свои для каждого типа)

CVAPI(void*) cvRead( CvFileStorage* fs, CvFileNode* node,
                        CvAttrList* attributes CV_DEFAULT(NULL));
— десериализация объекта и возвращение указатель на него
fs — файловое хранилище
node — узел объекта
attributes — неиспользуемый параметр

CVAPI(void) cvStartWriteStruct( CvFileStorage* fs, const char* name,
                                int struct_flags, const char* type_name CV_DEFAULT(NULL),
                                CvAttrList attributes CV_DEFAULT(cvAttrList()));
— начало записи новой структуры
fs — указатель на файловое хранилище
name — название записываемой структуры
struct_flags — флаг:
#define CV_NODE_SEQ 5 // последовательность
#define CV_NODE_MAP 6 // карта

type_name — название типа объекта
attributes — не используется

CVAPI(void) cvEndWriteStruct( CvFileStorage* fs );
— завершение записи структуры
fs — указатель на файловое хранилище

CVAPI(void) cvWriteInt( CvFileStorage* fs, const char* name, int value );
— запись целочисленного значения
fs — указатель на файловое хранилище
name — название записываемой величины (может быть NULL только в случае если родительская структура — последовательность)
value — записываемое значение

CVAPI(void) cvWriteReal( CvFileStorage* fs, const char* name, double value );
— запись значения c плавающей точкой (float)
fs — указатель на файловое хранилище
name — название записываемой величины (может быть NULL только в случае если родительская структура — последовательность)
value — записываемое значение

CVAPI(void) cvWriteString( CvFileStorage* fs, const char* name,
                           const char* str, int quote CV_DEFAULT(0) );
— записывает строчку
fs — указатель на файловое хранилище
name — название записываемой величины (может быть NULL только в случае если родительская структура — последовательность)
str — записываемая строчка
quote — если отлично от 0, то записываемая строчка обрамляется в кавычки

CVAPI(void) cvWriteComment( CvFileStorage* fs, const char* comment,
                            int eol_comment );
— записывает комментарий
fs — указатель на файловое хранилище
comment — комментарий
eol_comment — если отлично от 0, функция пытается поместить комментарий в конце текущей линии. Если 0, если комментраий многострочный или он не помещается в конце строки — он записывается с новой строчки.

CVAPI(void) cvWriteRawData( CvFileStorage* fs, const void* src,
                                int len, const char* dt );
— записывает числа
fs — указатель на файловое хранилище
src — указатель на массив данных для записи
len — число элементов в массиве (для записи)
dt — спецификация каждого элемента массива формата:
([count]f’u’|’c’|’w’|’s’|’i’|’f’|’d’g)…
, где буквы определяют тип данных:
u — 8-битный беззнаковый
c — 8-битный знаковый
w — 16-битный беззнаковый
s — 16-битный знаковый
i — 32-битный знаковый
f — float
d — double
r — указатель (32-битный знаковый целочисленный)

int cvReadInt( const CvFileNode* node, int default_value CV_DEFAULT(0) );
int cvReadIntByName( const CvFileStorage* fs, const CvFileNode* map,
                         const char* name, int default_value CV_DEFAULT(0) );
— считывает безымянное/именованное целочисленное значение
fs — указатель на файловое хранилище
map — родительская карта. Если NULL — функция считывает самое верхнее значение
name — название узла
default_value — значение по-умолчанию

double cvReadReal( const CvFileNode* node, double default_value CV_DEFAULT(0.) );
double cvReadRealByName( const CvFileStorage* fs, const CvFileNode* map,
                        const char* name, double default_value CV_DEFAULT(0.) );
— считывает безымянное/именованное значение с плавающей точкой
fs — указатель на файловое хранилище
map — родительская карта. Если NULL — функция считывает самое верхнее значение
name — название узла
default_value — значение по-умолчанию

const char* cvReadString( const CvFileNode* node,
                        const char* default_value CV_DEFAULT(NULL) );
const char* cvReadStringByName( const CvFileStorage* fs, const CvFileNode* map,
                        const char* name, const char* default_value CV_DEFAULT(NULL) );
-считываем безымянное/именованное значение строки
fs — указатель на файловое хранилище
map — родительская карта. Если NULL — функция считывает самое верхнее значение
name — название узла
default_value — значение по-умолчанию

/* starts reading data from sequence or scalar numeric node */
CVAPI(void) cvStartReadRawData( const CvFileStorage* fs, const CvFileNode* src,
                               CvSeqReader* reader );

/* reads multiple numbers and stores them to array */
CVAPI(void) cvReadRawDataSlice( const CvFileStorage* fs, CvSeqReader* reader,
                               int count, void* dst, const char* dt );

CVAPI(void) cvReadRawData( const CvFileStorage* fs, const CvFileNode* src,
                          void* dst, const char* dt );
— считывает числа
fs — указатель на файловое хранилище
src — файловый узел для считывания данных
dst — указатель на массив для хранения данных
dt — спецификация каждого элемента массива (аналогична cvWriteRawData())

CVAPI(CvFileNode*) cvGetFileNodeByName( const CvFileStorage* fs,
                                       const CvFileNode* map,
                                       const char* name );

— находит узел в файловом хранилище по имени
fs — указатель на файловое хранилище
map — родительская карта. Если NULL — функция считывает самое верхнее значение
name — имя узла

Пример создания конфигурационного xml-файла:

// Несколько модифицированный пример Example 3-17.
// демонстрирующий запись значений в xml-файл
//
// из книги:
//   Learning OpenCV: Computer Vision with the OpenCV Library
//     by Gary Bradski and Adrian Kaehler
//     Published by O'Reilly Media, October 3, 2008
// p83

#include <cv.h>
#include <highgui.h>
#include <stdio.h>

int main(int argc, char** argv)
{
	CvMat *cmatrix = cvCreateMat(5,5,CV_32FC1);
	float element_3_2 = 7.7;
	*((float*)CV_MAT_ELEM_PTR( *cmatrix, 3,2) ) = element_3_2;
	cvmSet(cmatrix,4,4,0.5000);
	cvSetReal2D(cmatrix,3,3,0.5000);
	printf("Example 3_17, writing cfg.xml\n");
	// открываем файл для записи
	CvFileStorage* fs = cvOpenFileStorage(
		"cfg.xml",
		0,
		CV_STORAGE_WRITE
		);
	// записываем значения
	cvWriteInt( fs, "frame_count", 10 );
	cvStartWriteStruct( fs, "frame_size", CV_NODE_SEQ);
	cvWriteInt( fs, 0, 320 );
	cvWriteInt( fs, 0, 200 );
	cvEndWriteStruct(fs);
	cvWrite( fs, "color_cvt_matrix", cmatrix );
	cvReleaseFileStorage( &fs );
	return 0;
}


в результате получается cfg.xml вида:

<?xml version="1.0"?>
<opencv_storage>
<frame_count>10</frame_count>
<frame_size>
  320 200</frame_size>
<color_cvt_matrix type_id="opencv-matrix">
  <rows>5</rows>
  <cols>5</cols>
  <dt>f</dt>
  <data>
    0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 7.69999981
    0.50000000 0. 0. 0. 0. 0. 0.50000000</data></color_cvt_matrix>
</opencv_storage>


а теперь пример считывания этого конфигурационного файла:

// Несколько модифицированный пример Example 3-19.
// демонстрирующий считывание значений из xml-файла
//
// из книги:
//   Learning OpenCV: Computer Vision with the OpenCV Library
//     by Gary Bradski and Adrian Kaehler
//     Published by O'Reilly Media, October 3, 2008
// p84

#include <cv.h>
#include <highgui.h>
#include <stdio.h>

int main(int argc, char** argv)
{
	printf("Example 3_19 Reading in cfg.xml\n");

	// открываем файл для чтения
	CvFileStorage* fs = cvOpenFileStorage(
		"cfg.xml", 
		0, 
		CV_STORAGE_READ
		);

	//
	// считываем значения
	//
	int frame_count = cvReadIntByName( 
		fs, 
		0, 
		"frame_count", 
		5 // значение по-умолчанию
		);

	CvSeq* s = cvGetFileNodeByName(fs,0,"frame_size")->data.seq;

	int frame_width = cvReadInt( 
		(CvFileNode*)cvGetSeqElem(s,0) 
		);

	int frame_height = cvReadInt( 
		(CvFileNode*)cvGetSeqElem(s,1) 
		);

	CvMat* color_cvt_matrix = (CvMat*) cvRead(
		fs,
		0
		);

	// показываем
	printf("frame_count=%d, frame_width=%d, frame_height=%d\n",frame_count,frame_width,frame_height);

	cvReleaseFileStorage( &fs );
	return 0;
} 


Результат выполнения:
Example 3_19 Reading in cfg.xml
frame_count=10, frame_width=320, frame_height=200


Далее: 16. OpenCV шаг за шагом. Генерация случайных чисел
  • 0
  • 3 сентября 2010, 10:39
  • noonv

Комментарии (1)

RSS свернуть / развернуть

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.