...

воскресенье, 14 июля 2013 г.

[Из песочницы] Просмотр изображений из формата L15 спутника «Электро-Л»

Здравствуйте, уважаемые Хабарюзеры.

Как известно, фотографии со спутника «Электро-Л» выкладываются на FTP в двух форматах.

Один — общеизвестный jpg, который нам не интересен.

Второй, как писал Zelenyikot


«секретный» формат доступный только метеорологам. В сети нет ПО, которое позволяет его открыть и посмотреть. Правда меня заверили, что с точки зрения картинки, там то же самое, что и на JPEG, а дополнительная информация только текстом – всякие там, высоты, температуры, скорости…





Вот его мы и попытается прочитать.

Дополнительную информацию у меня прочитать не получилось, зато картинка вполне читаема, и она несколько отличается от той, что в JPG, по количеству бит на единственный канал. Если в JPG их 8 (256 оттенков серого), то в L15 их 10 (1024 оттенка серого).


Если изображение в файле не зашифровано, то в нём должны встречаться размеры изображения. Будем надеяться, что оно не зашифровано.

Размеры изображения у фотографий со спутника в формате jpg 2784x2784. Переведя 2784 в HEX получим 0A E0. Эту последовательность надо перевернуть и искать E0 0A

Нашлось e0 0a 00 00 e0 0a 00 00 10 00

Сгруппировав эти данные по 4 байта и отобразив как десятичное число получим 2784 2784 16


От конца блока, вставленного чуть выше до конца файла 0xEC8800 (15501312) байт.

15501312/(2784*2784)=2. Из этих результатов предположим, что один пиксель описывается двумя байтами.


Но прежде чем пытаться прочитать изображение надо понять, как искать место, с которого оно начинается.

Два дня поисков в файлах L15 либо прямого адреса области с изображением или близкого к нему участка, либо смещения на этот адрес к успеху не привели.

Поэтому, будем искать этот участок «в лоб», читатя файл бит за битом до тех пор, пока не встретится число 2784 или 11136(это разрешение изображений от каналов R G B).

После чего проверяем, повторяется ли это число ещё раз, и, если оно повторяется, проверяем, равняется ли следующее число 16.

Если всё верно, поздравляю, мы нашли начало картинки.



long Find_Image_Pos(FILE *EL_Data,int *res_out)
{
unsigned int int_data;
int resolution;
unsigned long filepos;
filepos=0;
while(!feof(EL_Data))
{
fseek(EL_Data,filepos,SEEK_SET);
fread((void*)&int_data,sizeof(unsigned int),1,EL_Data);
if(int_data==2784||int_data==11136)
{
resolution=int_data;
fread((void*)&int_data,sizeof(unsigned int),1,EL_Data);
if(int_data==resolution)
{
fread((void*)&int_data,sizeof(unsigned int),1,EL_Data);
if(int_data==16)
{
*res_out=resolution;
return ftell(EL_Data);
}
}
}
filepos++;
}
return 0;
}




Метод костыльный, но пока ошибок не давал.

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



Будем читать файл по 2 байта и записывать считанное значение в файл.
void Save_Image(FILE *EL_Data,FILE *EL_Image,long pos,int resolution)
{
#ifdef P5
char header[50];
sprintf(header,"P5\n%i %i\n1024\n",resolution,resolution);
fwrite(&header,strlen(header),1,EL_Image);
#else
fprintf(EL_Image,"P2\n%i %i\n1024\n",resolution,resolution);
#endif
int progress=-1;

int max=0;
int x=0,y=0;
int pixel=0;
fseek(EL_Data,pos,SEEK_SET);
for(y=0;y<resolution;y++)
{
if(progress<(y*100/resolution))
{
progress=(y*100/resolution);
cout<<progress<<"%"<<endl;
}

for(x=0;x<resolution;x++)
{
fread(&pixel,2,1,EL_Data);
#ifdef P5
fwrite(&pixel,1,1,EL_Image);
#else
fprintf(EL_Image,"%i\n",pixel);
#endif
if(pixel>max)
max=pixel;
}
}
cout<<"100 %"<<endl;
cout<<"max="<<max<<endl;

}




В формате P5, пиксели, яркость которых больше 255 (то есть больше 1-го байта) становятся чёрными.

Результат:

P2:



P5


И на последок код, который соеденяет вышенаписанные функции



#include <iostream>;
#include <stdio.h>
#include <tchar.h>
#include <stdlib.h>
#include <windows.h>
//#define P5

using namespace std;
long Find_Image_Pos(FILE *EL_Data,int *res_out);
void Save_Image(FILE *EL_Data,FILE *EL_Image,long pos,int resolution);

int _tmain(int argc, _TCHAR* argv[])
{

FILE *EL_Data,*EL_Image;
if(argc==1)
return 0;
EL_Data=_wfopen(argv[1],L"rb");
if(!EL_Data)
return 0;

wchar_t out_file[300];
#ifdef P5
wsprintf(out_file,L"%s.P5.pgm",argv[1]);
EL_Image=_wfopen(out_file,L"wb");
#else
wsprintf(out_file,L"%s.P2.pgm",argv[1]);
EL_Image=_wfopen(out_file,L"wt");
#endif
if(!EL_Image)
return 0;

int resolution=0;
long pos=Find_Image_Pos(EL_Data,&resolution);
if(!pos)
return 0;

Save_Image(EL_Data,EL_Image,pos,resolution);

fclose(EL_Image);
fclose(EL_Data);
return 0;
}


Изображения с глубиной цвета 10 бит на канал можно использовать для создания HDRi изображений. Впрочем, это уже тема отдельного топика.


UPD: Есть подозрение, что текстовые данные хранятся в формате wchar. Надо будет проверить…


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends: 'You Say What You Like, Because They Like What You Say' - http://www.medialens.org/index.php/alerts/alert-archive/alerts-2013/731-you-say-what-you-like-because-they-like-what-you-say.html


Комментариев нет:

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