diff --git a/aos.go b/aos.go index 93dec61..276b455 100644 --- a/aos.go +++ b/aos.go @@ -1,6 +1,81 @@ package main +import ( + "bufio" + "fmt" + "os" + "path/filepath" + log "github.com/sirupsen/logrus" +) + +const ( + AOSFrameLength = 1024 +) + +var AOSSyncWord = []byte{0x1A, 0xCF, 0xFC, 0x1D} type AOSFrame struct { } + +func (p *Processor) ExtractAosData() error { + // 打开传输帧文件 - 一次读入内存 + rawData, err := os.ReadFile(p.params.InputData) + if err != nil { + log.Println("read data from", p.params.InputData, "error:", err.Error()) + return err + } + + name := filepath.Base(p.params.InputData) + aosDataFile := filepath.Join(p.params.TempPath, "aos_data_"+name) + foData, err := os.OpenFile(aosDataFile, + os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0777) + if err != nil { + fmt.Println("create data err", err.Error()) + return err + } + defer foData.Close() + wData := bufio.NewWriter(foData) + + var validFrameCnt int + var errFrameCnt int + + for i := 0; i < len(rawData); { + // 寻找帧头 0x1A CF FC 1D + if i+4 > len(rawData) { + log.Info("end of raw data") + break + } + + if rawData[i] == 0x1A && rawData[i+1] == 0xCF && rawData[i+2] == 0xFC && rawData[i+3] == 0x1D { + // 找到帧头 + log.Debug("detect AOS frame") + } else { + i++ + continue + } + + if i+1024 > len(rawData) { + log.Info("not enough data for AOS frame") + break + } + + // 读取完整帧 + if ldpcCheck(rawData[i:i+1024]) != nil { + errFrameCnt++ + } + + wData.Write(rawData[i+10 : i+894]) + i += 1024 + validFrameCnt++ + } + + log.Println("valid AOS frame cnt:", validFrameCnt) + log.Println("err AOS frame cnt:", errFrameCnt) + + return nil +} + +func ldpcCheck(frame []byte) error { + return nil +} diff --git a/aux.go b/aux.go new file mode 100644 index 0000000..60f3094 --- /dev/null +++ b/aux.go @@ -0,0 +1,247 @@ +package main + +import ( + "bufio" + "encoding/binary" + "errors" + "os" + "path/filepath" + "strings" + + "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 +} + +// 中心机辅助数据 512 字节 +type AuxCenterMachine struct { +} + +// 焦面电箱辅助数据 128 字节 +type AuxFocalBox struct { +} + +// 从传输帧文件中分离辅助数据,分别存储到辅助数据文件 _AUX.dat 和图像数据文件 _IMG_{波谱}.dat 中 +func (p *Processor) 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) + + name := filepath.Base(sDataFile) + name = strings.TrimRight(name, filepath.Ext(name)) + + aux0 := filepath.Dir(sDataFile) + "/" + name + "_AUX0.dat" + 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 := filepath.Dir(sDataFile) + "/" + name + "_AUX1.dat" + 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 := filepath.Dir(sDataFile) + "/" + 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(filepath.Dir(sDataFile)+"/"+name+"_IMG_PAN.HDR", &panEnviHdr) + defer wpanHdr.Close() + + // 先按单波段存储,再按波段组合存储为 BSQ 格式的 MSS + mss := filepath.Dir(sDataFile) + "/" + 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(filepath.Dir(sDataFile)+"/"+name+"_IMG_MSS.HDR", &mssEnviHdr) + defer wmssHdr.Close() + + var afh AuxFrameHead + dataLen := len(sData) + 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++ + 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") + break + } + + // 目前只支持线阵模式 + 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.Info("length of row data is not enough for row length:", 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]) + dataIndex += 1192 + mssEnviHdr.Lines += 1 + } + if afh.B2 { + wmss.Write(sData[dataIndex : dataIndex+1192]) + dataIndex += 1192 + } + if afh.B3 { + wmss.Write(sData[dataIndex : dataIndex+1192]) + dataIndex += 1192 + } + if afh.B4 { + wmss.Write(sData[dataIndex : dataIndex+1192]) + dataIndex += 1192 + } + i = dataIndex // 完成一行数据解析 + } + + panEnviHdr.Samples = 9520 + panEnviHdr.Bands = 1 + wpanHdr.Write([]byte(panEnviHdr.String())) + mssEnviHdr.Lines = mssEnviHdr.Lines / 4 // 多光谱波段分别在 4 行中传输 + mssEnviHdr.Bands = 1 + mssEnviHdr.Samples = 2384 * 4 + wmssHdr.Write([]byte(mssEnviHdr.String())) + + return nil +} diff --git a/envi.go b/envi.go new file mode 100644 index 0000000..ac64922 --- /dev/null +++ b/envi.go @@ -0,0 +1,69 @@ +package main + +import ( + "bytes" + "html" + + "io" + "os" + "text/template" +) + +type BSQWriter struct { + filepath string + fio *os.File + w io.Writer + content *EnviHdr +} + +var HDRTemplate = `ENVI +description = { + File Imported into ENVI.} +samples = {{.Samples}} +lines = {{.Lines}} +bands = {{.Bands}} +header offset = 0 +file type = ENVI Standard +data type = 12 +interleave = bsq +sensor type = Unknown +byte order = 0 +wavelength units = Unknown` + +// https://www.nv5geospatialsoftware.com/docs/ENVIHeaderFiles.html +type EnviHdr struct { + Samples int // samples (pixels) each line + Lines int + Bands int +} + +func (h *EnviHdr) String() string { + var t *template.Template + t = template.New("template") + t, err := t.Parse(HDRTemplate) + if err != nil { + return "" + } + buf := new(bytes.Buffer) + t.Execute(buf, h) + buf = bytes.NewBufferString(html.UnescapeString(buf.String())) + + return buf.String() +} + +func NewBSQWriter(filepath string, content *EnviHdr) (*BSQWriter, error) { + fio, err := os.Create(filepath) + if err != nil { + return nil, err + } + w := fio + return &BSQWriter{filepath, fio, w, content}, nil +} + +func (w *BSQWriter) Write(data []byte) (int, error) { + return w.w.Write(data) +} + +func (w *BSQWriter) Close() error { + return w.fio.Close() +} diff --git a/go.mod b/go.mod index d915a3a..be4e1d7 100644 --- a/go.mod +++ b/go.mod @@ -2,10 +2,18 @@ module starwiz.cn/sjy01/preprocessing go 1.21.0 +require github.com/k0kubun/pp v3.0.1+incompatible + require ( github.com/duke-git/lancet/v2 v2.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/cobra v1.8.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect golang.org/x/exp v0.0.0-20221208152030-732eee02a75a // indirect + golang.org/x/sys v0.1.0 // indirect ) diff --git a/go.sum b/go.sum index 3f97e02..0a3a11a 100644 --- a/go.sum +++ b/go.sum @@ -1,14 +1,36 @@ github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/duke-git/lancet/v2 v2.3.0 h1:Ztie0qOnC4QgGYYqmpmQxbxkPcm54kqFXj1bwhiV8zg= github.com/duke-git/lancet/v2 v2.3.0/go.mod h1:zGa2R4xswg6EG9I6WnyubDbFO/+A/RROxIbXcwryTsc= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/k0kubun/pp v3.0.1+incompatible h1:3tqvf7QgUnZ5tXO6pNAZlrvHgl6DvifjDrd9g2S9Z40= +github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= golang.org/x/exp v0.0.0-20221208152030-732eee02a75a h1:4iLhBPcpqFmylhnkbY3W0ONLUYYkDAW9xMFLfxgsvCw= golang.org/x/exp v0.0.0-20221208152030-732eee02a75a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index 5f6dbdd..9b4b1ed 100644 --- a/main.go +++ b/main.go @@ -16,14 +16,19 @@ var rootCmd = &cobra.Command{ Long: `Preprocessing tools for SJY01 dataset`, Run: func(cmd *cobra.Command, args []string) { fmt.Println("preprocessing tools for SJY01 dataset") - p := Params{ - InputData: "demo/050722.dat", + params := Params{ + InputData: "demo/4545.dat", OutputPath: "demo/output", TempPath: "demo/temp", - DataId: "050722", + DataId: "004545", } - // preprocess(&p) - exractImageData(&p) + p := NewProcessor(¶ms) + p.ExtractAosData() + dats, _ := p.ExtractOriginalImageData() + for _, d := range dats { + p.SeprateAuxAndImgData(d) + } + }, } diff --git a/process.go b/process.go index 851dafa..16354f9 100644 --- a/process.go +++ b/process.go @@ -1,179 +1,15 @@ package main import ( - "bufio" - "encoding/binary" - "fmt" - "io" - "log" "os" - "path/filepath" - "sort" - - "github.com/duke-git/lancet/v2/slice" ) -const ( - AOSFrameLength = 1024 -) - -var AOSSyncWord = []byte{0x1A, 0xCF, 0xFC, 0x1D} -var ImageFrameHead = 0xE77EE77E - - -func preprocess(params *Params) error { - // extract data from aos frame - fi, err := os.Open(params.InputData) - if err != nil { - log.Println("exract data from", params.InputData, "error:", err.Error()) - return err - } - defer fi.Close() - - name := filepath.Base(params.InputData) - aosDataFile := filepath.Join(params.TempPath, "aos_data_"+name) - foData, err := os.OpenFile(aosDataFile, - os.O_RDWR|os.O_CREATE|os.O_APPEND, 0777) - if err != nil { - fmt.Println("create data err", err.Error()) - return err - } - defer foData.Close() - wData := bufio.NewWriter(foData) - - var validFrameCnt int - var errFrameCnt int - - iBuf := make([]byte, AOSFrameLength) - r := bufio.NewReader(fi) - for { - correct := true - nI, err := r.Read(iBuf) - if err != nil && err != io.EOF { - panic(err) - } - - if nI < AOSFrameLength || err == io.EOF { - break - } - - iTag := iBuf[0:4] - if iTag[0] == 0x1A && iTag[1] == 0xCF && iTag[2] == 0xFC && iTag[3] == 0x1D { - if err := ldpcCheck(iBuf); err != nil { - errFrameCnt++ - correct = false - } else { - validFrameCnt++ - } - } else { - correct = false - errFrameCnt++ - } - - if !correct { - continue - } - - data := iBuf[10:894] - wData.Write(data) - } - - log.Println("valid frame cnt:", validFrameCnt) - log.Println("err frame cnt:", errFrameCnt) - - return nil +type Processor struct { + params *Params } -func ldpcCheck(frame []byte) error { - return nil -} - -func exractImageData(params *Params) ([]string, error) { - var sData []string - name := filepath.Base(params.InputData) - aosDataFile := filepath.Join(params.TempPath, "aos_data_"+name) - - aosData, err := os.ReadFile(aosDataFile) - if err != nil { - log.Println("read data from", aosDataFile, "error:", err.Error()) - return nil, err - } - - snRange := map[int][]int{} - datSet := map[int][]byte{} - - var i int - for i < len(aosData) { - if i+4 > len(aosData) { - break - } - - if aosData[i] == 0xE7 && aosData[i+1] == 0x7E && aosData[i+2] == 0xE7 && aosData[i+3] == 0x7E { - i += 4 // <- 帧头 - - serialNum := binary.BigEndian.Uint32(aosData[i : i+4]) - i += 4 // <- 流水号 - i += 2 // <- 保留位 - i += 2 // <- 密钥库索引号 - i += 1 // <- 明密标志 - - flag := aosData[i] - i += 1 // <-帧标志 - - fileno := int(aosData[i]) - snRange[fileno] = append(snRange[fileno], int(serialNum)) - i += 1 // <- 文件号 - - i += 1 // <- 保留 - - if i+ImageFrameDataLength > len(aosData) { - log.Println("frame length error") - break - } - - // 只保留非空帧 - if flag != 0x55 { - datSet[fileno] = append(datSet[fileno], aosData[i:i+ImageFrameDataLength]...) - } - - i += ImageFrameDataLength // <- 图像数据 - if i > len(aosData) { - log.Println("frame length error") - break - } - - // fmt.Println("serialNum:", serialNum, "fileno:", fileno) - continue - } - i++ - } - - for k, v := range datSet { - frameCnt := slice.Unique(snRange[k]) - if len(frameCnt) < 4096 { - log.Println("fileno", k, "数据长度不足4096帧") - continue - } - - s01 := filepath.Join(params.TempPath, fmt.Sprintf("%s_S%d.dat", params.DataId, k)) - fo, err := os.OpenFile(s01, - os.O_RDWR|os.O_CREATE|os.O_APPEND, 0777) - if err != nil { - log.Println("create file", s01, "error:", err.Error()) - return nil, err - } - w := bufio.NewWriter(fo) - w.Write(v) - w.Flush() - fo.Close() - sData = append(sData, s01) - } - - for k, v := range snRange { - vv := slice.Unique(v) - sort.Slice(vv, func(i, j int) bool { return vv[i] < vv[j] }) - fmt.Println("fileno:", k, ", sn range:", vv[0], "-", vv[len(vv)-1], "len", len(vv)) - } - - return sData, nil +func NewProcessor(params *Params) *Processor { + os.MkdirAll(params.OutputPath, 0755) + os.MkdirAll(params.TempPath, 0755) + return &Processor{params: params} } diff --git a/raw.go b/raw.go new file mode 100644 index 0000000..929253d --- /dev/null +++ b/raw.go @@ -0,0 +1,18 @@ +package main + +// 图像数据帧头信息、辅助数据以及图像数据组成, +// 帧头信息长度为24字节, +// 辅助数据总共640字节,分16行传输,每行传输40字节 +// 其中40字节中包含8字节焦面电箱辅助数据以及32节字的中心机辅助数据 +// 图像数据 每个像素16bit +// 线阵模式每 16 行一组,可拼出 640 字节辅助数据 +type LineMatrixRawRow struct { + FrameHeader [24]byte // 帧头信息 + AuxFocalBox [8]byte // 焦面电箱辅助数据 + AuxCenterMachine [32]byte // 中心机辅助数据 + B0Data []byte // 全色图像数据 19040 字节,9520 像素 + B1Data []byte // 多光谱1图像数据 1192 字节,每 4 行一组,共 4768 字节,2384 像素 + B2Data []byte // 多光谱2图像数据 1192 字节,每 4 行一组,共 4768 字节,2384 像素 + B3Data []byte // 多光谱3图像数据 1192 字节,每 4 行一组,共 4768 字节,2384 像素 + B4Data []byte // 多光谱4图像数据 1192 字节,每 4 行一组,共 4768 字节,2384 像素 +} diff --git a/spectral_img.go b/spectral_img.go new file mode 100644 index 0000000..37db38b --- /dev/null +++ b/spectral_img.go @@ -0,0 +1,12 @@ +package main + +type SpectralImage struct { + Spectrum string // PAN(B0) B1 B2 B3 B4 + H uint32 // 9520 像素 2(Margin) + 48(OB) + 38(Margin) + 9344(Effective Pixels) + 38(Margin) + 48(OB) + 2(Margin) + V uint32 // 7056 像素 2(Margin) + 12(OB) + 18(Margin) + 20(Margin) + 7000(Effective Pixels) + 4(Margin) + Pixels [][]*Pixel +} + +type Pixel struct { + Bits [2]byte // 16bit +} diff --git a/trans_frame.go b/trans_frame.go index 2fe8529..bd25e8e 100644 --- a/trans_frame.go +++ b/trans_frame.go @@ -1,7 +1,21 @@ package main -const ImageFrameHeadLength = 16 -const ImageFrameDataLength = 8176 +import ( + "bufio" + "fmt" + "os" + "path/filepath" + "sort" + + log "github.com/sirupsen/logrus" + + "github.com/duke-git/lancet/v2/slice" +) + +const TransImageFrameLength = 8192 +const TransImageFrameHeadLength = 16 +const TransImageFrameDataLength = 8176 +const ImageFrameHead = 0xE77EE77E // 智能载荷电箱与数传单机之间图像数据传输帧格式 type TransFrame struct { @@ -11,13 +25,13 @@ type TransFrame struct { KeyIndex uint16 // 密钥库索引号 大端序 SecretFlag byte // 明密标志 0x55 明传 0xAA 密传 FrameFlag byte // 帧类型 0x00:智能载荷电箱有效帧 0x55: 智能载荷电箱空帧 - FileNo byte // 文件编号 + FileNo uint8 // 文件编号 Reserved1 byte // 保留字节 0x00 - Data [8176]byte + Data []byte // 数据区 8176字节 } func (t *TransFrame) Decode(frame []byte) { - if len(frame) < ImageFrameHeadLength+ImageFrameDataLength { + if len(frame) < TransImageFrameLength { return } copy(t.Header[:], frame[:4]) @@ -28,5 +42,79 @@ func (t *TransFrame) Decode(frame []byte) { t.FrameFlag = frame[13] t.FileNo = frame[14] t.Reserved1 = frame[15] - copy(t.Data[:], frame[16:]) + t.Data = append(t.Data, frame[16:8192]...) +} + +// 提取图像传输帧中的原始图像数据 +func (p *Processor) ExtractOriginalImageData() ([]string, error) { + var sData []string + name := filepath.Base(p.params.InputData) + aosDataFile := filepath.Join(p.params.TempPath, "aos_data_"+name) + + aosData, err := os.ReadFile(aosDataFile) + if err != nil { + log.Println("read data from", aosDataFile, "error:", err.Error()) + return nil, err + } + + snRange := map[int][]uint32{} + datSet := map[int][]byte{} + + var i int + for i < len(aosData) { + if i+4 > len(aosData) { + log.Println("end of trans frame data") + break + } + + if aosData[i] == 0xE7 && aosData[i+1] == 0x7E && aosData[i+2] == 0xE7 && aosData[i+3] == 0x7E { + if i+TransImageFrameLength > len(aosData) { + log.Println("trans frame length error") + break + } + + var tf TransFrame + tf.Decode(aosData[i : i+TransImageFrameLength]) + fileno := int(tf.FileNo) + snRange[fileno] = append(snRange[fileno], tf.SNo) + + // 只保留非空帧 + if tf.FrameFlag != 0x55 && fileno != 0 { + datSet[fileno] = append(datSet[fileno], tf.Data...) + } + + i += TransImageFrameLength + continue + } + i++ + } + + for k, v := range snRange { + vv := slice.Unique(v) + sort.Slice(vv, func(i, j int) bool { return vv[i] < vv[j] }) + fmt.Println("fileno:", k, ", sn range:", vv[0], "-", vv[len(vv)-1], "len", len(vv)) + } + + for k, v := range datSet { + frameCnt := slice.Unique(snRange[k]) + if len(frameCnt) < 4096 { + log.Println("fileno", k, "数据长度不足4096帧") + continue + } + + s01 := filepath.Join(p.params.TempPath, fmt.Sprintf("%s_S%d.dat", p.params.DataId, k)) + fo, err := os.OpenFile(s01, + os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0777) + if err != nil { + log.Println("create file", s01, "error:", err.Error()) + return nil, err + } + w := bufio.NewWriter(fo) + w.Write(v) + w.Flush() + fo.Close() + sData = append(sData, s01) + } + + return sData, nil }