Емельянов Эдуард Владимирович (eddy_em) wrote,
Емельянов Эдуард Владимирович
eddy_em

Category:

Формат FITS и работа с ним в C

Выше я уже писал о работе с FITS-форматом в GNU Octave, однако, что это за формат такой и с чем его едят как работать с ним в своих приложениях на C не упомянул.




Краткое описание формата


Что такое FITS можно прочитать в википедии, поэтому здесь сделаю лишь краткую выжимку. Итак, FITS (Flexible Image Transport System — гибкая система передачи изображений) — цифровой формат файлов используемый в науке для хранения, передачи и редактирования изображений и их метаданных. В основном этот формат используется в астрономии для хранения изображений. Помимо изображений он позволяет хранить табличные данные, а также различные дескрипторы (ключи). Причем в одном файле может быть несколько изображений, таблиц и ключей. Сами дескрипторы хранятся в «шапке» файла в ASCII-формате, что позволяет при помощи less/more/F3 в mc и т.п. получить информацию о содержимом файла, даже не имея средств для просмотра FITS.

Библиотеки и программное обеспечение для работы с FITS


Помимо специализированных средств работы с FITS-файлами, многие существующие графические редакторы могут импортировать изображения из них (правда, теряя метаинформацию, а также ограничивая импорт одним изображением на файл, хотя их там может быть несколько).


Математические пакеты (Matlab, Octave и т.п.) имеют средства для чтения/записи FITS-файлов (но тоже эти средства зачастую ограниченны); естественно, для астрофизиков есть и специальное ПО (например, MIDAS, Iraf и т.п.), позволяющее полноценно работать с разнообразным содержимым FITS-файлов.


Для работы в своих проектах можно выбрать одну из множества библиотек, позволяющих работать с FITS-файлами (а можно и свой "велосипед" сделать). В языке C наиболее популярной (и полноценной) является библиотека CFITSIO, вкратце о ней я и расскажу.

Краткое описание CFITSIO


На основе примеров работы с cfitsio можно понять основные функции библиотеки. Для работы с файлами cfitsio представляет функции чтения и записи, позволяющие работать со сжатыми файлами, задавать маски файлов (а также - области, необходимые для считывания) в имени файла. Маской в имени файла можно также задать необходимые таблицы и/или ключи для импорта, а также выполнить элементарную правку ключей.


При работе с FITS-файлами следует помнить, что наибольшее количество одновременно открытых файлов равно 25 (оно определяется значением константы NIOBUF при компиляции библиотеки). Максимальное количество расширений (блоков с данными - изображениями, таблицами, ключами), с которым может работать библиотека, составляет 1000 для одного файла (определяется константой MAXHDU). Библиотека не работает с файлами, чей размер превышает 2.1ГБ. Также библиотека не работает с данными, имеющими разрядность выше 32 бит (в принципе, это понятно: современные АЦП в светоприемной аппаратуре обычно имеют разрядность в лучшем случае 16 бит).


Библиотека позволяет одновременно несколько раз открыть один и тот же файл (например, для параллельной работы с шапкой, таблицами и изображениями в файле). При работе с файлами, чья «шапка» содержит несколько разделов с ключами, cfitsio может работать лишь с одним из разделов, поэтому если одновременно нужно брать данные из нескольких, необходимо будет открыть файл нужное количество раз.


При чтении и записи изображений cfitsio автоматически преобразует значения по значениям стандартных ключей BSCALE и BZERO:

output value = (FITS value) * BSCALE + BZERO
FITS value = ((input value) - BZERO) / BSCALE


Работая с ключами, следует помнить, что стандарт FITS вносит ограничение на размеры ключа: весь ключ (имя, значение, комментарий) не может иметь длину больше 80 байт; имя ключа не может превышать 8 байт. Если необходимо вписать, например, более длинное имя ключа, или же имя ключа должно содержать непотребные нестандартные символы (пробелы, а также символы, не являющиеся латинскими буквами или символом подчеркивания), перед таким ключом ставится префикс HIERARCH. В этом случае максимальная длина ключа составляет 67 символов (однако, при этом некуда будет вписывать значение переменной и комментарий). CFITSIO прозрачно работает с ключами и читает/записывает даже такие нестандартные ключи. Если при записи ключа возникает какая-то ошибка (например, ключ+значение+комментарий не вписываются в 80 байт, cfitsio возвращает ошибку). Кстати, 80 байт - это ограничение на всю строку, а т.к. имя ключа обычно отделено от значения знаком равенства, окруженным пробелами, а комментарий — косой чертой, окруженной пробелами, полный ключ со значением и комментарием суммарно может занимать не более 74 байт. Т.к. 8 байт занимает сам ключ (кроме указанного выше исключения), на значение и комментарий остается 66 байт.

Использование CFITSIO в своих проектах


Не мудрствуя лукаво, опишу работу с библиотекой на примере своих «велосипедов»: takepic — CLI-интерфейс для работы с камерой FLI Proline 9000, а также многострадальной fitsview — смотрелки FITS-файлов с возможностями простейшего редактирования (все никак не допилю модуль обработки гартманнограмм, да и вообще что-то подзабыл я о нем).

В takepic я взял за основу пример из SDK разработчиков камеры, добавив в него нужный мне функционал. Для упрощения диагностирования ошибок при работе с библиотекой cfitsio используются обертки:

#define TRYFITS(f, ...)						\
do{	int status = 0;							\
	f(__VA_ARGS__, &status);				\
	if (status){							\
		fits_report_error(stderr, status);		\
		return -1;}						\
}while(0)
#define WRITEKEY(...)						\
do{ int status = 0;							\
	fits_write_key(__VA_ARGS__, &status);	\
	if(status) fits_report_error(stderr, status);	\
}while(0)

Если при выполнении функций cfitsio возвращает ошибку, генерируется сообщение об ошибке и внешняя функция, в которой произошла ошибка, завершается с возвращением -1. При записи ключа в случае ошибки просто генерируется сообщение об ошибке (т.к. это не так критично).


Сама функция записи FITS-файлов довольно проста: в качестве аргументов она принимает имя файла (filename), размеры полученного изображения (width, height) и указатель на массив с данными изображения (data). Так как изображение характеризуется двумя осями, необходимо создать массив из двух чисел, в который поместить ширину и высоту изображения (этот массив, naxes, мы передадим функции создания области с изображением в FITS-файле). Итак, предварительная подготовка:


long naxes[2] = {width, height};
fitsfile *fp;
TRYFITS(fits_create_file, &fp, filename);
TRYFITS(fits_create_img, fp, USHORT_IMG, 2, naxes);

Я создаю область изображения с типом unsigned short (т.к. для работы с камерой FLI его вполне хватает), однако, можно указать и другой тип изображения — cfitsio автоматически осуществит преобразование типов (главное — помнить, что преобразование из int в uint скорее всего, закончится ошибкой, если входная интенсивность будет превышать допустимый уровень в выходной).


Далее можно заполнить «шапку» файла необходимыми данными, например:


WRITEKEY(fp, TSTRING, "FILE", filename, "Input file original name");
WRITEKEY(fp, TSTRING, "DETECTOR", camera, "Detector model");
WRITEKEY(fp, TDOUBLE, "TEMPBODY", &t_ext, "Camera body temperature at exp. end (degr C)");
WRITEKEY(fp, TDOUBLE, "EXPTIME", &tmp, "actual exposition time (sec)");
WRITEKEY(fp, TSTRING, "OBJECT", objname, "Object name");

и т.д., и т.п. (помимо основных сведений я вписываю в «шапку» еще сведения о погодных условиях, координатах объекта и т.п.).


После заполнения «шапки» мы записываем изображение и закрываем файл: все готово!


TRYFITS(fits_write_img, fp, TUSHORT, 1, width * height, data);
TRYFITS(fits_close_file, fp);



В fitsview мне нужно было не только записывать, но и читать файлы. Я использовал все те же макросы-обертки, что и в takepic, но добавил еще одну:

#define FITSFUN(f, ...)						\
do{	gboolean status = FALSE;				\
	int ret = f(__VA_ARGS__, &status);		\
	if(ret || status)							\
		fits_report_error(stderr, status);		\
}while(0)

чтобы в некритических случаях не завершать работу вызывавшей функции.


Функция записи файла практически ничем не отличается от takepic, разве что ключи пишутся в формате «карты» — уже готовой строки (т.к. ключи имеют разные форматы и хранятся в GtkTree).


Чтение файла производится с параллельной обработкой ключей (т.к. некоторая информация из ключей используется в характеристиках изображения), кроме того, ключи сохраняются в GtkTree для возможности редактирования.
Итак, основные функции для чтения файла включают в себя открытие файла, получение количества «шапок» в файле, перемещение к первой, считывание и обработка ключей


fitsfile *fp; // gchar *filename, IMAGE *image - аргументы функции 
int dtype, j, hdunum, keynum, morekeys;
char keyname[FLEN_KEYWORD], keyval[FLEN_VALUE];
char keycomment[FLEN_COMMENT], cdtype[32];
TRYFITS(fits_open_file, &fp, filename, READWRITE);
FITSFUN(fits_get_num_hdus, fp, &hdunum);
FITSFUN(fits_get_hdrpos ,fp, &keynum, &morekeys);
for (j = 1; j <= keynum; j++){
	FITSFUN(fits_read_keyn, fp, j, keyname, keyval, keycomment);
	dtype = guess_type(keyval, cdtype);
	add_key(image, cdtype, keyname, keyval, keycomment, dtype);
}

Функция guess_type пытается определить тип данных: анализируется вид данных и последовательно вызываются функции преобразования строки в разные типы (double, long long). Если данные не подходят к типам double или long long, проверяется еще — не являются ли они комплексным числом. Если и комплексным не является, тип считается строковым.


Если файл содержит больше одной «шапки», считываются ключи и из других. При записи cfitsio автоматически разобьет ключи на нужное количество «шапок» (если ключей будет слишком много).
Далее мы получаем параметры изображения, считываем его (сразу преобразуя средствами cfitsio в тип float) и закрываем файл.


TRYFITS(fits_get_img_param, fp, 4, &dtype, &naxis, naxes);
TRYFITS(fits_read_img, fp, TFLOAT, 1, sz, &nullval, image->data, &stat);
TRYFITS(fits_close_file, fp);


Итак, работа с FITS-файлами при помощи cfitsio достаточно проста.
Tags: c, fits
Subscribe

Recent Posts from This Journal

  • Чем бы таким заменить STM32F072C8T6?

    Полез сейчас на али цены посмотреть, а там… В среднем уже по 600-700 рублей за штучку просят! Вообще охамели. И это - гарантированно БУшные ведь!.. А…

  • Понаблюдал, блин!

    Опять у нас что-то с сетью поломали. Хотел было протестировать, как наша подвесная часть оптоволоконного спектрографа работает, а из дома связь с…

  • Релюшки на CAN-шине

    Закончил с прошивкой для новой железяки. Как "наследница" USB-CAN переходника, она умеет все то же самое + несколько специфичных вещей (опрос…

promo eddy_em august 17, 2019 12:33 3
Buy for 10 tokens
Юра намедни напечатал корпус для хронометра. Для первого блина получилось неплохо: И еще немного фотографий:
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic
  • 0 comments