diff --git a/cmd/fus.go b/cmd/fus.go index e4172a0..313fa90 100644 --- a/cmd/fus.go +++ b/cmd/fus.go @@ -17,6 +17,7 @@ var ( outputDir string fusReport string fusMethod int + weight float32 ) var fusCmd = &cobra.Command{ @@ -41,7 +42,8 @@ var fusCmd = &cobra.Command{ err := fusion.Pansharpen(panImage, mssImage, filepath.Join(outputDir, fusedTiff), - fusion.PansharpenMethod(fusMethod)) + fusion.PansharpenMethod(fusMethod), + weight) if err != nil { logrus.Fatal(err) } @@ -66,7 +68,8 @@ func init() { fusCmd.Flags().StringVarP(&mssImage, "mss", "m", "", "path to the MSS image") fusCmd.Flags().StringVarP(&outputDir, "output", "o", "", "path to the output directory") fusCmd.Flags().StringVarP(¶msXML, "params", "x", "", "path to the XML file containing parameters for GDAL_Pansharpen") - fusCmd.Flags().IntVarP(&fusMethod, "method", "t", int(fusion.ESRI), "method to use for fusion (5: IHS, 3: ESRI)") + fusCmd.Flags().IntVarP(&fusMethod, "method", "t", int(fusion.ESRI), "method to use for fusion (5: IHS, 3: ESRI 1: brovey)") + fusCmd.Flags().Float32VarP(&weight, "weight", "w", 0.1, "weight of the MSS image in the fusion (0-1)") } func initFUSParams() { diff --git a/pkg/fusion/fusion.go b/pkg/fusion/fusion.go index ee8a0d5..7889205 100644 --- a/pkg/fusion/fusion.go +++ b/pkg/fusion/fusion.go @@ -12,6 +12,8 @@ import ( "starwiz.cn/sjy01/image-proc/pkg/utils" ) +// Reference: https://www.kaggle.com/code/resolut/panchromatic-sharpening + type PansharpenMethod int const ( @@ -24,7 +26,7 @@ const ( GIHS ) -func Pansharpen(panTif, mssTif, fusTif string, method PansharpenMethod) error { +func Pansharpen(panTif, mssTif, fusTif string, method PansharpenMethod, weight float32) error { log.Infof("Pansharpening %s and %s", panTif, mssTif) pan, err := utils.ReadTifftoMat(panTif) if err != nil { @@ -53,7 +55,9 @@ func Pansharpen(panTif, mssTif, fusTif string, method PansharpenMethod) error { case ESRI: fus = PansharpenESRI(*pan, BGRI[0], BGRI[1], BGRI[2], BGRI[3]) case IHS: - fus = PansharpenIHS(*pan, BGRI[0], BGRI[1], BGRI[2], BGRI[3]) + fus = PansharpenIHS(*pan, BGRI[0], BGRI[1], BGRI[2], BGRI[3], weight) + case Brovey: + fus = PansharpenBrovey(*pan, BGRI[0], BGRI[1], BGRI[2], BGRI[3], weight) default: fus = PansharpenESRI(*pan, BGRI[0], BGRI[1], BGRI[2], BGRI[3]) } @@ -102,9 +106,62 @@ func PansharpenSimpleBrovey(pan, B, G, R, I gocv.Mat) error { } func PansharpenBrovey(pan, B, G, R, I gocv.Mat, w float32) gocv.Mat { + pan.ConvertTo(&pan, gocv.MatTypeCV32F) + B.ConvertTo(&B, gocv.MatTypeCV32F) + G.ConvertTo(&G, gocv.MatTypeCV32F) + R.ConvertTo(&R, gocv.MatTypeCV32F) + I.ConvertTo(&I, gocv.MatTypeCV32F) + // DNF = (PAN - w*I)/(R*w + G*w + B*w) - var fus gocv.Mat - return fus + wI := gocv.NewMat() + I.CopyTo(&wI) + wI.MultiplyFloat(-1 * w) + defer wI.Close() + wR := gocv.NewMat() + R.CopyTo(&wR) + wR.MultiplyFloat(w) + defer wR.Close() + wG := gocv.NewMat() + G.CopyTo(&wG) + wG.MultiplyFloat(w) + defer wG.Close() + wB := gocv.NewMat() + B.CopyTo(&wB) + wB.MultiplyFloat(w) + defer wB.Close() + + DNF := gocv.NewMat() + defer DNF.Close() + gocv.Add(pan, wI, &DNF) + gocv.Add(wR, wG, &wR) + gocv.Add(wR, wB, &wR) + gocv.Divide(DNF, wR, &DNF) + + gocv.Multiply(R, DNF, &R) + gocv.Multiply(G, DNF, &G) + gocv.Multiply(B, DNF, &B) + gocv.Multiply(I, DNF, &I) + + mss := gocv.NewMat() + mt := gocv.MatTypeCV16UC3 + switch config.GCONFIG.CoRegistration.FUSBandOrder { + case "RGB": + gocv.Merge([]gocv.Mat{R, G, B}, &mss) + case "BGR": + gocv.Merge([]gocv.Mat{B, G, R}, &mss) + case "RGBI": + gocv.Merge([]gocv.Mat{R, G, B, I}, &mss) + mt = gocv.MatTypeCV16UC4 + case "BGRI": + gocv.Merge([]gocv.Mat{B, G, R, I}, &mss) + mt = gocv.MatTypeCV16UC4 + default: + gocv.Merge([]gocv.Mat{R, G, B}, &mss) + } + + mss.ConvertTo(&mss, mt) + + return mss } func PansharpenSimpleMean(pan, B, G, R, I gocv.Mat) error { return nil } @@ -157,7 +214,7 @@ func PansharpenESRI(pan, B, G, R, I gocv.Mat) gocv.Mat { return mss } -func PansharpenIHS(pan, B, G, R, I gocv.Mat) gocv.Mat { +func PansharpenIHS(pan, B, G, R, I gocv.Mat, w float32) gocv.Mat { mss := gocv.NewMat() gocv.Merge([]gocv.Mat{B, G, R}, &mss) mssHLS := gocv.NewMat() @@ -179,7 +236,9 @@ func PansharpenIHS(pan, B, G, R, I gocv.Mat) gocv.Mat { gocv.Normalize(hlsFloat, &hlsFloat, 0, 65535, gocv.NormMinMax) // 替换亮度分量 - hlsChannels[1] = panFloat + I.ConvertTo(&I, gocv.MatTypeCV32F) + I.MultiplyFloat(-1 * w) + gocv.Add(panFloat, I, &hlsChannels[1]) // 合并通道 gocv.Merge(hlsChannels, &mssHLS) diff --git a/pkg/producer/scenes.go b/pkg/producer/scenes.go index 0c46df2..dc7a9c5 100644 --- a/pkg/producer/scenes.go +++ b/pkg/producer/scenes.go @@ -242,7 +242,7 @@ func (r *Registrator) SaveScenesToTiff(panScenes []*Scene, mssScenes []*Scene) e func (r *Registrator) DoScenePansharpen(panScenes []*Scene, mssScenes []*Scene) error { for i := 0; i < len(panScenes); i++ { fusedTiff := strings.Replace(mssScenes[i].Tiff, "MSS", "FUS", -1) - err := fusion.Pansharpen(panScenes[i].Tiff, mssScenes[i].Tiff, fusedTiff, fusion.ESRI) + err := fusion.Pansharpen(panScenes[i].Tiff, mssScenes[i].Tiff, fusedTiff, fusion.ESRI, 0.1) if err != nil { return err }