В прошлый раз я рассказал, как подключить библиотеку для работы с файлами 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 , а это неудобно и долго.
Ну и вот отчёт:
![]() |
| Было изображение |
![]() |
| Стало изображение |




Комментариев нет:
Отправить комментарий