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