mrgloom 242 Жалоба Опубликовано November 25, 2013 допустим надо записать большой файл в формате TIFF, но мы не хотим его держать в памяти, а хотим создать например хэдер, а потом туда писать небольшими кусками, возможно ли это как то упростить с помощью OpenCV? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано November 27, 2013 http://www.remotesensing.org/libtiff/libtiff.html по сути надо 2 вещи 1.Возможность создать большую картинку на диске не создавая её в памяти. по идее это можно сделать записав тупо нули построчно тем же TIFFWriteScanline или какими то большими блоками. 2.Затем нужна возможность записывать изображение начиная с произвольного места, т.е. например у нас есть главное изображение (10000,10000) и мы хотим записать изображения (200, 200) начиная с координаты (100,300). Вот такой функциональности я не нашел, если только не построчно считывать(причем строка то по идее может быть большой), потом изменять строку в каком то месте и писать обратно. это можно сделать если создать тупо файл на диске и использовать потом fseek, но тогда надо будет самому руками писать хэдер. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано November 27, 2013 Может с проекциями файла в память хорошо получится? Там при необходимости своп используется. И адресация как в массиве. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано November 28, 2013 а это что? какой нибудь memmap? по большому счёту можно сделать примерно так FILE* f = _tfopen(fileName, _T("wb")); uint64 fileSize = headerSize + (uint64)im.Width() * im.Height() * (grayscale ? 1 : 3); // Allocate file space if( _fseeki64(f, fileSize - 1, SEEK_SET) == 0 && fputc(0, f) != EOF ) { _fseeki64(f, 0, SEEK_SET); // Write header //write img using pointer with offset int64 posPixels = headerSize + dy * width + dx; но проблема в том, что в таком случае надо руками лепить хэдер, а не очень хочется это делать, т.к. там легко ошибиться. возможно можно выцепить структуру хедера из исходников libtiff,но сходу я его не нашел. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано November 28, 2013 почему то файл не модифицируется, такое ощущение, что только первый memset дйествует. int imagelength; TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imagelength); unsigned char* buf = (unsigned char*)_TIFFmalloc(TIFFScanlineSize(tif)); //write dummy zero file memset(buf,0,TIFFScanlineSize(tif)); for (int row = 0; row < imagelength; row++) { TIFFWriteScanline(tif,buf,row); } //modify file for (int row = 0; row < imagelength; row++) { TIFFReadScanline(tif,buf,row); //modify unsigned char* p= buf+10; p[0]=12; p[1]=10; p[3]=3; p[4]=4; //memset(buf,120,TIFFScanlineSize(tif)); TIFFWriteScanline(tif,buf,row); } _TIFFfree(buf); Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано November 28, 2013 похоже, что второй TIFFWriteScanline(tif,buf,row); возвращает ошибку, т.е. не может перезаписать по уже записанному. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано November 28, 2013 решил разобраться с хедером спецификация на 14 странице вроде как его строение, но до конца я его не понял. http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf в начале файла Byte 1 2 3 Hex 49 49 2A Char I I * записал изображение 2 х 3 и 1 х 1 TIFF* tif = TIFFOpen( path, "w"); if( tif != NULL ) { int w= 3; int h= 2; TIFFSetField( tif, TIFFTAG_IMAGEWIDTH, (DWORD)w ); TIFFSetField( tif, TIFFTAG_IMAGELENGTH, (DWORD)h ); // Save RGB image TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB ); TIFFSetField( tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, 3 ); TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, 8 ); TIFFSetField( tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); TIFFSetField( tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); int imagelength; TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imagelength); unsigned char* buf = (unsigned char*)_TIFFmalloc(TIFFScanlineSize(tif)); //write dummy zero file memset(buf,0,TIFFScanlineSize(tif)); for (int row = 0; row < imagelength; row++) { TIFFWriteScanline(tif,buf,row); } _TIFFfree(buf); int nSize = GetFileSize( (HANDLE)TIFFFileno(tif), NULL ); TIFFClose( tif ); } но непонятно как интерпретировать данные 2 x 3 49 49 2a 00 1a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 01 03 00 01 00 00 00 03 00 00 00 01 01 03 00 01 00 00 00 02 00 00 00 02 01 03 00 03 00 00 00 98 00 00 00 03 01 03 00 01 00 00 00 01 00 00 00 06 01 03 00 01 00 00 00 02 00 00 00 11 01 04 00 01 00 00 00 08 00 00 00 12 01 03 00 01 00 00 00 01 00 00 00 15 01 03 00 01 00 00 00 03 00 00 00 17 01 04 00 01 00 00 00 12 00 00 00 1c 01 03 00 01 00 00 00 01 00 00 00 00 00 00 00 08 00 08 00 08 00 1 x 1 49 49 2a 00 0c 00 00 00 00 00 00 00 0a 00 00 01 03 00 01 00 00 00 01 00 00 00 01 01 03 00 01 00 00 00 01 00 00 00 02 01 03 00 03 00 00 00 8a 00 00 00 03 01 03 00 01 00 00 00 01 00 00 00 06 01 03 00 01 00 00 00 02 00 00 00 11 01 04 00 01 00 00 00 08 00 00 00 12 01 03 00 01 00 00 00 01 00 00 00 15 01 03 00 01 00 00 00 03 00 00 00 17 01 04 00 01 00 00 00 03 00 00 00 1c 01 03 00 01 00 00 00 01 00 00 00 00 00 00 00 08 00 08 00 08 00 понял только 2 x 3 49 49 2a Standard header 00 1a => 26 Page offset 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 01 03 непонятно что они значат, но пропускаем 26 байт 00 01 вроде как означает что у нас одна IFD 00 00 00 03 00 00 00 01 01 03 00 01 Directory Entry 12 byte 00 00 00 02 00 00 00 02 01 03 00 03 00 00 00 98 00 00 00 03 01 03 00 01 00 00 00 01 00 00 00 06 01 03 00 01 00 00 00 02 00 00 00 11 01 04 00 01 00 00 00 08 00 00 00 12 01 03 00 01 00 00 00 01 00 00 00 15 01 03 00 01 00 00 00 03 00 00 00 17 01 04 00 01 00 00 00 12 00 00 00 1c 01 03 00 01 00 00 00 01 00 00 00 00 00 00 00 08 00 08 00 08 00 1 x 1 49 49 2a Standard header 00 0c => 12 Page offset 00 00 00 00 00 00 00 0a 00 00 01 03 непонятно что они значат, но пропускаем 12 байт 00 01 вроде как означает что у нас одна IFD 00 00 00 01 00 00 00 01 01 03 00 01 Directory Entry 12 byte 00 00 00 01 00 00 00 02 01 03 00 03 00 00 00 8a 00 00 00 03 01 03 00 01 00 00 00 01 00 00 00 06 01 03 00 01 00 00 00 02 00 00 00 11 01 04 00 01 00 00 00 08 00 00 00 12 01 03 00 01 00 00 00 01 00 00 00 15 01 03 00 01 00 00 00 03 00 00 00 17 01 04 00 01 00 00 00 03 00 00 00 1c 01 03 00 01 00 00 00 01 00 00 00 00 00 00 00 08 00 08 00 08 00 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано November 28, 2013 Вот тут у меня работа с проекциями файлов в память: http://www.compvision.ru/forum/index.php?showtopic=1193 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано November 29, 2013 посмотрел код, такой подход всё равно не избавляет от ручного создания хедера. по коду: один файл который лежит на диске могут просматривать с разными view сразу несколько потоков для этого это сделано? попробовал еще просто прописать настройки но ничего не писать в файл, но думаю, что такой файл неправильный. всего лишь 49 49 2a 00 00 00 00 00 причем что значат нули непонятно. а нет получается как раз валидный просто пустой. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано November 29, 2013 вообщем тут несколько понятней http://www.fileformat.info/format/tiff/egff.htm до конца расшифровать так и не получилось, но зато удалось понять, что после 8 байтового хедера идут сами данные. 2 x 3 49 49 2a 00 =>header 1a 00 00 00 =>offset (4bytes) hex:0000001a => int:26 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 => Image Data 0a 00 00 01 03 00 01 00 =>offset 26 ? для чего какое то выравнивание? 00 00 => 0 tags? 03 00 00 00 => next IFD offset (3 bytes) 01 01 03 =>offset 3 ? 00 01 => 1 tag 00 00 00 02 00 00 00 02 01 03 00 03 =>12 byte tag | WORD:TagId WORD:DataType DWORD:DataCount DWORD:DataOffset 0 tag? | ASCII | 2 00 00 00 98 00 00 00 03 01 03 00 01 00 00 00 01 00 00 00 06 01 03 00 01 00 00 00 02 00 00 00 11 01 04 00 01 00 00 00 08 00 00 00 12 01 03 00 01 00 00 00 01 00 00 00 15 01 03 00 01 00 00 00 03 00 00 00 17 01 04 00 01 00 00 00 12 00 00 00 1c 01 03 00 01 00 00 00 01 00 00 00 00 00 00 00 08 00 08 00 08 00 попробовал модифицировать, но почему то остальной файл бьется. т.е. после создания тиф файла кодом что выше, я решил просто изменить бинарный файл. Нужная секция перезаписывается но при этом бьётся всё остальное почему то. FILE* f = _tfopen(fileName, _T("wb")); if( f != NULL ) { uint64 headerSize = 8; //стандартный размер заголовка 8 байт //test char arr[2*3*3]; //w=3 h=3 RGB memset(arr,123,2*3*3); _fseeki64(f, headerSize, SEEK_SET); fwrite(arr,sizeof(char),sizeof(arr),f); fclose(f); } Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано November 29, 2013 OpenCV, насколько я понимаю, юзает LibTIFF (см. файлы grfmt_tiff.cpp и grfmt_tiff.hpp в папке opencv\modules\highgui\src\), у которого есть исходники может их взять за основу? В частности, там есть файл tiff-3.8.2\libtiff\tif_win32.c в котором определены системно-зависимые функции чтения-записи файла. Если их переопределить, мне кажется можно заставить либу работать с памятью. И еще, в файле tif_read.c есть функция /* * Seek to a random row+sample in a file. */ static int TIFFSeek(TIFF* tif, uint32 row, tsample_t sample) ... ... [/code] Думается эта функция поиска места в файле, где размещается заданный пиксел (хотя подробно не смотрел, могу ошибаться). И тут есть примеры чтения-записи произвольного доступа к содержимому TIFF файла. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано November 29, 2013 нет тут чтение по тайлам, с таким же успехом я мог бы считывать и писать по строкам, но проблема в том, что библиотека не позволяет перезаписывать строку в файле. Т.е. предполагается, что считывается весь массив в память, там модифицируется, и потом записывается целиком обратно, мне же нужна возможность считывать и перезаписывать небольшие куски изображения, не загружая всего в память. есть вроде еще TIFFClientOpen там надо определить самому функции доступа, но как то это сложно по-моему. http://www.libtiff.org/man/TIFFOpen.3t.html и еще что то типа http://telegraphics.com.au/svn/tifflibplugin/trunk/tif_support_win.c я так понимаю там как раз испольщуется CreateFileMapping Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано November 29, 2013 вообщем всё работает надо было FILE* f = _tfopen(fileName, _T("r+b")); правда в таком подходе будут лишние расходы на создание пустого файла на диске + нельзя создавать сжатый файл. разобрался в простейшем случае http://cool.conservation-us.org/bytopic/imaging/std/tiff4.html 2 x 3 49 49 2a 00 => standard tiff header 1a 00 00 00 => offset of 1st IFD from beginning of the file 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 => image data (no compression) 0a 00 => 10 tag fields? 00 01 03 00 01 00 00 00 03 00 00 00 => 256 ImageWidth в конце не офсет а значение просто? 01 01 03 00 01 00 00 00 02 00 00 00 => 257 ImageHeight 02 01 03 00 03 00 00 00 98 00 00 00 => 258 BitsPerSample 03 01 03 00 01 00 00 00 01 00 00 00 => 259 Compression 06 01 03 00 01 00 00 00 02 00 00 00 => 262 PhotometricInterpretation 11 01 04 00 01 00 00 00 08 00 00 00 => 273 StripOffsets 12 01 03 00 01 00 00 00 01 00 00 00 => 274 Orientation 15 01 03 00 01 00 00 00 03 00 00 00 => 277 SamplesPerPixel 17 01 04 00 01 00 00 00 12 00 00 00 => 279 StripByteCounts 1c 01 03 00 01 00 00 00 01 00 00 00 => 284 PlanarConfiguration 00 00 00 00 =>offset to next IFD 08 00 08 00 08 00 =>end of file? 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах