• 概要
  • FITSファイルは天体観測の結果を保存に使用しているファイルです。
    1981年に標準化されて多くの天体画像処理ソフトウェアが対応しています。
    RAW画像でも、サイズと色数画像情報がヘッダに入っていて1クリックで開くことができます。

  • FITSフォーマット
  • 仕様:
    https://fits.gsfc.nasa.gov/fits_documentation.html
    手引き:https://staff.fukuoka-edu.ac.jp/kanamitu/fits/jdoc/fits_t70a.pdf



  • RAW2FITS

    • Makefile
    • TARGET := $(lastword $(subst /, ,$(abspath $(dir $(lastword $(MAKEFILE_LIST))))))
      
      CC = g++
      
      all: $(TARGET)
      
      $(TARGET): *.c
      	$(CC) -O3 -Wall -fopenmp -o $(TARGET) *.c `pkg-config --cflags --libs opencv4`
      
      clean:
      	rm $(TARGET)
      

    • main.c
    • #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <unistd.h>
      #include <errno.h>
      #include <fcntl.h>
      #include <sys/ioctl.h>
      #include <sys/stat.h>
      #include <sys/time.h>
      #include <iostream>
      
      #define FITS_BLOCK_SIZE 2880
      #define FITS_RECORD_SIZE 80
      
      //ファイル名をコピーして、拡張子 raw を fts に変換します。
      void RawNmae2Fts(char *Fts, char *Raw){
      	strcpy(Fts, Raw);
      	int len=strlen(Fts);
      	strcpy(Fts+len-3,"fts");
      }
      
      //コピーもとのメモリから格納先メモリに保存します。
      //packされた10bit,12bitは16bitに展開してします。
      void CnvertImage(unsigned char *dst, unsigned char *src, int srcSize, int bpp){
      	int j = 0;
      	switch(bpp){
      		case 8:
      		case 16:
      			for(int i = 0; i < srcSize; i++){
      				dst[i] = src[i];
      			}
      			break;
      		case 10:
      			for(int i = 0; i < srcSize; i+=5){
      				dst[j++]  = src[i]    *  4 + (src[i+4] )     % 4;
      				dst[j++]  = src[i]    / 64;
      				dst[j++]  = src[i+1]  * 4 + (src[i+4] >> 2)  % 4;
      				dst[j++]  = src[i+1]  / 64;
      				dst[j++]  = src[i+2]  * 4 + (src[i+4] >> 4 ) % 4;
      				dst[j++]  = src[i+2]  / 64;
      				dst[j++]  = src[i+3]  * 4 + (src[i+4] >> 6 ) % 4;
      				dst[j++]  = src[i+3]  / 64;
      			}
      			break;
      		case 12:
      			for(int i = 0; i < srcSize; i+=3){
      				dst[j++] = src[i]   * 16 + (src[i+2] )     % 16;
      				dst[j++] = src[i]   / 16;
      				dst[j++] = src[i+1] * 16 + (src[i+2] >> 4) % 16;
      				dst[j++] = src[i+1] / 16;
      			}
      			break;
      		default:
      			break;
      	}
      }
      
      void EndianChange(unsigned char *dst, unsigned char *src, int srcSize, int bpp){
      	switch(bpp){
      		case 16:
      		case 10:
      		case 12:
      			for(int i = 0; i < srcSize; i+=2){
      				dst[i] = src[srcSize-i];
      			}
      			break;
      		case 8:
      		default:
      			break;
      	}
      }
      
      int main(int argc, char *argv[]){
      	if(argc < 4){
      		printf("usage:%s Width Height RawFilename\n",argv[0]);
      		exit(EXIT_FAILURE);
      	}
      
      	short width, height;
      	char *RawFilename;
      	char FtsFilename[256];
          struct stat RawFileInfo;
      
      	width  = atoi(argv[1]);
      	height = atoi(argv[2]);
      	RawFilename = argv[3];
      	RawNmae2Fts(FtsFilename, RawFilename);
      
          if (stat(RawFilename, &RawFileInfo) == -1) {
              perror("stat");
              exit(EXIT_FAILURE);
          }
      
      	int BinSize, FtsSize;
      	int RawSize = RawFileInfo.st_size;
      	int bpp = RawSize * 8 / width / height;
      	//変換後のサイズを計算
      	if(bpp == 10){
      		BinSize = RawSize * 2 * 4 / 5;	// 8,8,8,8,(2,2,2,2)
      	}else if(bpp == 12){
      		BinSize = RawSize * 2 * 2 / 3;	// 8,8,(4,4)
      	}else{
      		BinSize = RawSize;
      	}
      
      	if(BinSize % FITS_BLOCK_SIZE > 0)
      		FtsSize = BinSize / FITS_BLOCK_SIZE + 1;
      	else
      		FtsSize = BinSize / FITS_BLOCK_SIZE;
      	FtsSize = FtsSize * FITS_BLOCK_SIZE;
      
      	printf("depth:%dbit\n", bpp);
      	printf("Raw %s %d bytes\n",RawFilename, RawSize);
      	printf("Fts %s %d bytes\n",FtsFilename, FtsSize + FITS_BLOCK_SIZE);
      
      	unsigned char *RawImage = (unsigned char *)malloc(RawSize);
      	unsigned char *BinImage = (unsigned char *)malloc(BinSize);
      	unsigned char *FtsImage = (unsigned char *)malloc(FtsSize);
      	char *FtsHeader = (char *)malloc(FITS_BLOCK_SIZE);
      	if(RawImage == NULL){
              perror("Raw malloc");
              exit(EXIT_FAILURE);
      	}
      	if(FtsImage == NULL){
              perror("Fts malloc");
              exit(EXIT_FAILURE);
      	}
      
      	FILE *fpRaw,*fpFts;
      
      	fpRaw = fopen(RawFilename, "rb");
      	int r = fread(RawImage, sizeof(char), RawSize, fpRaw);
      	printf("Read %d bytes\n", r);
      	fclose(fpRaw);
      
      	CnvertImage(FtsImage, RawImage, RawSize, bpp);
      	EndianChange(FtsImage, BinImage, BinSize, bpp);
      
      	int offset = 0;
      	sprintf(FtsHeader+offset,"%-80s", "SIMPLE  =                   T / Created by raw2fts");
      	offset += FITS_RECORD_SIZE;
      	sprintf(FtsHeader+offset,"BITPIX  = %19d / %-49s", 16, "number of bits per data pixel");
      	offset += FITS_RECORD_SIZE;
      	sprintf(FtsHeader+offset,"NAXIS   = %19d / %-49s", 2, "number of data axes");
      	offset += FITS_RECORD_SIZE;
      	sprintf(FtsHeader+offset,"NAXIS1  = %19d / %-49s", width, "length of data axis 1");
      	offset += FITS_RECORD_SIZE;
      	sprintf(FtsHeader+offset,"NAXIS2  = %19d / %-49s", height, "length of data axis 2");
      	offset += FITS_RECORD_SIZE;
      	sprintf(FtsHeader+offset,"BZERO   = %19d / %-49s", 0, "data range offset");
      	offset += FITS_RECORD_SIZE;
      	sprintf(FtsHeader+offset,"BSCALE  = %19d / %-49s", 1, "lscaling factor");
      	offset += FITS_RECORD_SIZE;
      	sprintf(FtsHeader+offset,"%-80s", "END");
      	for(int i=0; i < FITS_BLOCK_SIZE; i++){
      		if(*(FtsHeader+i) == 0x00)
      			*(FtsHeader+i) = 0x20;
      	}
      
      	int w;
      	fpFts = fopen(FtsFilename, "wb");
      	w = fwrite(FtsHeader, sizeof(char), FITS_BLOCK_SIZE, fpFts);
      	printf("%ld ", FITS_BLOCK_SIZE * sizeof(char));
      	w = fwrite(FtsImage, sizeof(char), FtsSize, fpFts);
      	printf("+ %d bytes\n", w);
      	fclose(fpFts);
      
      	free(FtsHeader);
      	free(FtsImage);
      	free(BinImage);
      	free(RawImage);
      }
      

  • 振り返り
  • アプリによって、エンディアンが逆のものがありますが対応できていません。

  • 更新履歴
  • 2022.12.12 作成