Files
sjy01-image-proc/registrate.go
nuknal 7d8a4d4f84 1
2024-05-24 17:02:17 +08:00

270 lines
7.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"bufio"
"fmt"
"image"
"os"
"github.com/chai2010/tiff"
log "github.com/sirupsen/logrus"
"gocv.io/x/gocv"
)
type Registrate interface{}
const (
MssBands = 4
PixelBytes = 2
PanWidth = 9344 // 像素宽度
MssWidth = 2336
BlockNum = 5
)
type Registrator struct {
PanImage gocv.Mat
PanHeight int
PanWidth int
MssImages [4]gocv.Mat
MssHeight int
MssWidth int
registeredImages [4]gocv.Mat
rgbirImage gocv.Mat
}
func NewRegistrator() *Registrator {
var r Registrator
return &r
}
func (r *Registrator) LoadPanRaw(raw string) error {
data, err := os.ReadFile(raw)
if err != nil {
log.Error("Error reading raw file: ", err)
return err
}
height := len(data) / (PanWidth * PixelBytes)
r.PanImage, err = gocv.NewMatFromBytes(height, PanWidth, gocv.MatTypeCV16U, data)
if err != nil {
log.Error("Error creating Mat from bytes: ", err)
return err
}
r.PanHeight = height
r.PanWidth = PanWidth
return nil
}
func (r *Registrator) LoadMssRaw(raw string) error {
data, err := os.ReadFile(raw)
if err != nil {
log.Error("Error reading raw file: ", err)
return err
}
height := len(data) / (MssWidth * PixelBytes * MssBands)
mssData := make([][]byte, MssBands)
for h := 0; h < height; h++ {
row := data[h*MssWidth*MssBands*PixelBytes : (h+1)*MssWidth*MssBands*PixelBytes]
for i := 0; i < MssBands; i++ {
mssData[i] = append(mssData[i], row[i*MssWidth*PixelBytes:(i+1)*MssWidth*PixelBytes]...)
}
}
for i := 0; i < MssBands; i++ {
r.MssImages[i], err = gocv.NewMatFromBytes(height, MssWidth, gocv.MatTypeCV16U, mssData[i])
if err != nil {
log.Error("Error creating Mat from bytes: ", err)
return err
}
}
r.MssHeight = height
r.MssWidth = MssWidth
return nil
}
func (r *Registrator) DoPhaseCorrelation() error {
// 确保 MSS 高度是 PAN 高度的 1/4
if r.MssHeight*4 != r.PanHeight {
err := fmt.Errorf("MSS height is not 1/4 of PAN height, invalid raw file")
log.Error(err)
return err
}
// 将PAN将采样作为轮廓匹配基准图像
downsampledPanImage := gocv.NewMat()
gocv.Resize(r.PanImage, &downsampledPanImage,
image.Point{X: r.MssWidth, Y: r.MssHeight}, 0, 0, gocv.InterpolationLinear)
// 对每个 MSS 波段图像进行上采样
upsampledMSSImages := make([]gocv.Mat, MssBands)
for i := 0; i < MssBands; i++ {
upsampledMSSImages[i] = gocv.NewMat()
gocv.Resize(r.MssImages[i], &upsampledMSSImages[i],
image.Point{X: r.PanWidth, Y: r.PanHeight}, 0, 0, gocv.InterpolationLinear)
// r.msToRaw(upsampledMSSImages[i].ToBytes(), fmt.Sprintf("MSS%d.RAW", i+1))
}
fmt.Println("PAN images size:", r.PanImage.Size())
fmt.Println("upsampled MSS1 images size:", upsampledMSSImages[0].Size())
fmt.Println("upsampled MSS2 images size:", upsampledMSSImages[0].Size())
fmt.Println("upsampled MSS3 images size:", upsampledMSSImages[0].Size())
fmt.Println("upsampled MSS4 images size:", upsampledMSSImages[0].Size())
// 分块高度
blockHeight := r.PanHeight / BlockNum
alignedMssData := make([][]byte, MssBands)
for band := 0; band < MssBands; band++ {
var alignedMSSImage gocv.Mat
for block := 0; block < BlockNum; block++ {
// 读取 PAN 和 MSS 分块数据
y1 := (block + 1) * blockHeight
if block == BlockNum-1 {
y1 = r.PanHeight
}
log.Println("Processing block", block, image.Rect(0, block*blockHeight, r.PanWidth, y1))
panBlock := r.PanImage.Region(image.Rect(0, block*blockHeight, r.PanWidth, y1))
mssBlock := upsampledMSSImages[band].Region(image.Rect(0, block*blockHeight, r.PanWidth, y1))
// 处理每个分块
alignedBlock := r.processBlock(panBlock, mssBlock)
alignedBlockData := alignedBlock.ToBytes()
alignedMssData[band] = append(alignedMssData[band], alignedBlockData...)
if alignedMSSImage.Empty() {
alignedMSSImage = alignedBlock.Clone()
} else {
gocv.Vconcat(alignedMSSImage, alignedBlock, &alignedMSSImage)
alignedBlock.Close()
}
panBlock.Close()
mssBlock.Close()
}
r.registeredImages[band] = alignedMSSImage
}
r.mssToRaw(alignedMssData, "mss.raw")
return nil
}
func (r *Registrator) processBlock(panBlock, mssBlock gocv.Mat) gocv.Mat {
pan := gocv.NewMat()
mss := gocv.NewMat()
panBlock.ConvertTo(&pan, gocv.MatTypeCV32FC1)
defer pan.Close()
mssBlock.ConvertTo(&mss, gocv.MatTypeCV32FC1)
defer mss.Close()
hann := gocv.NewMat()
shift, response := gocv.PhaseCorrelate(pan, mss, hann)
hann.Close()
dx := shift.X
dy := shift.Y
log.Printf("Block shift: dx = %f, dy = %f. response = %f \n", dx, dy, response)
// cv::Mat translationMatrix = (cv::Mat_<double>(2, 3) << 1, 0, shift.x, 0, 1, shift.y);
translationMat := gocv.NewMatWithSize(2, 3, gocv.MatTypeCV32F)
translationMat.SetFloatAt(0, 0, 1)
translationMat.SetFloatAt(0, 1, 0)
translationMat.SetFloatAt(0, 2, shift.X)
translationMat.SetFloatAt(1, 0, 0)
translationMat.SetFloatAt(1, 1, 1)
translationMat.SetFloatAt(1, 2, shift.Y)
alignedBlock := gocv.NewMat()
gocv.WarpAffine(mss, &alignedBlock, translationMat, image.Pt(panBlock.Size()[0], panBlock.Size()[1]))
translationMat.Close()
alignedBlock.ConvertTo(&alignedBlock, gocv.MatTypeCV16U)
return alignedBlock
}
func (r *Registrator) panToTiff(panImage gocv.Mat, filePath string) error {
return nil
}
func (r *Registrator) mssToTiff(registeredImages [4]gocv.Mat, filePath string) error {
// 创建合并后的图像RGBIR
rgbirImage := gocv.NewMatWithSize(r.PanHeight, r.PanWidth, gocv.MatTypeCV16UC4) // 4通道16位
for y := 0; y < r.PanHeight; y++ {
for x := 0; x < r.PanWidth; x++ {
r := registeredImages[0].GetShortAt(y, x)
g := registeredImages[1].GetShortAt(y, x)
b := registeredImages[2].GetShortAt(y, x)
ir := registeredImages[3].GetShortAt(y, x)
rgbirImage.SetShortAt(y, x*4+0, r)
rgbirImage.SetShortAt(y, x*4+1, g)
rgbirImage.SetShortAt(y, x*4+2, b)
rgbirImage.SetShortAt(y, x*4+3, ir)
}
}
// 将合并后的图像保存为TIFF文件
fileName := "registered_rgbir.tiff"
tiffFile, err := os.Create(fileName)
if err != nil {
fmt.Println("Error creating TIFF file:", err)
return err
}
defer tiffFile.Close()
// 使用tiff库保存图像
img, err := rgbirImage.ToImage()
if err != nil {
fmt.Println("Error converting Mat to image:", err)
return err
}
if err := tiff.Encode(tiffFile, img, nil); err != nil {
fmt.Println("Error encoding TIFF file:", err)
return err
}
fmt.Println("Saved", fileName)
return nil
}
func (r *Registrator) mssToRaw(mssData [][]byte, filePath string) error {
f, err := os.OpenFile("mss.RAW", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0777)
if err != nil {
return err
}
w := bufio.NewWriter(f)
for row := 0; row < r.PanHeight; row++ {
w.Write(mssData[0][row*r.PanWidth*PixelBytes : (row+1)*r.PanWidth*PixelBytes])
w.Write(mssData[1][row*r.PanWidth*PixelBytes : (row+1)*r.PanWidth*PixelBytes])
w.Write(mssData[2][row*r.PanWidth*PixelBytes : (row+1)*r.PanWidth*PixelBytes])
w.Write(mssData[3][row*r.PanWidth*PixelBytes : (row+1)*r.PanWidth*PixelBytes])
}
return nil
}
func (r *Registrator) msToRaw(mssData []byte, filePath string) error {
f, err := os.OpenFile(filePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0777)
if err != nil {
return err
}
w := bufio.NewWriter(f)
w.Write(mssData)
return nil
}