使用gamma校正提升jpg亮度
This commit is contained in:
150
pkg/producer/jpg.go
Normal file
150
pkg/producer/jpg.go
Normal file
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user