From 07ee4d88d475411e2ea5442935dfa61dd8a57ed6 Mon Sep 17 00:00:00 2001 From: nuknal Date: Thu, 30 May 2024 11:22:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=BF=E7=94=A8gamma=E6=A0=A1=E6=AD=A3?= =?UTF-8?q?=E6=8F=90=E5=8D=87jpg=E4=BA=AE=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/proc.go | 2 +- pkg/config/config.go | 8 + {producer => pkg/producer}/filter.go | 0 {producer => pkg/producer}/fit.go | 0 {producer => pkg/producer}/gdal_pansharpen.go | 4 +- {producer => pkg/producer}/hdr.go | 0 {producer => pkg/producer}/image_proc_test.go | 20 +-- .../producer}/image_registration.go | 0 pkg/producer/jpg.go | 150 ++++++++++++++++++ {producer => pkg/producer}/meta.go | 0 {producer => pkg/producer}/output.go | 0 {producer => pkg/producer}/params.go | 0 .../producer}/phase_correlation.go | 0 {producer => pkg/producer}/proj.go | 0 {producer => pkg/producer}/report.go | 0 {producer => pkg/producer}/scenes.go | 4 +- {producer => pkg/producer}/util.go | 0 producer/jpg.go | 84 ---------- 18 files changed, 174 insertions(+), 98 deletions(-) create mode 100644 pkg/config/config.go rename {producer => pkg/producer}/filter.go (100%) rename {producer => pkg/producer}/fit.go (100%) rename {producer => pkg/producer}/gdal_pansharpen.go (96%) rename {producer => pkg/producer}/hdr.go (100%) rename {producer => pkg/producer}/image_proc_test.go (52%) rename {producer => pkg/producer}/image_registration.go (100%) create mode 100644 pkg/producer/jpg.go rename {producer => pkg/producer}/meta.go (100%) rename {producer => pkg/producer}/output.go (100%) rename {producer => pkg/producer}/params.go (100%) rename {producer => pkg/producer}/phase_correlation.go (100%) rename {producer => pkg/producer}/proj.go (100%) rename {producer => pkg/producer}/report.go (100%) rename {producer => pkg/producer}/scenes.go (99%) rename {producer => pkg/producer}/util.go (100%) delete mode 100644 producer/jpg.go diff --git a/cmd/proc.go b/cmd/proc.go index 5ad8cb6..be70b81 100644 --- a/cmd/proc.go +++ b/cmd/proc.go @@ -8,7 +8,7 @@ import ( "github.com/airbusgeo/godal" "github.com/sirupsen/logrus" "github.com/spf13/cobra" - producer "starwiz.cn/sjy01/image-proc/producer" + producer "starwiz.cn/sjy01/image-proc/pkg/producer" ) var ( diff --git a/pkg/config/config.go b/pkg/config/config.go new file mode 100644 index 0000000..eeeae07 --- /dev/null +++ b/pkg/config/config.go @@ -0,0 +1,8 @@ +package config + +type CoRegistrationConfig struct { + CRBlockNW int `yaml:"cr_block_nw" mapstructure:"cr_block_nw"` + CRBlockNH int `yaml:"cr_block_nh" mapstructure:"cr_block_nh"` + CRResampleMethod string `yaml:"cr_resample_method" mapstructure:"cr_resample_method"` + FUSBandOrder string `yaml:"fu_band_order" mapstructure:"fu_band_order"` +} diff --git a/producer/filter.go b/pkg/producer/filter.go similarity index 100% rename from producer/filter.go rename to pkg/producer/filter.go diff --git a/producer/fit.go b/pkg/producer/fit.go similarity index 100% rename from producer/fit.go rename to pkg/producer/fit.go diff --git a/producer/gdal_pansharpen.go b/pkg/producer/gdal_pansharpen.go similarity index 96% rename from producer/gdal_pansharpen.go rename to pkg/producer/gdal_pansharpen.go index afc4ec6..26345bd 100644 --- a/producer/gdal_pansharpen.go +++ b/pkg/producer/gdal_pansharpen.go @@ -4,6 +4,7 @@ import ( "image" "os" "os/exec" + "path/filepath" "strings" log "github.com/sirupsen/logrus" @@ -83,7 +84,8 @@ func PansharpenIHS(panImage, mssImage gocv.Mat) gocv.Mat { } func GDALPansharpen(panTiff, mssTiff string) (string, error) { - fusedTIff := strings.Replace(mssTiff, "MSS", "FUS", 1) + fusedTIff := strings.Replace(mssTiff, "MSS", "FUS", -1) + os.MkdirAll(filepath.Dir(fusedTIff), 0755) // 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.4", "-w", "0.2", "-w", "0.4", "-w", "0", diff --git a/producer/hdr.go b/pkg/producer/hdr.go similarity index 100% rename from producer/hdr.go rename to pkg/producer/hdr.go diff --git a/producer/image_proc_test.go b/pkg/producer/image_proc_test.go similarity index 52% rename from producer/image_proc_test.go rename to pkg/producer/image_proc_test.go index 4447da3..5efbe62 100644 --- a/producer/image_proc_test.go +++ b/pkg/producer/image_proc_test.go @@ -18,22 +18,22 @@ func TestGDALPansharpen(t *testing.T) { func TestGTiffToJPG(t *testing.T) { godal.RegisterAll() - tiff := "../data/051622/006/SJY01_MSS_20240516_101236_051622_096_006.tiff" - jpg := "../data/051622/006/SJY01_MSS_20240516_101236_051622_096_006.jpg" + tiff := "../data/051622/006/MSS/SJY01_MSS_20240516_101236_051622_096_006.tiff" + jpg := "../data/051622/006/MSS/SJY01_MSS_20240516_101236_051622_096_006.jpg" err := GTiffToJPG(tiff, jpg, false) if err != nil { t.Error(err) } - // tiff = "../data/051622/006/SJY01_PAN_20240516_101236_051622_096_006.tiff" - // jpg = "../data/051622/006/SJY01_PAN_20240516_101236_051622_096_006.jpg" - // err = GTiffToJPG(tiff, jpg, false) - // if err != nil { - // t.Error(err) - // } + tiff = "../data/051622/006/PAN/SJY01_PAN_20240516_101236_051622_096_006.tiff" + jpg = "../data/051622/006/PAN/SJY01_PAN_20240516_101236_051622_096_006.jpg" + err = GTiffToJPG(tiff, jpg, false) + if err != nil { + t.Error(err) + } - tiff = "../data/051622/006/SJY01_FUS_20240516_101236_051622_096_006.tiff" - jpg = "../data/051622/006/SJY01_FUS_20240516_101236_051622_096_006.jpg" + tiff = "../data/051622/006/FUS/SJY01_FUS_20240516_101236_051622_096_006.tiff" + jpg = "../data/051622/006/FUS/SJY01_FUS_20240516_101236_051622_096_006.jpg" err = GTiffToJPG(tiff, jpg, true) if err != nil { t.Error(err) diff --git a/producer/image_registration.go b/pkg/producer/image_registration.go similarity index 100% rename from producer/image_registration.go rename to pkg/producer/image_registration.go diff --git a/pkg/producer/jpg.go b/pkg/producer/jpg.go new file mode 100644 index 0000000..4f7652b --- /dev/null +++ b/pkg/producer/jpg.go @@ -0,0 +1,150 @@ +package imageproc + +import ( + "fmt" + "image" + "math" + + "github.com/airbusgeo/godal" + log "github.com/sirupsen/logrus" + "gocv.io/x/gocv" +) + +func GTiffToJPG(ftiff, fjpg string, reversed bool) error { + // 打开 TIFF 文件 + ds, err := godal.Open(ftiff) + if err != nil { + log.Printf("Error opening TIFF file %s: %v", ftiff, err) + return err + } + defer ds.Close() + + bands := ds.Bands() + log.Infof("creating JPG for TIFF file %s.", ftiff) + + // 获取图像大小 + width := bands[0].Structure().SizeX + height := bands[0].Structure().SizeY + bandsCnt := len(bands) + + // 创建 16 位图像矩阵 + var img gocv.Mat + defer img.Close() + if bandsCnt == 1 { + img = gocv.NewMatWithSize(height, width, gocv.MatTypeCV16UC1) + } else { + bandsCnt = 3 // 只取前三个波段 + img = gocv.NewMatWithSize(height, width, gocv.MatTypeCV16UC3) + } + + // 读取每个波段并存储到图像矩阵中 + for i := 0; i < bandsCnt; i++ { + band := bands[i] + data := make([]uint16, width*height) + err = band.Read(0, 0, data, width, height) + if err != nil { + fmt.Printf("Error reading band %d: %v\n", i, err) + return err + } + + // 将 16 位数据存储到图像的相应通道 + for y := 0; y < height; y++ { + for x := 0; x < width; x++ { + value := data[y*width+x] + img.SetShortAt(y, x*bandsCnt+i, int16(value)) + } + } + } + + channels := gocv.Split(img) + for i, ch := range channels { + // 2. 计算图像的最小值和最大值 + minVal, maxVal, minLoc, maxLoc := gocv.MinMaxLoc(ch) + log.Printf("Min value: %f, Max value: %f, min location: %v, max location: %v", minVal, maxVal, minLoc, maxLoc) + + // 3. 将16位图像线性拉伸到8位图像 + scale := 255.0 / (maxVal - minVal) + shift := -minVal * scale + ch.ConvertToWithParams(&channels[i], gocv.MatTypeCV8U, scale, shift) + } + + img8bit := gocv.NewMat() + defer img8bit.Close() + if reversed { + gocv.Merge([]gocv.Mat{channels[2], channels[1], channels[0]}, &img8bit) + } else { + gocv.Merge(channels, &img8bit) + } + + for i := range channels { + channels[i].Close() + } + + gocv.Resize(img8bit, &img8bit, + image.Point{X: img8bit.Cols() / 2, Y: img8bit.Rows() / 2}, + 0, 0, gocv.InterpolationCubic) + + // 7. 应用伽玛校正提升亮度 + // avgBrightness := calculateAverageBrightness(img8bit) + // gamma := determineGammaValue(avgBrightness) + // log.Printf("Average Brightness: %f, Determined Gamma: %f", avgBrightness, gamma) + + gammaCorrected := applyGammaCorrection(img8bit, 1.6) // 伽玛值 + defer gammaCorrected.Close() + ok := gocv.IMWriteWithParams(fjpg, gammaCorrected, []int{gocv.IMWriteJpegOptimize, 1}) + if !ok { + err = fmt.Errorf("error saving %s", fjpg) + return err + } + + // gocv.IMWrite(strings.Replace(fjpg, ".jpg", "_8.jpg", 1), img8bit) + + return nil +} + +// applyGammaCorrection applies gamma correction to the image +func applyGammaCorrection(src gocv.Mat, gamma float64) gocv.Mat { + lookupTable := make([]uint8, 256) + invGamma := 1.0 / gamma + for i := 0; i < 256; i++ { + lookupTable[i] = uint8(math.Pow(float64(i)/255.0, invGamma) * 255.0) + } + + dst := gocv.NewMat() + gammaMat, err := gocv.NewMatFromBytes(1, 256, gocv.MatTypeCV8UC1, lookupTable) + if err != nil { + log.Printf("Error creating gamma correction matrix: %v", err) + return src + } + defer gammaMat.Close() + + gocv.LUT(src, gammaMat, &dst) + return dst +} + +// calculateAverageBrightness calculates the average brightness of the image +func calculateAverageBrightness(img gocv.Mat) float64 { + if img.Channels() == 1 { + return img.Mean().Val1 + } + gray := gocv.NewMat() + defer gray.Close() + gocv.CvtColor(img, &gray, gocv.ColorBGRToGray) + return gray.Mean().Val1 + // mean := gocv.NewMat() + // dstStdDev := gocv.NewMat() + // defer mean.Close() + // defer dstStdDev.Close() + // gocv.MeanStdDev(gray, &mean, &dstStdDev) + // return float64(mean.GetFloatAt(0, 0)) +} + +// determineGammaValue determines an appropriate gamma value based on the average brightness +func determineGammaValue(avgBrightness float64) float64 { + targetBrightness := 180.0 + if avgBrightness < 0.1 { + return 1.0 + } + gamma := math.Log(targetBrightness/255.0) / math.Log(avgBrightness/255.0) + return gamma +} diff --git a/producer/meta.go b/pkg/producer/meta.go similarity index 100% rename from producer/meta.go rename to pkg/producer/meta.go diff --git a/producer/output.go b/pkg/producer/output.go similarity index 100% rename from producer/output.go rename to pkg/producer/output.go diff --git a/producer/params.go b/pkg/producer/params.go similarity index 100% rename from producer/params.go rename to pkg/producer/params.go diff --git a/producer/phase_correlation.go b/pkg/producer/phase_correlation.go similarity index 100% rename from producer/phase_correlation.go rename to pkg/producer/phase_correlation.go diff --git a/producer/proj.go b/pkg/producer/proj.go similarity index 100% rename from producer/proj.go rename to pkg/producer/proj.go diff --git a/producer/report.go b/pkg/producer/report.go similarity index 100% rename from producer/report.go rename to pkg/producer/report.go diff --git a/producer/scenes.go b/pkg/producer/scenes.go similarity index 99% rename from producer/scenes.go rename to pkg/producer/scenes.go index 2f8b866..e3e5446 100644 --- a/producer/scenes.go +++ b/pkg/producer/scenes.go @@ -88,7 +88,7 @@ func (r *Registrator) SubScenes() (panScenes []*Scene, mssScenes []*Scene, err e 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)) + dir := filepath.Join(r.Params.OutputDir, fmt.Sprintf("%03d", i+1), "PAN") os.MkdirAll(dir, 0755) tiff := filepath.Base(r.Params.PanTiffFile) @@ -105,7 +105,7 @@ func (r *Registrator) SaveScenesToTiff(panScenes []*Scene, mssScenes []*Scene) e } for i, scene := range mssScenes { - dir := filepath.Join(r.Params.OutputDir, fmt.Sprintf("%03d", i+1)) + dir := filepath.Join(r.Params.OutputDir, fmt.Sprintf("%03d", i+1), "MSS") os.MkdirAll(dir, 0755) tiff := filepath.Base(r.Params.MssTiffFile) diff --git a/producer/util.go b/pkg/producer/util.go similarity index 100% rename from producer/util.go rename to pkg/producer/util.go diff --git a/producer/jpg.go b/producer/jpg.go deleted file mode 100644 index 0d5f941..0000000 --- a/producer/jpg.go +++ /dev/null @@ -1,84 +0,0 @@ -package imageproc - -import ( - "fmt" - "image" - - "github.com/airbusgeo/godal" - log "github.com/sirupsen/logrus" - "gocv.io/x/gocv" -) - -func GTiffToJPG(ftiff, fjpg string, reversed bool) error { - // 打开 TIFF 文件 - ds, err := godal.Open(ftiff) - if err != nil { - log.Printf("Error opening TIFF file %s: %v", ftiff, err) - return err - } - defer ds.Close() - - bands := ds.Bands() - log.Infof("creating JPG for TIFF file %s.", ftiff) - - // 获取图像大小 - width := bands[0].Structure().SizeX - height := bands[0].Structure().SizeY - bandsCnt := len(bands) - - // 创建 16 位图像矩阵 - var img gocv.Mat - defer img.Close() - if bandsCnt == 1 { - img = gocv.NewMatWithSize(height, width, gocv.MatTypeCV16UC1) - } else { - bandsCnt = 3 // 只取前三个波段 - img = gocv.NewMatWithSize(height, width, gocv.MatTypeCV16UC3) - } - - // 读取每个波段并存储到图像矩阵中 - for i := 0; i < bandsCnt; i++ { - band := bands[i] - data := make([]uint16, width*height) - err = band.Read(0, 0, data, width, height) - if err != nil { - fmt.Printf("Error reading band %d: %v\n", i, err) - return err - } - - // 将 16 位数据存储到图像的相应通道 - for y := 0; y < height; y++ { - for x := 0; x < width; x++ { - value := data[y*width+x] - img.SetShortAt(y, x*bandsCnt+i, int16(value)) - } - } - } - - // 重采样图像 - gocv.Resize(img, &img, image.Point{X: img.Cols() / 2, Y: img.Rows() / 2}, 0, 0, gocv.InterpolationCubic) - - // 创建 8 位图像矩阵 - img8 := gocv.NewMat() - defer img8.Close() - if bandsCnt == 1 { - img.ConvertToWithParams(&img8, gocv.MatTypeCV8UC1, 1.0/256.0*1.5, 0) - } else { - img.ConvertToWithParams(&img8, gocv.MatTypeCV8UC3, 1.0/256.0*1.5, 0) - if reversed { - channels := gocv.Split(img8) - gocv.Merge([]gocv.Mat{channels[2], channels[1], channels[0]}, &img8) - for _, ch := range channels { - ch.Close() - } - } - } - - ok := gocv.IMWrite(fjpg, img8) - if !ok { - err = fmt.Errorf("error saving %s", fjpg) - return err - } - - return nil -}