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; irows; i++){
		for(j=0; jcols; j++){
			printf("%.0f ", CV_MAT_ELEM( *matrix, float, i, j));
		}
		printf("\n");
	}
	printf("-----\n");
	// 2 вариант: с использованием cvGet2D(), cvGetReal2D()
	for(i=0; irows; i++){
		for(j=0; jcols; j++){
			printf("%.0f ", cvGet2D(matrix, i, j));//cvGetReal2D(matrix, i, j));
		}
		printf("\n");
	}
	printf("-----\n");
	// 3 вариант: прямой доступ к элементам
	for(i=0; irows; i++){
		float* ptr = (float*)(matrix->data.ptr + i*matrix->step);
		for(j=0; jcols; 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 шаг за шагом. Генерация случайных чисел


Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Arduino Bluetooth CraftDuino DIY Google IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд юмор

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение