• 概要
  • SERファイルは、元は lucam recorder software の出力ファイルだったようです。(IDにその名残があります。)
    天体の16bit動画記録のデファクトスタンダードのファイルとなって、惑星の記録に使っています。
    RaspberryPiCameraで撮影した惑星を従来の方法で処理するためにSERファイルに保存するようにしました。

  • SERフォーマット
  • 仕様:
    https://free-astro.org/index.php/File:SER_Doc_V3b.pdf
    ヘッダの例



    全体


  • 書き出し

    • ser.h
    • //Ser
      #define SER_BLOCK_SIZE          178
      #define SER_FILEID_SIZE         14
      #define SER_LUID_SIZE           4
      #define SER_COLORID_SIZE        4
      #define SER_LITTLEENDIAN_SIZE   4
      #define SER_WIDTH_SIZE          4
      #define SER_HEIGHT_SIZE         4
      #define SER_PIXELDPTH_SIZE      4
      #define SER_FRAMES_SIZE         4
      #define SER_OBSERVER_SIZE       40
      #define SER_INSTRUMENT_SIZE     40
      #define SER_TELESCOPE_SIZE      40
      #define SER_DATETIME_SIZE       8
      #define SER_DATETIMEUTC_SIZE    8
      #define SER_FRAMES_OFFSET       38
      #define SER_DATETIME_OFFSET     162
      #define SER_DATETIMEUTC_OFFSET  170
      
      int InitSer(int bpp, int width, int height, char *fname);
      int WriteSERHeader(char *wfname);
      int WriteSERImage(unsigned char *BinImage, int BinSize, int bpp);
      int CloseSER();
      

    • ser.c
    • /*====================================================================*
       * ser.c
       *
       * Copyright(c) 2022 TsukiTsuki. (http://tsukitsuki.tips/)
       *====================================================================*/
      #include <stdio.h>
      #include <unistd.h>
      #include <time.h>
      #include <sys/time.h>
      #include <sys/statvfs.h>
      #include <string.h>
      #include <math.h>
      #include <regex.h>
      #include "fits.h"
      #include "ser.h"
      
      unsigned char *SerImage;
      char *SerHeader;
      char sensorname2[18];
      int FrameCount;
      
      /*--------------------------------------------------------------------*
       *  SERファイル保存用の各データを初期化する
       *--------------------------------------------------------------------*/
      int InitSer(int bpp, int width, int height, char *fname)
      {
          GetSensorName(fname, sensorname2);
      
          SerHeader = (char *)malloc(SER_BLOCK_SIZE);
          if(SerHeader == NULL){
              perror("malloc error");
              exit(EXIT_FAILURE);
          }
      
          char *SHp = SerHeader;
          for(int i=0; i<178; i++) {
              *SHp++ = 0;
          }
      
          int offset = 0;
          sprintf(SerHeader+offset,"LUCAM-RECORDER");
          offset += SER_FILEID_SIZE;
          offset += SER_LUID_SIZE;
          *(int *)(SerHeader+offset) = 8; //RGGB
          offset += SER_COLORID_SIZE;
          offset += SER_LITTLEENDIAN_SIZE;
          *(int *)(SerHeader+offset) = width;
          offset += SER_WIDTH_SIZE;
          *(int *)(SerHeader+offset) = height;
          offset += SER_HEIGHT_SIZE;
          *(int *)(SerHeader+offset) = bpp;
          offset += SER_PIXELDPTH_SIZE;
          offset += SER_FRAMES_SIZE;
          sprintf(SerHeader+offset,"%-40s", "Observer");
          offset += SER_OBSERVER_SIZE;
          sprintf(SerHeader+offset,"%-40s", sensorname2);
          offset += SER_INSTRUMENT_SIZE;
          sprintf(SerHeader+offset,"%-40s", "Telescope");
          offset += SER_TELESCOPE_SIZE;
          offset += SER_DATETIME_SIZE;
          offset += SER_DATETIMEUTC_SIZE;
      
          return 0;
      }
      
      FILE *fpSer;
      FILE *fpTS;
      struct timeval tv;
      
      /*--------------------------------------------------------------------*
       *  SERファイルにヘッダを書き出す
       *--------------------------------------------------------------------*/
      int WriteSERHeader(char *wfname)
      {
          FrameCount = 0;
          fpSer = fopen64(wfname, "wb");
          fwrite(SerHeader, sizeof(char), SER_BLOCK_SIZE, fpSer);
          printf("Rec Start.\n");
      
          // タイムスタンプを一旦テンポラリファイルに記録
          fpTS = fopen("/tmp/timestamp.bin", "wb");
      
          return 0;
      }
      
      /*--------------------------------------------------------------------*
       *  SERファイルに画像を書き出す
       *--------------------------------------------------------------------*/
      int WriteSERImage(unsigned char *BinImage, int BinSize, int bpp)
      {
          gettimeofday(&tv, NULL);
          
      //    EndianChange(SerImage, BinImage, BinSize, bpp);
          fwrite(BinImage, sizeof(char), BinSize, fpSer);
          FrameCount++;
          fwrite(&tv, sizeof(tv), 1, fpTS);        // 8bytes
      
          return 0;
      }
      
      /*--------------------------------------------------------------------*
       *  日付から100ナノ秒単位に変換
       *--------------------------------------------------------------------*/
      int64_t date2timestamp(int year, int month, int day, int hour, int minute, int second, int microsec){
          int monthdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; //平年の月の日数
      
          // グレゴリオ暦で年を日数に変換
          year += 1900;
          int year2day = (year -1) *365 + year/400 - year/100 + year/4;
          
          // 年内の日数を計算
          int mon2day;
          for(int i=0; i < month; i++){
              mon2day += monthdays[i];
          }
          int days = year2day + mon2day + day -1;
      
          // 秒に換算
          int64_t seconds = ((int64_t)hour *60 + (int64_t)minute) *60 + (int64_t)second;
          seconds += (int64_t)days * 24 *60 *60;
      
          // 100ナノ秒に換算
          return (seconds * 1000 * 1000 + (int64_t)microsec) * 10;
      }
      
      /*--------------------------------------------------------------------*
       *  SERファイルに画像を終了する
       *--------------------------------------------------------------------*/
      int CloseSER()
      {
          struct tm *ts;
          int64_t TimeDate;
      
          // フレーム数を記録
          fseek(fpSer, SER_FRAMES_OFFSET, SEEK_SET);
          fwrite(&FrameCount, 1, sizeof(int), fpSer);
      
          fclose(fpTS);
      
          // タイムスタンプの記録ファイルを開く
          fpTS = fopen("/tmp/timestamp.bin", "rb");
          fread(&tv, sizeof(tv), 1, fpTS);
          fclose(fpTS);
      
          // ローカルタイムを記録
          ts = localtime(&tv.tv_sec);
          TimeDate = date2timestamp(ts->tm_year, ts->tm_mon, ts->tm_mday,
              ts->tm_hour, ts->tm_min, ts->tm_sec, tv.tv_usec);
          fseek(fpSer, SER_DATETIME_OFFSET, SEEK_SET);
          fwrite(&TimeDate, sizeof(TimeDate), 1, fpSer);
          printf("%04d-%02d-%02d %02d:%02d:%02d.%06d JST\n",ts->tm_year +1900, ts->tm_mon +1,
              ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec, tv.tv_usec);
      
          // UTCを記録
          ts = gmtime(&tv.tv_sec);
          TimeDate = date2timestamp(ts->tm_year, ts->tm_mon, ts->tm_mday,
              ts->tm_hour, ts->tm_min, ts->tm_sec, tv.tv_usec);
          fseek(fpSer, SER_DATETIMEUTC_OFFSET, SEEK_SET);
          fwrite(&TimeDate, sizeof(TimeDate), 1, fpSer);
          printf("%04d-%02d-%02d %02d:%02d:%02d.%06d UTC\n",ts->tm_year +1900, ts->tm_mon +1,
              ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec, tv.tv_usec);
      
          // タイムスタンプをトレーラに記録
          fseek(fpSer, 0, SEEK_END);
          fpTS = fopen("/tmp/timestamp.bin", "rb");
          for(int i=0; itm_year, ts->tm_mon, ts->tm_mday,
                  ts->tm_hour, ts->tm_min, ts->tm_sec, tv.tv_usec);
              fwrite(&TimeDate, sizeof(TimeDate), 1, fpSer);
          }
          fclose(fpTS);
      
          fclose(fpSer);
          printf("%dframes\n", FrameCount);
          printf("Rec Stop.\n");
      
          return 0;
      }
      

    • 2176x2176_250421_223053_730869.ser
    • 実際のファイル(すみませんダークです。)

  • 読み取り
  • ディレクトリのSERファイルを比較明して、PNGにします。さらに動画として保存します。

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

    • main.cpp
    • #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <opencv2/opencv.hpp>
      #include <opencv2/highgui/highgui.hpp>
      #include <omp.h>
      #include <glob.h>
      #include "timestamp.h"
      
      typedef struct {
      	char FileID[14];
      	int  LuID;
      	int  ColorID;
      	int  LittleEndian;
      	int  ImageWidth;
      	int  ImageHeight;
      	int  PixelDepthPerPlane;
      	int  FrameCount;
      	char Observer[40];
      	char Instrument[40];
      	char Telescope[40];
      	long DateTime;
      	long DateTime_UTC;
      } serHeader;
      
      unsigned char *BinImage;
      unsigned char *BinImage2;
      
      //ファイル名をコピーして、拡張子を変換します。
      char * ChangeExt(char *ext, char *Filename){
          strcpy(Filename + strlen(Filename) - 3,ext);
      
          return Filename;
      }
      
      
      void InitImage(unsigned short *dst, int width, int height){
      #pragma omp parallel for
          for(int j=0; j<height; j++){
      #pragma omp parallel for
              for(int i=0; i<width; i++){
                  *(dst+i+width*j) = 0;
              }
          }
      }
      
      
      //コピーもとのメモリから格納先メモリに比較明しながら保存します。
      void SLImage(unsigned short *dst, unsigned short *src, int width, int height){
      #pragma omp parallel for
          for(int j=0; j<height; j++){
      #pragma omp parallel for
              for(int i=0; i<width; i++){
                  if(*(dst+i+width*j) < *(src+i+width*j))
                      *(dst+i+width*j) = *(src+i+width*j);
              }
          }
      }
      
      
      void WBImageRG(unsigned short *src, int width, int height){
      #pragma omp parallel for
          for(int j=0; j<height; j++){
      #pragma omp parallel for
              for(int i=0; i<width; i++){
                  if(i%2==0 && j%2==0){
                      *(src+i+width*j) = *(src+i+width*j)/2;
                  }else if(i%2==1 && j%2==1){
                      ;
                  }else{
                      *(src+i+width*j) = *(src+i+width*j)/2;
                  }
              }
          }
      }
      
      
      cv::VideoWriter writer; // 動画ファイルを書き出すためのオブジェクトを宣言する
      
      int readSer(char *path){
          FILE *fpSer;
          serHeader SerHeader;
          char tmpc[41];
      
          printf("%s\n",path);
      
          fpSer = fopen64(path, "rb");
          int r = fread(&SerHeader.FileID, 1, sizeof(SerHeader.FileID), fpSer);
          strncpy(tmpc, SerHeader.FileID, 14);
          tmpc[14]='\0';
          r = fread(&SerHeader.LuID, 1, sizeof(SerHeader.LuID), fpSer);
          r = fread(&SerHeader.ColorID, 1, sizeof(SerHeader.ColorID), fpSer);
          r = fread(&SerHeader.LittleEndian, 1, sizeof(SerHeader.LittleEndian), fpSer);
          r = fread(&SerHeader.ImageWidth, 1, sizeof(SEEK_CUR), fpSer);
          r = fread(&SerHeader.ImageHeight, 1, sizeof(SerHeader.ImageHeight), fpSer);
          r = fread(&SerHeader.PixelDepthPerPlane, 1, sizeof(SerHeader.PixelDepthPerPlane), fpSer);
          r = fread(&SerHeader.FrameCount, 1, sizeof(SerHeader.FrameCount), fpSer);
          r = fread(&SerHeader.Observer, 1, sizeof(SerHeader.Observer), fpSer);
          strncpy(tmpc, SerHeader.Observer, 40);
          tmpc[40]='\0';
          r = fread(&SerHeader.Instrument, 1, sizeof(SerHeader.Instrument), fpSer);
          strncpy(tmpc, SerHeader.Instrument, 40);
          tmpc[40]='\0';
          r = fread(&SerHeader.Telescope, 1, sizeof(SerHeader.Telescope), fpSer);
          strncpy(tmpc, SerHeader.Telescope, 40);
          tmpc[40]='\0';
          int yeer, month, day, hour, minute, second, microsec;
          r = fread(&SerHeader.DateTime, 1, sizeof(SerHeader.DateTime), fpSer);
          timestamp2date(SerHeader.DateTime, &yeer, &month, &day, &hour, &minute, &second, µsec);
          r = fread(&SerHeader.DateTime_UTC, 1, sizeof(SerHeader.DateTime_UTC), fpSer);
          timestamp2date(SerHeader.DateTime_UTC, &yeer, &month, &day, &hour, &minute, &second, µsec);
          unsigned long TrailerDate;
          fseek(fpSer, -1*SerHeader.FrameCount * sizeof(TrailerDate), SEEK_END);
          for(int i = 0; i < SerHeader.FrameCount; i++){
              r = fread(&TrailerDate, 1, sizeof(TrailerDate), fpSer);
              timestamp2date(TrailerDate, &yeer, &month, &day, &hour, &minute, &second, µsec);
          }
      
          fseek(fpSer, 178, SEEK_SET);
          int RawSize = SerHeader.ImageWidth * SerHeader.ImageHeight * SerHeader.PixelDepthPerPlane / 8;
      //    unsigned char *BinImage = (unsigned char *)malloc(RawSize);
      //    unsigned char *BinImage2 = (unsigned char *)malloc(RawSize);
          InitImage((unsigned short *)BinImage2, SerHeader.ImageWidth, SerHeader.ImageWidth);
          cv::Mat rgb8BitMat(SerHeader.ImageHeight, SerHeader.ImageWidth, CV_8UC3);			// RGB用バッファを用意
          cv::Mat rgb8BitMat2(SerHeader.ImageHeight/2, SerHeader.ImageWidth/2, CV_8UC3);			// RGB用バッファを用意
          for(int i=0; i<SerHeader.FrameCount; i++){
              int r = fread(BinImage, sizeof(char), RawSize, fpSer);
              WBImageRG((unsigned short *)BinImage, SerHeader.ImageWidth, SerHeader.ImageWidth);
              SLImage((unsigned short *)BinImage2, (unsigned short *)BinImage, SerHeader.ImageWidth, SerHeader.ImageWidth);
              cv::Mat bayer16BitMat(SerHeader.ImageHeight, SerHeader.ImageWidth, CV_16UC1, BinImage2);	// 16bit用バッファを用意して取り込み
      //        cv::Mat bayer16BitMat(SerHeader.ImageHeight, SerHeader.ImageWidth, CV_16UC1, BinImage);	// 16bit用バッファを用意して取り込み
              cv::Mat bayer8BitMat = bayer16BitMat.clone();			// 8bit用バッファを用意
      //        bayer8BitMat.convertTo(bayer8BitMat, CV_8UC1, 0.0625*4);	// 8bitに変換
              bayer8BitMat.convertTo(bayer8BitMat, CV_8UC1, 0.0625*2);	// 8bitに変換
              cv::cvtColor(bayer8BitMat, rgb8BitMat, cv::COLOR_BayerRG2RGB);	// デベイヤー
              cv::resize(rgb8BitMat, rgb8BitMat2, cv::Size(), 0.5, 0.5);		// 縮小
              cv::imshow("opencv_viewer", rgb8BitMat2);			// ウィンドウに画像を表示する
              if (cv::waitKey(1) == 'q') break;							//qを押すと終了
          }
          char PngPath[256];
          strcpy(PngPath, path);
          cv::imwrite(ChangeExt((char *)"png",PngPath), rgb8BitMat);				// PNGで保存
          writer << rgb8BitMat;  										// 画像 image を動画ファイルへ書き出す
      //    free(BinImage2);
      //    free(BinImage);
          fclose(fpSer);
          return 0;
      }
      
      int main(int argc, char *argv[]){
          char *dirname = argv[3];
          char mp4path[256];
          char globpath[256];
      
          short width   = atoi(argv[1]);
          short height  = atoi(argv[2]);
      
          printf("OK\n");
          sprintf(mp4path,"%s/out.mp4", dirname);
          int fourcc = cv::VideoWriter::fourcc('m', 'p', '4', 'v'); // ビデオフォーマットの指定( ISO MPEG-4 / .mp4)
          writer.open(mp4path, fourcc, 30, cv::Size(width, height));
      
          sprintf(globpath,"%s/*.ser", dirname);
      
          BinImage = (unsigned char *)malloc(width * height *2);
          BinImage2 = (unsigned char *)malloc(width * height *2);
      
          glob_t globbuf;
          glob(globpath, 0, NULL, &globbuf);
          for (int i = 0; i < (int)globbuf.gl_pathc; i++) {
              readSer(globbuf.gl_pathv[i]);
          }
          writer.release();
          free(BinImage2);
          free(BinImage);
          return 0;
      }
      

    • timestamp.h
    • #ifndef TIMESTAMP_H
      #define TIMESTAMP_H
      void timestamp2date(long int timestamp, int *year, int *month, int*day, int *hour, int*minute, int *second, int *microsec);
      
      
      #endif // TIMESTAMP_H
      

    • timestamp.cpp
    • #include "timestamp.h"
      
      static int monthdays[2][12] = {
                              {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} //平年の月の日数
                             ,{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} //うるう年の月の日数
                             };
      
      void timestamp2date(long int timestamp, int *year, int *month, int*day, int *hour, int*minute, int *second, int *microsec){
          // 時刻を求めます
          *microsec   = (int)((timestamp/10)%(1000*1000));
          *second     = (int)((timestamp/10/1000/1000) % 60);
          *minute     = (int)((timestamp/10/1000/1000/60) % 60);
          *hour       = (int)((timestamp/10/1000/1000/60/60) % 24);
          // 年を求めます
          int days    = (int)(timestamp/10/1000/1000/60/60/24);
          int year400 = days / (366 * (400/4 - 3) + 365 * (400 - (400/4 - 3)));
          days        = days % (366 * (100 - 3) + 365 * (400 - (100 - 3)));
          int year100 = days / (366 * (100 - 3) + 365 * (100 - 3));
          days        = days % (366 * (100 - 3) + 365 * (100 - 3));
          int year4   = days / (366 + 365 * 3);
          days        = days % (366 + 365 * 3);
          int year1   = days / (366 + 365 * 3);
          *year       = days / 365 + 4 * year4 + 100 * year100 + 400 * year400;
      
          // 月日を求めます
          days        = days % 365;
          int *mp = monthdays[year1 / 3];
          int i;
          for(i=0; i<12; i++, mp++){
              if(days - *mp < 0){
                  break;
              }
              days -= *mp;
          }
          *month = i + 1;
          *day = days + 1;
      }
      

    • 実行の様子
    • 出力ファイル


    • 改善後との比較用です。

  • 読み取り(修正版)
  • 多くのコマ数を撮影したときの雲にかき消されることがあるので、任意のコマ数で比較明するように変更しました。
    • main.cpp
    • 変更部分に色を付けています。
          :
          :
      int frames, frameCount;
      cv::VideoWriter writer; // 動画ファイルを書き出すためのオブジェクトを宣言する
      
      int readSer(char *path){
          FILE *fpSer;
          serHeader SerHeader;
          char tmpc[41];
      
          printf("%s\n",path);
      
          fpSer = fopen64(path, "rb");
          int r = fread(&SerHeader.FileID, 1, sizeof(SerHeader.FileID), fpSer);
          strncpy(tmpc, SerHeader.FileID, 14);
          tmpc[14]='\0';
          r = fread(&SerHeader.LuID, 1, sizeof(SerHeader.LuID), fpSer);
          r = fread(&SerHeader.ColorID, 1, sizeof(SerHeader.ColorID), fpSer);
          r = fread(&SerHeader.LittleEndian, 1, sizeof(SerHeader.LittleEndian), fpSer);
          r = fread(&SerHeader.ImageWidth, 1, sizeof(SEEK_CUR), fpSer);
          r = fread(&SerHeader.ImageHeight, 1, sizeof(SerHeader.ImageHeight), fpSer);
          r = fread(&SerHeader.PixelDepthPerPlane, 1, sizeof(SerHeader.PixelDepthPerPlane), fpSer);
          r = fread(&SerHeader.FrameCount, 1, sizeof(SerHeader.FrameCount), fpSer);
          r = fread(&SerHeader.Observer, 1, sizeof(SerHeader.Observer), fpSer);
          strncpy(tmpc, SerHeader.Observer, 40);
          tmpc[40]='\0';
          r = fread(&SerHeader.Instrument, 1, sizeof(SerHeader.Instrument), fpSer);
          strncpy(tmpc, SerHeader.Instrument, 40);
          tmpc[40]='\0';
          r = fread(&SerHeader.Telescope, 1, sizeof(SerHeader.Telescope), fpSer);
          strncpy(tmpc, SerHeader.Telescope, 40);
          tmpc[40]='\0';
          int yeer, month, day, hour, minute, second, microsec;
          r = fread(&SerHeader.DateTime, 1, sizeof(SerHeader.DateTime), fpSer);
          timestamp2date(SerHeader.DateTime, &yeer, &month, &day, &hour, &minute, &second, µsec);
          r = fread(&SerHeader.DateTime_UTC, 1, sizeof(SerHeader.DateTime_UTC), fpSer);
          timestamp2date(SerHeader.DateTime_UTC, &yeer, &month, &day, &hour, &minute, &second, µsec);
          unsigned long TrailerDate;
          fseek(fpSer, -1*SerHeader.FrameCount * sizeof(TrailerDate), SEEK_END);
          for(int i = 0; i < SerHeader.FrameCount; i++){
              r = fread(&TrailerDate, 1, sizeof(TrailerDate), fpSer);
              timestamp2date(TrailerDate, &yeer, &month, &day, &hour, &minute, &second, µsec);
          }
      
          fseek(fpSer, 178, SEEK_SET);
          int RawSize = SerHeader.ImageWidth * SerHeader.ImageHeight * SerHeader.PixelDepthPerPlane / 8;
      //    unsigned char *BinImage = (unsigned char *)malloc(RawSize);
      //    unsigned char *BinImage2 = (unsigned char *)malloc(RawSize);
      //    InitImage((unsigned short *)BinImage2, SerHeader.ImageWidth, SerHeader.ImageWidth);
          cv::Mat rgb8BitMat(SerHeader.ImageHeight, SerHeader.ImageWidth, CV_8UC3);			// RGB用バッファを用意
          cv::Mat rgb8BitMat2(SerHeader.ImageHeight/2, SerHeader.ImageWidth/2, CV_8UC3);			// RGB用バッファを用意
          for(int i=0; i < SerHeader.FrameCount; i++){
              int r = fread(BinImage, sizeof(char), RawSize, fpSer);
              if(frameCount == 0){
                  InitImage((unsigned short *)BinImage2, SerHeader.ImageWidth, SerHeader.ImageWidth);
              }
              WBImageRG((unsigned short *)BinImage, SerHeader.ImageWidth, SerHeader.ImageWidth);
              SLImage((unsigned short *)BinImage2, (unsigned short *)BinImage, SerHeader.ImageWidth, SerHeader.ImageWidth);
              cv::Mat bayer16BitMat(SerHeader.ImageHeight, SerHeader.ImageWidth, CV_16UC1, BinImage2);	// 16bit用バッファを用意して取り込み
      //        cv::Mat bayer16BitMat(SerHeader.ImageHeight, SerHeader.ImageWidth, CV_16UC1, BinImage);	// 16bit用バッファを用意して取り込み
              cv::Mat bayer8BitMat = bayer16BitMat.clone();			// 8bit用バッファを用意
      //        bayer8BitMat.convertTo(bayer8BitMat, CV_8UC1, 0.0625*4);	// 8bitに変換
              bayer8BitMat.convertTo(bayer8BitMat, CV_8UC1, 0.0625*2);	// 8bitに変換
              cv::cvtColor(bayer8BitMat, rgb8BitMat, cv::COLOR_BayerRG2RGB);	// デベイヤー
              cv::resize(rgb8BitMat, rgb8BitMat2, cv::Size(), 0.5, 0.5);		// 縮小
              cv::imshow("opencv_viewer", rgb8BitMat2);			// ウィンドウに画像を表示する
              if (cv::waitKey(1) == 'q') break;							//qを押すと終了
              frameCount++;
              if(frames <= frameCount){
                  frameCount = 0;
                  writer << rgb8BitMat;  										// 画像 image を動画ファイルへ書き出す
              }
          }
          char PngPath[256];
          strcpy(PngPath, path);
          cv::imwrite(ChangeExt((char *)"png",PngPath), rgb8BitMat);				// PNGで保存
      //    writer << rgb8BitMat;  										// 画像 image を動画ファイルへ書き出す
      //    free(BinImage2);
      //    free(BinImage);
          fclose(fpSer);
          return 0;
      }
      
      int main(int argc, char *argv[]){
          char *dirname = argv[4];
          char mp4path[256];
          char globpath[256];
      
          short width   = atoi(argv[1]);
          short height  = atoi(argv[2]);
          frames = atoi(argv[3]);
          frameCount = 0;
      
          sprintf(mp4path,"%s/out.mp4", dirname);
          int fourcc = cv::VideoWriter::fourcc('m', 'p', '4', 'v'); // ビデオフォーマットの指定( ISO MPEG-4 / .mp4)
          writer.open(mp4path, fourcc, 30, cv::Size(width, height));
      
          sprintf(globpath,"%s/*.ser", dirname);
      
          BinImage = (unsigned char *)malloc(width * height *2);
          BinImage2 = (unsigned char *)malloc(width * height *2);
      
          glob_t globbuf;
          glob(globpath, 0, NULL, &globbuf);
          for (int i = 0; i < (int)globbuf.gl_pathc; i++) {
              readSer(globbuf.gl_pathv[i]);
          }
          writer.release();
          free(BinImage2);
          free(BinImage);
          return 0;
      }
      
    • 出力ファイル
  • 振り返り
  • 読み込めたソフトは、SER Player, AutoStakkert, ステライメージ のみです。
    このファイルのおかげで、流星観測用の全天カメラも動画で記録するようになりました。

  • 参考サイト
  • https://free-astro.org/index.php/SER
  • 更新履歴
  • 2024.04.21 更新(ステライメージ対応)
    2022.12.12 作成