326 lines
8.6 KiB
Go
326 lines
8.6 KiB
Go
package extract
|
||
|
||
import (
|
||
"bufio"
|
||
"encoding/binary"
|
||
"errors"
|
||
"fmt"
|
||
"os"
|
||
"path/filepath"
|
||
"sort"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/sirupsen/logrus"
|
||
log "github.com/sirupsen/logrus"
|
||
)
|
||
|
||
// 每行传感器数据帧头信息长度为24字节
|
||
type AuxFrameHead struct {
|
||
PkgHead [4]byte // 包头头标识符,固定为0xD15BD15B
|
||
FillByte0 byte // 填充字节 0x00
|
||
FrmHead [6]byte // 帧头标识符,固定为0xEB90EB90EB90
|
||
// 图像模式
|
||
// B7 模式标识 000:为线阵模式
|
||
// B6
|
||
// B5
|
||
// B4 B4谱状态 0:不输出1:输出
|
||
// B3 B3谱状态 0:不输出1:输出
|
||
// B2 B2谱状态 0:不输出1:输出
|
||
// B1 B1谱状态 0:不输出1:输出
|
||
// B0 全色状态 0:不输出1:输出
|
||
ImgMode byte
|
||
SerialNo uint32 // 当前流水号
|
||
TimeSec uint32 // 时间(秒) 量纲:1us/bit,十六进制无符号整型数
|
||
TimeSecFrac uint32 // 秒小数
|
||
FileNo uint8 // 文件号
|
||
|
||
IsValidFrmHead bool
|
||
B0 bool
|
||
B1 bool
|
||
B2 bool
|
||
B3 bool
|
||
B4 bool
|
||
IsLinerMatrix bool
|
||
RowLength int
|
||
}
|
||
|
||
func (afh *AuxFrameHead) Decode(data []byte) error {
|
||
if len(data) < 24 {
|
||
return errors.New("length of AuxFrameHead is not 24")
|
||
}
|
||
|
||
afh.PkgHead = [4]byte{data[0], data[1], data[2], data[3]}
|
||
afh.FillByte0 = data[4]
|
||
afh.FrmHead = [6]byte{data[5], data[6], data[7], data[8], data[9], data[10]}
|
||
afh.ImgMode = data[11]
|
||
afh.B0 = (afh.ImgMode&(1<<0) != 0x0)
|
||
afh.B1 = (afh.ImgMode&(1<<1) != 0x0)
|
||
afh.B2 = (afh.ImgMode&(1<<2) != 0x0)
|
||
afh.B3 = (afh.ImgMode&(1<<3) != 0x0)
|
||
afh.B4 = (afh.ImgMode&(1<<4) != 0x0)
|
||
afh.IsLinerMatrix = (afh.ImgMode&(1<<5) == 0x0 && afh.ImgMode&(1<<6) == 0x0 && afh.ImgMode&(1<<7) == 0x0)
|
||
afh.SerialNo = binary.BigEndian.Uint32(data[12:16])
|
||
afh.TimeSec = binary.BigEndian.Uint32(data[16:20])
|
||
afh.TimeSecFrac = uint32(uint32(data[20])<<16 | uint32(data[21])<<8 | uint32(data[22])) //binary.BigEndian.Uint32(data[20:23])
|
||
afh.FileNo = data[23]
|
||
|
||
afh.RowLength = afh.LengthOfRow()
|
||
afh.IsValidFrmHead = afh.CheckFrmHead()
|
||
|
||
return nil
|
||
}
|
||
|
||
// 计算一行数据长度:帧头+辅助数据+图像数据
|
||
func (afh AuxFrameHead) LengthOfRow() int {
|
||
if !afh.IsLinerMatrix {
|
||
return 14344
|
||
}
|
||
|
||
length := 64 // 帧头+辅助数据长度
|
||
if afh.B0 {
|
||
length += 19040
|
||
}
|
||
if afh.B1 {
|
||
length += 1192
|
||
}
|
||
if afh.B2 {
|
||
length += 1192
|
||
}
|
||
if afh.B3 {
|
||
length += 1192
|
||
}
|
||
if afh.B4 {
|
||
length += 1192
|
||
}
|
||
|
||
return length
|
||
}
|
||
|
||
func (afh AuxFrameHead) CheckFrmHead() bool {
|
||
if afh.FrmHead[0] == 0xEB && afh.FrmHead[1] == 0x90 &&
|
||
afh.FrmHead[2] == 0xEB && afh.FrmHead[3] == 0x90 &&
|
||
afh.FrmHead[4] == 0xEB && afh.FrmHead[5] == 0x90 {
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
|
||
type Record struct {
|
||
index int
|
||
frmHead *AuxFrameHead
|
||
}
|
||
|
||
// 从传输帧文件中分离辅助数据,分别存储到辅助数据文件 _AUX.dat 和图像数据文件 _IMG_{波谱}.dat 中
|
||
func (p *Extractor) SeprateAuxAndImgData(sDataFile string) error {
|
||
// 打开传输帧文件 - 一次读入内存
|
||
sData, err := os.ReadFile(sDataFile)
|
||
if err != nil {
|
||
log.Println("read data from", sDataFile, "error:", err.Error())
|
||
return err
|
||
}
|
||
|
||
log.Info("seprate aux and img data from", sDataFile)
|
||
|
||
// 数据质量分析
|
||
fimg, _ := os.Create("demo/temp/" + p.params.DataId + "_aux_img.txt")
|
||
defer fimg.Close()
|
||
fimg.WriteString("字节数 帧头流水号 文件号 帧头时间 中心辅助数据前4字节(行33-36)\n")
|
||
var qmap []*Record
|
||
for i := 0; i < len(sData); {
|
||
// 解析帧
|
||
if i+24 > len(sData) {
|
||
log.Info("length of original image frame head is not engough: ", len(sData)-i)
|
||
break
|
||
}
|
||
|
||
if sData[i] == 0xD1 && sData[i+1] == 0x5B && sData[i+2] == 0xD1 && sData[i+3] == 0x5B {
|
||
log.Debug("find package head: 0xD15BD15B")
|
||
} else {
|
||
i++
|
||
// log.Println(i,"not find package head: 0xD15BD15B, skip 1 byte")
|
||
continue
|
||
}
|
||
|
||
afh := &AuxFrameHead{}
|
||
afh.Decode(sData[i : i+24])
|
||
|
||
if !afh.IsValidFrmHead {
|
||
log.Debugf("[%d] invalid frame head of original raw data %v", i, afh.FrmHead)
|
||
i += 1
|
||
} else {
|
||
r := &Record{index: i, frmHead: afh}
|
||
qmap = append(qmap, r)
|
||
i += 24
|
||
|
||
utcTime := binary.BigEndian.Uint32(sData[i+32 : i+36])
|
||
|
||
t := time.Unix(int64(afh.TimeSec+uint32(ReferenceTime2000)), 0)
|
||
tAux := time.Unix(int64(utcTime), 0)
|
||
startAuxLine := tAux.Year() == t.Year() && tAux.Month() == t.Month() && tAux.Day() == t.Day() &&
|
||
tAux.Hour() == t.Hour() && tAux.Minute() == t.Minute()
|
||
|
||
if startAuxLine {
|
||
fimg.WriteString("----- AUX Start -----\n")
|
||
}
|
||
|
||
fimg.WriteString(fmt.Sprintf("%d %d %d %s %s\n",
|
||
i,
|
||
afh.SerialNo,
|
||
afh.FileNo,
|
||
t.String(),
|
||
tAux.String(),
|
||
))
|
||
}
|
||
}
|
||
|
||
sort.Slice(qmap, func(i, j int) bool {
|
||
return qmap[i].index < qmap[j].index
|
||
})
|
||
|
||
name := filepath.Base(sDataFile)
|
||
name = strings.TrimRight(name, filepath.Ext(name))
|
||
outputDir := p.params.OutputPath
|
||
|
||
aux0 := outputDir + "/" + name + "_EB.AUX"
|
||
os.Remove(aux0)
|
||
faux0, _ := os.OpenFile(aux0, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0777)
|
||
waux0 := bufio.NewWriter(faux0)
|
||
defer waux0.Flush()
|
||
defer faux0.Close()
|
||
|
||
aux1 := outputDir + "/" + name + "_PLAT.AUX"
|
||
os.Remove(aux1)
|
||
faux1, _ := os.OpenFile(aux1, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0777)
|
||
waux1 := bufio.NewWriter(faux1)
|
||
defer waux1.Flush()
|
||
defer faux1.Close()
|
||
|
||
pan := outputDir + "/" + name + "_IMG_PAN.RAW"
|
||
os.Remove(pan)
|
||
fpan, _ := os.OpenFile(pan, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0777)
|
||
wpan := bufio.NewWriter(fpan)
|
||
defer wpan.Flush()
|
||
defer fpan.Close()
|
||
panEnviHdr := EnviHdr{}
|
||
wpanHdr, _ := NewBSQWriter(outputDir+"/"+name+"_IMG_PAN.HDR", &panEnviHdr)
|
||
defer wpanHdr.Close()
|
||
|
||
// 先按单波段存储,再按波段组合存储为 BSQ 格式的 MSS
|
||
mss := outputDir + "/" + name + "_IMG_MSS.RAW"
|
||
os.Remove(mss)
|
||
fmss, _ := os.OpenFile(mss, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0777)
|
||
wmss := bufio.NewWriter(fmss)
|
||
defer wmss.Flush()
|
||
defer fmss.Close()
|
||
mssEnviHdr := EnviHdr{}
|
||
wmssHdr, _ := NewBSQWriter(outputDir+"/"+name+"_IMG_MSS.HDR", &mssEnviHdr)
|
||
defer wmssHdr.Close()
|
||
|
||
var afh AuxFrameHead
|
||
dataLen := len(sData)
|
||
|
||
mssData := make([][]byte, 4)
|
||
for i := 0; i < dataLen; {
|
||
if i+4 > dataLen {
|
||
logrus.Println("end of data, dataLen:", dataLen, "i:", i)
|
||
break
|
||
}
|
||
|
||
// 包头
|
||
if sData[i] == 0xD1 && sData[i+1] == 0x5B && sData[i+2] == 0xD1 && sData[i+3] == 0x5B {
|
||
log.Debug("find package head: 0xD15BD15B")
|
||
} else {
|
||
i++
|
||
// log.Println("not find package head: 0xD15BD15B, skip 1 byte")
|
||
continue
|
||
}
|
||
|
||
// 解析帧
|
||
if i+24 > dataLen {
|
||
log.Info("length of frame head is not engough for frame head")
|
||
break
|
||
}
|
||
afh.Decode(sData[i : i+24])
|
||
// pp.Println(afh)
|
||
|
||
if !afh.IsValidFrmHead {
|
||
log.Info("invalid frame head of original raw data")
|
||
i += 1
|
||
continue
|
||
}
|
||
|
||
// 目前只支持线阵模式
|
||
if !afh.IsLinerMatrix {
|
||
log.Error("not liner matrix mode, only support liner matrix mode")
|
||
break
|
||
}
|
||
|
||
// 读取一行数据 sData[i : i+afh.RowLength]
|
||
if i+afh.RowLength > dataLen {
|
||
log.Infof("length of image row data %v is not enough: %v", dataLen-i, afh.RowLength)
|
||
break
|
||
}
|
||
|
||
// 存储辅助数据到临时文件
|
||
dataIndex := i + 24
|
||
waux0.Write(sData[dataIndex : dataIndex+8]) // 8字节焦面电箱辅助数据
|
||
dataIndex += 8
|
||
waux1.Write(sData[dataIndex : dataIndex+32]) // 32字节中心机辅助数据
|
||
dataIndex += 32
|
||
|
||
// 存储图像数据到临时文件 - 以 ENVI BSQ 格式存储,同时提供 HDR 描述文件
|
||
if afh.B0 {
|
||
wpan.Write(sData[dataIndex : dataIndex+19040])
|
||
dataIndex += 19040
|
||
panEnviHdr.Lines += 1
|
||
}
|
||
|
||
if afh.B1 {
|
||
// wmss.Write(sData[dataIndex : dataIndex+1192])
|
||
mssData[0] = append(mssData[0], sData[dataIndex:dataIndex+1192]...)
|
||
dataIndex += 1192
|
||
mssEnviHdr.Lines += 1
|
||
}
|
||
if afh.B2 {
|
||
// wmss.Write(sData[dataIndex : dataIndex+1192])
|
||
mssData[1] = append(mssData[1], sData[dataIndex:dataIndex+1192]...)
|
||
dataIndex += 1192
|
||
}
|
||
if afh.B3 {
|
||
// wmss.Write(sData[dataIndex : dataIndex+1192])
|
||
mssData[2] = append(mssData[2], sData[dataIndex:dataIndex+1192]...)
|
||
dataIndex += 1192
|
||
}
|
||
if afh.B4 {
|
||
// wmss.Write(sData[dataIndex : dataIndex+1192])
|
||
mssData[3] = append(mssData[3], sData[dataIndex:dataIndex+1192]...)
|
||
dataIndex += 1192
|
||
}
|
||
i = dataIndex // 完成一行数据解析
|
||
}
|
||
|
||
var bands = 0
|
||
for i := 0; i < 4; i++ {
|
||
if len(mssData[i]) > 0 {
|
||
log.Println("write mss data of band B", i+1)
|
||
_, err := wmss.Write(mssData[i])
|
||
if err != nil {
|
||
log.Error("write mss data error:", err.Error())
|
||
}
|
||
bands += 1
|
||
}
|
||
}
|
||
|
||
panEnviHdr.Samples = 9520
|
||
panEnviHdr.Bands = 1
|
||
wpanHdr.Write([]byte(panEnviHdr.String()))
|
||
|
||
mssEnviHdr.Lines = mssEnviHdr.Lines / 4 // 多光谱波段分别在 4 行中传输
|
||
mssEnviHdr.Samples = 2384
|
||
mssEnviHdr.Bands = bands
|
||
wmssHdr.Write([]byte(mssEnviHdr.String()))
|
||
|
||
return nil
|
||
}
|