//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 * * 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-RECODER"); 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; }
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)
#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; }
#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
#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; }
: : 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; }