Перейти к содержимому
Compvision.ru
mrgloom

запись большого файла в TIFF

Recommended Posts

допустим надо записать большой файл в формате TIFF, но мы не хотим его держать в памяти, а хотим создать например хэдер, а потом туда писать небольшими кусками, возможно ли это как то упростить с помощью OpenCV?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

http://www.remotesensing.org/libtiff/libtiff.html

по сути надо 2 вещи

1.Возможность создать большую картинку на диске не создавая её в памяти.

по идее это можно сделать записав тупо нули построчно тем же TIFFWriteScanline или какими то большими блоками.

2.Затем нужна возможность записывать изображение начиная с произвольного места, т.е. например у нас есть главное изображение

(10000,10000) и мы хотим записать изображения (200, 200) начиная с координаты (100,300).

Вот такой функциональности я не нашел, если только не построчно считывать(причем строка то по идее может быть большой),

потом изменять строку в каком то месте и писать обратно.

это можно сделать если создать тупо файл на диске и использовать потом fseek, но тогда надо будет самому руками писать хэдер.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Может с проекциями файла в память хорошо получится?

Там при необходимости своп используется.

И адресация как в массиве.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

а это что? какой нибудь 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,но сходу я его не нашел.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

почему то файл не модифицируется, такое ощущение, что только первый 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);

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

похоже, что второй TIFFWriteScanline(tif,buf,row); возвращает ошибку, т.е. не может перезаписать по уже записанному.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

решил разобраться с хедером

спецификация на 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Вот тут у меня работа с проекциями файлов в память:

http://www.compvision.ru/forum/index.php?showtopic=1193

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

посмотрел код, такой подход всё равно не избавляет от ручного создания хедера.

по коду: один файл который лежит на диске могут просматривать с разными view сразу несколько потоков для этого это сделано?

попробовал еще просто прописать настройки но ничего не писать в файл, но думаю, что такой файл неправильный.

всего лишь

49 49 2a 00 00 00 00 00

причем что значат нули непонятно.

а нет получается как раз валидный просто пустой.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

вообщем тут несколько понятней

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);

}

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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 файла.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

нет тут чтение по тайлам,

с таким же успехом я мог бы считывать и писать по строкам, но проблема в том, что библиотека не позволяет перезаписывать строку в файле.

Т.е. предполагается, что считывается весь массив в память, там модифицируется, и потом записывается целиком обратно, мне же нужна возможность считывать и перезаписывать небольшие куски изображения, не загружая всего в память.

есть вроде еще TIFFClientOpen там надо определить самому функции доступа, но как то это сложно по-моему.

http://www.libtiff.org/man/TIFFOpen.3t.html

и еще что то типа

http://telegraphics.com.au/svn/tifflibplugin/trunk/tif_support_win.c

я так понимаю там как раз испольщуется CreateFileMapping

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

вообщем всё работает

надо было

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?

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×