Просмотр изображений из формата 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. Надо будет проверить…
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 11

    +5
    А для чего вообще делать «секретные» форматы для метеорологических исследований и выкладывать их в шару?
      +15
      Например, у метеорологов может быть секретное ПО, которое понимает секретные форматы.
        +2
        А какова цель «засекречивании» информации у метеорологов? Если большинство их исследований открыты.
          +4
          Вопрос не в «засекречивании», а в том, что люди пользуются каким-то своим специфическим форматом, который, например, позволяет передавать какую-то дополнительную информацию в нагрузку к изображению.
          • UFO just landed and posted this here
              +2
              Интересно, чем им не понравился FITS -формат?
        +3
        А вот это не описание ли нужного вам формата: www.cgms-info.org/docs/technical-publications/electro-l_hrit_lrit_eng_v1_0662829873B72.pdf?
          0
          Похоже это таки он, но я пока не уверен.
          А вообще, я опирался на инфу о том, что это «секретный» формат и даже не пытался искать по нему документацию.
          В любом случае, большое спасибо.
            +3
            Кавычки в слове «секретный» подразумевали переносное значение. Т.е. никакой он не секретный, просто ПО специализированное, которого не имеется в открытом доступе. А вообще интересный «взлом». Я не сомневался во всемогуществе Хабра :)
            0
            Свой комментарий редактировать тут нельзя? Это печально. :(

            В той документации встретил, на 16-й странице
            COFF и LOFF –определяют позицию окна с областью проекции в
            файле сегмента изображения.

            Похоже они толи забыли это перевести, толи забили.
            +1
            Формат сериализации довольно простой:
            [HEADER> 16b] + [CHUNK> type:U32, size:U32, data:*] *
            За исключением того, что первый чанк измеряется от начала файла (ну или это инопланетная логика разработчиков)

            Служебные чанки содержат русский текст в CP1251 и тучу инфы в даблах, лень разбирать

            Чанк за id 7 — это картинка. Теоретически может быть в разном формате, но встречались только 16битные грейскейлы.
            [HEADER: ?:U32, ?:U32, channels?:U32, width:U32, height:U32, bits?:U32] + raw bytes

            Питоний скрипт в первом приближении парсящий исходник в 8битный PGM:
            gist.github.com/sigman78/5996927#file-l15decode-py
            Без numpy работает медленно.

            Only users with full accounts can post comments. Log in, please.