В прошлый раз я рассказал, как подключить библиотеку для работы с файлами FITS к g++ в линукс.
Сегодня мы займёмся непосредственно чтением картинки, небольшим её редактированием и записью в новую картинку. На данном этапе мы не будем учитывать сотни возможностей формата Fits(большое кол-во слоев изображения, дополнительные параметры , многомерные таблицы и т.д. ). В качестве преобразования изображения, мы возьмём инвертирование. Мы просто составим программу вот такого алгоритма
Отразим алгоритм в функции main:
Теперь приступим к разбору каждого блока:
Чтение картинки.
В документации есть очень не плохой пример для чтения картинки и её атрибутов, но они, всё-же, уж очень изощренно и не оправдано пользуются библиотекой std. Это не особо нужно для данной-конкретной задачи. Поэтому, разобрав их пример, я взял только самое необходимое и составил свою функцию чтения.
Как видите, нет абсолютно ничего сложного. Да, я не спорю - я не рассматриваю многих тонкостей, что выявлены в стандартном примере. Для начала, вам достаточно знать - как читать файл fits и занести его в массив, а для этого не нужно быть гуру в std и умножать 2 числа через пень-колоду. Обратите внимание так-же на то, что я считываю только данные изображения - если в этом файле есть дополнительная информация, она считана не будет. В то-же время, я оставил лазейку - "умный" указатель pFits объявлен в глобальном контексте, а значит хранит файл целиком и после завершения функции чтения. Это дает возможность считать необходимую информацию как-нибудь потом.
Изменение картинки
За это у меня отвечает функция dataChange(). Как я уже говорил, я буду инвертировать картинку( то что было тёмным станет светлым и наоборот). Картинка у нас состоит из множества short значений( это было выявлено эмпирический методом научного тыка ). FITS нас не обязывает писать в short, в чём хочешь в том и пиши. Мне было странно, что не используется unsigned char с его 1 байтом. Я привык к градуировке [0 - 255] и мне кажется - 2 байта на 1 чёрно-белый пиксель это расточительно. Я ещё не понял всю глубину данного выбора. Но short так short- не принципиально...
Инверсия одного значения - это разница между максимально допустимым и текущим значением.
Где M - максимально допустимое значение A[i]
Функция преобразования в 2 строки,вот она:
Запись новой картинки
Последний этап нашего пути - запись измененных данных в новый файл fits.
Не смотря на ужасающие строки стандартных примеров, ничего сложного в этом нет.
После некоторого отсева даю вам необходимую выжимку:
В документации сказано, что этот конструктор FITS создает файл с данным именем, если его не было, но если файл есть - бросится исключение, которое я ловлю блоком catch.
Код, как, мне кажется, понятен, да и прокомментирован. Но на всякий случай расскажу, что тут делается.
В массив naxes заносится размерность картинки, которая хранится в соответствующих полях объекта image .Это нужно для конструктора.
Далее, мы просто вычисляем кол-во элементом путём умножения высоты матрицы на размерность 1 строки, и записываем это кол-во short-ов в объект из массива, который мы создали на этапе "Чтение картинки" и модифицировали на этапе "Изменение картинки" начиная с 1 short-а.
Вот весь исходный код программы.
Ниже приведен Makefile для этой программы. Он работает при условии, что установка CCfits прошла так, как написано в прошлой моей статье.
Использование программы
Ну как-же без отчёта?
Выполняем:
$make
$./FitsExamp input.fts outfut.fts
При этом должен существовать файл input.fts и не должно существовать файла outfut.fts .
Для просмотра крайне советую вот эту программу http://hea-www.harvard.edu/RD/ds9/site/Download.html . Распространяется в виде 1 исполняемого файла - батарейки в комплекте. Удобно просматривать fits файлы, без нее с fits справляется только gimp , а это неудобно и долго.
Ну и вот отчёт:
Отразим алгоритм в функции main:
int main(int argc, char *argv[]) { if(argc>=3){ char * input = argv[1]; char * output = argv[2]; readFITSImage(input); dataChange(); writeFITSImage(output); return 0; } cout<<"Not enough parameters"<<endl; cout<<"Usage: \n\t FitsExamp inputfile outputfile"<<endl; }
Теперь приступим к разбору каждого блока:
Чтение картинки.
В документации есть очень не плохой пример для чтения картинки и её атрибутов, но они, всё-же, уж очень изощренно и не оправдано пользуются библиотекой std. Это не особо нужно для данной-конкретной задачи. Поэтому, разобрав их пример, я взял только самое необходимое и составил свою функцию чтения.
void readFITSImage(char *path){ // read FITS file from path to pFits and put image data to contents; FITS::setVerboseMode(true); pFits.reset(new FITS(path,Read,true)); image = &pFits->pHDU();// get main image from file image->readAllKeys();//read Keys image->read(contents); // read DATA to valarray }
Как видите, нет абсолютно ничего сложного. Да, я не спорю - я не рассматриваю многих тонкостей, что выявлены в стандартном примере. Для начала, вам достаточно знать - как читать файл fits и занести его в массив, а для этого не нужно быть гуру в std и умножать 2 числа через пень-колоду. Обратите внимание так-же на то, что я считываю только данные изображения - если в этом файле есть дополнительная информация, она считана не будет. В то-же время, я оставил лазейку - "умный" указатель pFits объявлен в глобальном контексте, а значит хранит файл целиком и после завершения функции чтения. Это дает возможность считать необходимую информацию как-нибудь потом.
Изменение картинки
За это у меня отвечает функция dataChange(). Как я уже говорил, я буду инвертировать картинку( то что было тёмным станет светлым и наоборот). Картинка у нас состоит из множества short значений( это было выявлено эмпирический методом научного тыка ). FITS нас не обязывает писать в short, в чём хочешь в том и пиши. Мне было странно, что не используется unsigned char с его 1 байтом. Я привык к градуировке [0 - 255] и мне кажется - 2 байта на 1 чёрно-белый пиксель это расточительно. Я ещё не понял всю глубину данного выбора. Но short так short- не принципиально...
Инверсия одного значения - это разница между максимально допустимым и текущим значением.
Где M - максимально допустимое значение A[i]
Максимально допустимое значение short - 2 байта или 32767. По хорошему - каждый раз определять его функцией sizeof(short), а учитывая то, что в программе я не привязывался к определённому типу данных и объявил макрос #define DATATYPE short, буду вычислять это значение
sizeof(DATATYPE)
Функция преобразования в 2 строки,вот она:
void dataChange(){ for(int i = 0;i<contents.size();i ) //inverse contents[i]= sizeof(DATATYPE)-contents[i]; }
Запись новой картинки
Последний этап нашего пути - запись измененных данных в новый файл fits.
Не смотря на ужасающие строки стандартных примеров, ничего сложного в этом нет.
После некоторого отсева даю вам необходимую выжимку:
void writeFITSImage(char* path){ long naxis=2; long naxes[2] = { image->axis(0), image->axis(1) }; try{ pFits.reset( new FITS(path , SHORT_IMG , naxis, naxes ) ); } catch(FITS::CantCreate){ cout<<"Output file exists"<<endl; } long& vectorLength = naxes[0];// more useful names long& numberOfRows = naxes[1];// of variables long n = vectorLength*numberOfRows; image = &pFits->pHDU(); image->write(1,n,contents); cout<<"Write OK"<<endl; }
В документации сказано, что этот конструктор FITS создает файл с данным именем, если его не было, но если файл есть - бросится исключение, которое я ловлю блоком catch.
Код, как, мне кажется, понятен, да и прокомментирован. Но на всякий случай расскажу, что тут делается.
В массив naxes заносится размерность картинки, которая хранится в соответствующих полях объекта image .Это нужно для конструктора.
Далее, мы просто вычисляем кол-во элементом путём умножения высоты матрицы на размерность 1 строки, и записываем это кол-во short-ов в объект из массива, который мы создали на этапе "Чтение картинки" и модифицировали на этапе "Изменение картинки" начиная с 1 short-а.
Вот весь исходный код программы.
#include <CCfits> using namespace CCfits; using namespace std; #define DATATYPE short valarray<DATATYPE>contents; // array that contains file data std::auto_ptr<FITS> pFits;// FITS File Pointer PHDU* image; // sorce of image void readFITSImage(char *path){ // read FITS file from path to pFits and put image data to contents; FITS::setVerboseMode(true); pFits.reset(new FITS(path,Read,true)); image = &pFits->pHDU();// get main image from file image->readAllKeys();//read Keys image->read(contents); // read DATA to valarray } void dataChange(){ for(int i = 0;i<contents.size();i ) //inverse contents[i]= sizeof(DATATYPE)-contents[i]; } void writeFITSImage(char* path){ long naxis=2; long naxes[2] = { image->axis(0), image->axis(1) }; try{ pFits.reset( new FITS(path , SHORT_IMG , naxis, naxes ) ); } catch(FITS::CantCreate){ cout<<"Output file exists"<<endl; } long& vectorLength = naxes[0];// more useful names long& numberOfRows = naxes[1];// of variables long n = vectorLength*numberOfRows; image = &pFits->pHDU(); image->write(1,n,contents); cout<<"Write OK"<<endl; } int main(int argc, char *argv[]) { if(argc>=3){ char * input = argv[1]; char * output = argv[2]; readFITSImage(input); dataChange(); writeFITSImage(output); return 0; } cout<<"Not enough parameters"<<endl; cout<<"Usage: \n\t FitsExamp inputfile outputfile"<<endl; }
Ниже приведен Makefile для этой программы. Он работает при условии, что установка CCfits прошла так, как написано в прошлой моей статье.
CXX = g CFLAGS =-Wall -O3 INCPATH = -I/usr/local/include/CCfits -I/usr/local/lib/cfitsio/include -I. LIBS = -L/usr/local/lib -lCCfits SOURCES = FitsExamp.cpp OBJECTS = FitsExamp.o TARGET = FitsExamp RM =rm -f all:$(TARGET) $(RM) output.fts $(TARGET): $(OBJECTS) $(CXX) -o $(TARGET) $(OBJECTS) $(LIBS) $(OBJECTS): $(SOURCES) $(CXX) -c $(INCPATH) -o $(OBJECTS) $(SOURCES) clean: $(RM) $(OBJECTS) $(TARGET)
Использование программы
Ну как-же без отчёта?
Выполняем:
$make
$./FitsExamp input.fts outfut.fts
При этом должен существовать файл input.fts и не должно существовать файла outfut.fts .
Для просмотра крайне советую вот эту программу http://hea-www.harvard.edu/RD/ds9/site/Download.html . Распространяется в виде 1 исполняемого файла - батарейки в комплекте. Удобно просматривать fits файлы, без нее с fits справляется только gimp , а это неудобно и долго.
Ну и вот отчёт:
Было изображение |
Стало изображение |
Комментариев нет:
Отправить комментарий