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
