diff --git a/.gitignore b/.gitignore index 53321f8..7a94aea 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ data *.png *.PNG bin +log diff --git a/cmd/main.go b/cmd/main.go index 499f063..414f6a5 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,18 +1,5 @@ package main -import ( - "github.com/sirupsen/logrus" -) - -func init() { - logrus.SetFormatter(&logrus.TextFormatter{ - ForceColors: true, - DisableColors: false, - TimestampFormat: "2006-01-02 15:04:05", - FullTimestamp: true, - }) -} - func main() { rootCmd.Execute() } diff --git a/cmd/proc.go b/cmd/proc.go index 0db56b1..a0b0245 100644 --- a/cmd/proc.go +++ b/cmd/proc.go @@ -6,17 +6,13 @@ import ( "strings" "github.com/airbusgeo/godal" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" imageproc "starwiz.cn/sjy01/image-proc" ) var ( - PanRawFile string - MssRawFile string - AuxRawFile string - SaveRegisteredMssRaw bool - PansharpenIHS bool - OutputDir string + params imageproc.Params ) var procCmd = &cobra.Command{ @@ -25,20 +21,9 @@ var procCmd = &cobra.Command{ Long: `process images`, Run: func(cmd *cobra.Command, args []string) { reg := imageproc.NewRegistrator(imageproc.DownSampled) - reg.Params = imageproc.Params{ - PanRawFile: PanRawFile, - MssRawFile: MssRawFile, - AuxRawFile: AuxRawFile, - SaveRegisteredMssRaw: SaveRegisteredMssRaw, - PansharpenIHS: PansharpenIHS, - OutputDir: OutputDir, - MssTiffFile: filepath.Join(OutputDir, - strings.TrimSuffix(filepath.Base(MssRawFile), - filepath.Ext(MssRawFile))+".tiff"), - PanTiffFile: filepath.Join(OutputDir, - strings.TrimSuffix(filepath.Base(PanRawFile), - filepath.Ext(PanRawFile))+".tiff"), - } + reg.Params = params + reg.Params.MssTiffFile = filepath.Join(params.OutputDir, strings.TrimSuffix(filepath.Base(params.MssRawFile), filepath.Ext(params.MssRawFile))+".tiff") + reg.Params.PanTiffFile = filepath.Join(params.OutputDir, strings.TrimSuffix(filepath.Base(params.PanRawFile), filepath.Ext(params.PanRawFile))+".tiff") reg.Params.FusTIffFile = strings.Replace(reg.Params.MssTiffFile, ".tiff", "_FUS.tiff", 1) if err := reg.LoadMssRaw(); err != nil { @@ -50,26 +35,32 @@ var procCmd = &cobra.Command{ } godal.RegisterAll() - os.MkdirAll(OutputDir, 0755) + os.MkdirAll(params.OutputDir, 0755) if err := reg.DoPhaseCorrelation(); err != nil { panic(err) } reg.DoCoRegestration() - if SaveRegisteredMssRaw { + if params.SaveRegisteredMssRaw { registerdMSSRAW := filepath.Join( - OutputDir, - strings.TrimSuffix(filepath.Base(MssRawFile), filepath.Ext(MssRawFile))+"_registered.RAW", + params.OutputDir, + strings.TrimSuffix(filepath.Base(params.MssRawFile), filepath.Ext(params.MssRawFile))+"_registered.RAW", ) reg.SaveRegisteredMssToRaw(registerdMSSRAW) } + panScenes, mssScenes, err := reg.SubScenes() + if err != nil { + log.Error(err) + } + + reg.SaveScenesToTiff(panScenes, mssScenes) reg.SaveOriginalPanToGDALGTiff(reg.Params.PanTiffFile) reg.SaveRegisteredMssToGDALGTiff(reg.Params.MssTiffFile) - if PansharpenIHS { - reg.SavePansharpenedToGDALGTiff(reg.Params.FusTIffFile) + if params.PansharpenIHS { + reg.DoScenePansharpen(panScenes, mssScenes) } reg.Clean() @@ -79,10 +70,11 @@ var procCmd = &cobra.Command{ func init() { rootCmd.AddCommand(procCmd) - procCmd.Flags().StringVarP(&PanRawFile, "pan", "p", "pan.raw", "PAN image raw file path") - procCmd.Flags().StringVarP(&MssRawFile, "mss", "m", "mss.raw", "MSS image raw file path") - procCmd.Flags().StringVarP(&AuxRawFile, "aux", "a", "pms.aux", "AUX image raw file path") - procCmd.Flags().BoolVarP(&SaveRegisteredMssRaw, "srmss", "s", false, "save registered MSS image raw file") - procCmd.Flags().BoolVarP(&PansharpenIHS, "fus", "", false, "pansharpen using IHS") - procCmd.Flags().StringVarP(&OutputDir, "output-dir", "o", "data", "output directory") + procCmd.Flags().StringVarP(¶ms.PanRawFile, "pan", "p", "pan.raw", "PAN image raw file path") + procCmd.Flags().StringVarP(¶ms.MssRawFile, "mss", "m", "mss.raw", "MSS image raw file path") + procCmd.Flags().StringVarP(¶ms.AuxRawFile, "aux", "a", "pms.aux", "AUX image raw file path") + procCmd.Flags().BoolVarP(¶ms.SaveRegisteredMssRaw, "srmss", "s", false, "save registered MSS image raw file") + procCmd.Flags().BoolVarP(¶ms.PansharpenIHS, "fus", "", false, "pansharpen using IHS") + procCmd.Flags().StringVarP(¶ms.OutputDir, "output-dir", "o", "data", "output directory") + procCmd.Flags().BoolVarP(¶ms.SubScenes, "sub-scenes", "", false, "process sub-scenes") } diff --git a/gdal_pansharpen.go b/gdal_pansharpen.go index a32a77e..363c741 100644 --- a/gdal_pansharpen.go +++ b/gdal_pansharpen.go @@ -2,6 +2,9 @@ package imageproc import ( "image" + "os" + "os/exec" + "strings" log "github.com/sirupsen/logrus" @@ -78,3 +81,33 @@ func PansharpenIHS(panImage, mssImage gocv.Mat) gocv.Mat { return fused16U } + +func GDALPansharpen(panTiff, mssTiff string) (string, error) { + fusedTIff := strings.Replace(mssTiff, "MSS", "FUS", 1) + // pansharpenCmd := exec.Command("gdal_pansharpen.py", "-w 0.6 -w 0.1 -w 0.3 -w 0 -b 3 -b 2 -b 1", panTiff, mssTiff, fusedTIff, "-r cubic", "-of GTiff") + pansharpenCmd := exec.Command("gdal_pansharpen.py", + "-w", "0.6", "-w", "0.1", "-w", "0.3", "-w", "0", + "-b", "3", "-b", "2", "-b", "1", + "-r", "cubic", "-of", "GTiff", + panTiff, + mssTiff, + fusedTIff) + log.Println("Run Command: ", pansharpenCmd.String()) + pansharpenCmd.Stdout = os.Stdout + pansharpenCmd.Stderr = os.Stderr + return fusedTIff, pansharpenCmd.Run() +} + +func GDALTranslate(srcTiff, dstJPG string) error { + if dstJPG == "" { + dstJPG = strings.TrimSuffix(srcTiff, ".tiff") + ".jpg" + } + // gdal_translate -of JPEG -outsize 50% 50% -r bilinear input.tif output.jpg + cmd := exec.Command("gdal_translate", "-of", "JPEG", + "-scale", + srcTiff, dstJPG) + log.Println("Run Command: ", cmd.String()) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() +} diff --git a/gdal_pansharpen_test.go b/gdal_pansharpen_test.go new file mode 100644 index 0000000..92af82f --- /dev/null +++ b/gdal_pansharpen_test.go @@ -0,0 +1,13 @@ +package imageproc + +import "testing" + +func TestGDALPansharpen(t *testing.T) { + // err := GDALPansharpen("data/052022/SJY01_PAN_20240520_115428_052022_103_010.tiff", + // "data/052022/SJY01_MSS_20240520_115428_052022_103_010.tiff") + // if err != nil { + // t.Error(err) + // } + + GDALTranslate("data/052022/SJY01_MSS_20240520_115428_052022_103_010_FUS.tiff", "") +} diff --git a/go.mod b/go.mod index d19c0f1..e5260af 100644 --- a/go.mod +++ b/go.mod @@ -10,16 +10,24 @@ require ( require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/lestrrat-go/strftime v1.0.6 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/spf13/pflag v1.0.5 // indirect + golang.org/x/crypto v0.23.0 // indirect + golang.org/x/term v0.20.0 // indirect golang.org/x/text v0.15.0 // indirect ) require ( github.com/google/go-cmp v0.6.0 // indirect github.com/k0kubun/pp/v3 v3.2.0 + github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible + github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 github.com/spf13/cobra v1.8.0 + github.com/x-cray/logrus-prefixed-formatter v0.5.2 golang.org/x/net v0.25.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.20.0 // indirect diff --git a/go.sum b/go.sum index cf1d63f..ff6fa88 100644 --- a/go.sum +++ b/go.sum @@ -1059,6 +1059,11 @@ github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NB github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= +github.com/lestrrat-go/strftime v1.0.6 h1:CFGsDEt1pOpFNU+TJB0nhz9jl+K0hZSLE205AhTIGQQ= +github.com/lestrrat-go/strftime v1.0.6/go.mod h1:f7jQKgV5nnJpYgdEasS+/y7EsTb8ykN2z68n3TtcTaw= github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= @@ -1074,6 +1079,8 @@ github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPn github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= @@ -1096,6 +1103,7 @@ github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= @@ -1108,6 +1116,8 @@ github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3d github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo= +github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= @@ -1151,6 +1161,8 @@ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg= +github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1199,6 +1211,7 @@ golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIi golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1487,6 +1500,8 @@ golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/log.go b/log.go new file mode 100644 index 0000000..5007d94 --- /dev/null +++ b/log.go @@ -0,0 +1,80 @@ +package imageproc + +import ( + "os" + "time" + + rotatelogs "github.com/lestrrat-go/file-rotatelogs" + "github.com/rifflock/lfshook" + "github.com/sirupsen/logrus" + prefixed "github.com/x-cray/logrus-prefixed-formatter" +) + +type TagHook struct { + Tag string +} + +func NewTagHook(tag string) logrus.Hook { + hook := TagHook{ + Tag: tag, + } + return &hook +} + +func (hook *TagHook) Fire(entry *logrus.Entry) error { + entry.Data["tag"] = hook.Tag + return nil +} + +func (hook *TagHook) Levels() []logrus.Level { + return logrus.AllLevels +} + +var stdFormatter *prefixed.TextFormatter // 命令行输出格式 +var fileFormatter *prefixed.TextFormatter // 文件输出格式 + +func init() { + stdFormatter = &prefixed.TextFormatter{ + FullTimestamp: true, + TimestampFormat: "2006-01-02.15:04:05", + ForceFormatting: true, + ForceColors: false, + DisableColors: true, + } + fileFormatter = &prefixed.TextFormatter{ + FullTimestamp: true, + TimestampFormat: "2006-01-02.15:04:05", + ForceFormatting: true, + ForceColors: false, + DisableColors: true, + } + + configureLogger(logrus.StandardLogger(), "log/SJY01-imgproc.log", logrus.InfoLevel) +} + +func NewLogger(logfile string) *logrus.Logger { + logger := logrus.New() + configureLogger(logger, logfile, logrus.InfoLevel) + + return logger +} + +func configureLogger(logger *logrus.Logger, logfile string, level logrus.Level) { + logger.SetFormatter(stdFormatter) + logger.SetLevel(logrus.Level(level)) + writer, _ := rotatelogs.New( + logfile+".%Y%m%d", + rotatelogs.WithLinkName(logfile), + rotatelogs.WithMaxAge(time.Duration(30*24)*time.Hour), + rotatelogs.WithRotationTime(time.Duration(24)*time.Hour), + ) + + lfHook := lfshook.NewHook(lfshook.WriterMap{ + logrus.InfoLevel: writer, + logrus.DebugLevel: writer, + logrus.ErrorLevel: writer, + }, fileFormatter) + + logger.SetOutput(os.Stdout) + logger.AddHook(lfHook) +} diff --git a/output.go b/output.go index 0f16bd6..3778d6c 100644 --- a/output.go +++ b/output.go @@ -139,7 +139,7 @@ func SaveBGRToGDALGTiff(bgr gocv.Mat, bands int, resolution float64, tiffFile st } } - log.Info("Saved registered mss to ", tiffFile) + log.Info("Saved BGR MSS to ", tiffFile) return nil } diff --git a/params.go b/params.go index 08a4e59..1f52619 100644 --- a/params.go +++ b/params.go @@ -10,4 +10,5 @@ type Params struct { PanTiffFile string MssTiffFile string FusTIffFile string + SubScenes bool } diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..e27e655 --- /dev/null +++ b/run.sh @@ -0,0 +1,7 @@ +go run cmd/*.go proc -p /Users/lan/workspace/sjy01/preprocessing/demo/output/052022/SJY01_PAN_20240520_115428_052022_103.RAW -m /Users/lan/workspace/sjy01/preprocessing/demo/output/052022/SJY01_MSS_20240520_115428_052022_103.RAW -o data/052022 --fus + +go run cmd/*.go proc -p /Users/lan/workspace/sjy01/preprocessing/demo/output/051622/SJY01_PAN_20240516_101236_051622_096.RAW -m /Users/lan/workspace/sjy01/preprocessing/demo/output/051622/SJY01_MSS_20240516_101236_051622_096.RAW -o data/051622 --fus + +go run cmd/*.go proc -p /Users/lan/workspace/sjy01/preprocessing/demo/output/051922/SJY01_PAN_20240519_121433_051922_102.RAW -m /Users/lan/workspace/sjy01/preprocessing/demo/output/051922/SJY01_MSS_20240519_121433_051922_102.RAW -o data/051922 --fus + +go run cmd/*.go proc -p /Users/lan/workspace/sjy01/preprocessing/demo/output/051814/SJY01_PAN_20240517_111910_051814_098.RAW -m /Users/lan/workspace/sjy01/preprocessing/demo/output/051814/SJY01_MSS_20240517_111910_051814_098.RAW -o data/051814 --fus diff --git a/scenes.go b/scenes.go new file mode 100644 index 0000000..ae3cdaa --- /dev/null +++ b/scenes.go @@ -0,0 +1,163 @@ +package imageproc + +import ( + "fmt" + "image" + "os" + "path/filepath" + "strings" + + log "github.com/sirupsen/logrus" + "gocv.io/x/gocv" +) + +type Scene struct { + Width int + Height int + X int // coordinate of the left top corner of the scene + Y int + Mat []gocv.Mat + Tiff string +} + +func (s *Scene) Cleanup() { + for i := range s.Mat { + s.Mat[i].Close() + } +} + +// 对 PAN 和 配准后的MSS 在 Y 方向进行分景,景之间有25%的重叠 +// 默认分景大小: +// MSS 2336 * 2336 +// PAN 9344 * 9344 +func (r *Registrator) SubScenes() (panScenes []*Scene, mssScenes []*Scene, err error) { + hPAN := (9344 - 2336) + hPANOverlap := 2336 + panScenesCnt := r.PanHeight / hPAN + + for i := 0; i < panScenesCnt; i++ { + y1 := (i+1)*hPAN + hPANOverlap + if y1 > r.PanHeight { + y1 = r.PanHeight + } + + scene := &Scene{ + Width: 9344, + Height: y1 - i*hPAN, + X: 0, + Y: i * hPAN, + } + + mat := r.PanImage.Region(image.Rect(0, i*hPAN, 9344, y1)) + scene.Mat = append(scene.Mat, mat) + panScenes = append(panScenes, scene) + } + + hMSS := hPAN / 4 + hMSSOverlap := hPANOverlap / 4 + mssScenesCnt := r.MssHeight / hMSS + for i := 0; i < mssScenesCnt; i++ { + y1 := (i+1)*hMSS + hMSSOverlap + if y1 > r.MssHeight { + y1 = r.MssHeight + } + + scene := &Scene{ + Width: 2336, + Height: y1 - i*hMSS, + X: 0, + Y: i * hMSS, + } + + for band := 0; band < 4; band++ { + mat := r.registeredMssImages[band].Region(image.Rect(0, i*hMSS, 2336, y1)) + scene.Mat = append(scene.Mat, mat) + } + + mssScenes = append(mssScenes, scene) + } + + if len(panScenes) != len(mssScenes) { + log.Error("pan and mss scenes count not match") + err = fmt.Errorf("pan and mss scenes count not match") + } + + return panScenes, mssScenes, err +} + +func (r *Registrator) SaveScenesToTiff(panScenes []*Scene, mssScenes []*Scene) error { + for i, scene := range panScenes { + dir := filepath.Join(r.Params.OutputDir, fmt.Sprintf("%03d", i+1)) + os.MkdirAll(dir, 0755) + + tiff := filepath.Base(r.Params.PanTiffFile) + tiff = strings.TrimSuffix(tiff, ".tiff") + filename := fmt.Sprintf("%s_%03d.tiff", tiff, i+1) + scene.Tiff = filepath.Join(dir, filename) + err := savePanToGDALGTiff(scene.Mat[0], scene.Tiff) + if err != nil { + log.Errorf("save pan scene %d to tiff failed: %v", i+1, err) + return err + } + } + + for i, scene := range mssScenes { + dir := filepath.Join(r.Params.OutputDir, fmt.Sprintf("%03d", i+1)) + os.MkdirAll(dir, 0755) + + tiff := filepath.Base(r.Params.MssTiffFile) + tiff = strings.TrimSuffix(tiff, ".tiff") + filename := fmt.Sprintf("%s_%03d.tiff", tiff, i+1) + scene.Tiff = filepath.Join(dir, filename) + + rgbirImage, _ := r.MergeMSSToBGRNIR(scene.Mat) + err := SaveBGRToGDALGTiff(rgbirImage, 4, 5, scene.Tiff) + if err != nil { + log.Errorf("save mss scene %d to tiff failed: %v", i+1, err) + return err + } + } + + return nil +} + +func (r *Registrator) DoScenePansharpen(panScenes []*Scene, mssScenes []*Scene) error { + for i := 0; i < len(panScenes); i++ { + // rgbirImg, _ := r.MergeMSSToBGRNIR(mssScenes[i].Mat) + // ihsImage := PansharpenIHS(panScenes[i].Mat[0], rgbirImg) + // path := strings.TrimSuffix(r.Params.MssTiffFile, ".tiff") + // filename := fmt.Sprintf("%s_%03d_FUS.tiff", path, i+1) + + // SaveBGRToGDALGTiff(ihsImage, 3, 1.25, filename) + GDALPansharpen(panScenes[i].Tiff, mssScenes[i].Tiff) + } + return nil +} + +func (r *Registrator) MergeMSSToBGRNIR(channels []gocv.Mat) (gocv.Mat, error) { + var rgbirImage gocv.Mat + if len(channels) != 4 { + return rgbirImage, fmt.Errorf("mss channels count not match") + } + width := channels[0].Cols() + height := channels[0].Rows() + + // 创建合并后的图像(RGBIR) + rgbirImage = gocv.NewMatWithSize(height, width, gocv.MatTypeCV16UC4) // 4通道,16位 + + for y := 0; y < height; y++ { + for x := 0; x < width; x++ { + blue := channels[0].GetShortAt(y, x) + green := channels[1].GetShortAt(y, x) + red := channels[2].GetShortAt(y, x) + ir := channels[3].GetShortAt(y, x) + rgbirImage.SetShortAt(y, x*4+0, blue) + rgbirImage.SetShortAt(y, x*4+1, green) + rgbirImage.SetShortAt(y, x*4+2, red) + rgbirImage.SetShortAt(y, x*4+3, ir) + } + } + + return rgbirImage, nil + +}