Files
sjy01-image-proc/phase_correlation.go
2024-05-25 09:24:19 +08:00

128 lines
3.4 KiB
Go

package main
import (
"image"
"math"
log "github.com/sirupsen/logrus"
"gocv.io/x/gocv"
)
type PhaseShiftM struct {
dx float32
dy float32
Block Block
}
type Block struct {
width int
height int
coord image.Point // top-left corner of the block in the original image
}
func (r *Registrator) processBlock(panBlock, mssBlock gocv.Mat) (gocv.Mat, gocv.Point2f) {
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)
if math.IsNaN(float64(dx)) {
dx = 0.0
}
if math.IsNaN(float64(dy)) {
dy = 0.0
}
// 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, dx)
translationMat.SetFloatAt(1, 0, 0)
translationMat.SetFloatAt(1, 1, 1)
translationMat.SetFloatAt(1, 2, dy)
defer translationMat.Close()
alignedBlock := gocv.NewMat()
gocv.WarpAffine(mss, &alignedBlock, translationMat, image.Pt(mss.Size()[1], mss.Size()[0]))
alignedBlock.ConvertTo(&alignedBlock, gocv.MatTypeCV16U)
return alignedBlock, shift
}
func (r *Registrator) DoMssPhaseShift() ([][]byte, error) {
alignedMssData := make([][]byte, MssBands)
// 使用平均偏移量来做平移变换
for band := 0; band < MssBands; band++ {
var efficientShiftM int
var xTotal, yTotal float32
for _, shift := range r.phaseShifts[band] {
if math.IsNaN(float64(shift.dx)) || math.IsNaN(float64(shift.dy)) {
continue
}
efficientShiftM += 1
xTotal += shift.dx
yTotal += shift.dy
}
dx := xTotal / float32(efficientShiftM)
dy := yTotal / float32(efficientShiftM)
log.Println("Band", band+1, "average shift:", dx, dy, "efficientShiftM:", efficientShiftM)
translationMat := gocv.NewMatWithSize(2, 3, gocv.MatTypeCV32F)
translationMat.SetFloatAt(0, 0, 1)
translationMat.SetFloatAt(0, 1, 0)
translationMat.SetFloatAt(0, 2, dx)
translationMat.SetFloatAt(1, 0, 0)
translationMat.SetFloatAt(1, 1, 1)
translationMat.SetFloatAt(1, 2, dy)
alignedMss := gocv.NewMatWithSize(r.MssHeight, r.MssWidth, gocv.MatTypeCV32FC1)
cvtMss := gocv.NewMat()
r.MssImages[band].ConvertTo(&cvtMss, gocv.MatTypeCV32FC1)
// 手动平移像素
outY := math.MaxInt
for y := 0; y < r.MssHeight; y++ {
for x := 0; x < r.MssWidth; x++ {
// 计算新的坐标
newX := x + int(dx)
newY := y + int(dy)
// 如果新坐标在图像范围内,进行像素值赋值
if newX >= 0 && newX < r.MssWidth && newY >= 0 && newY < r.MssHeight {
alignedMss.SetFloatAt(y, x, cvtMss.GetFloatAt(newY, newX))
} else {
// 如果新坐标不在图像范围内,设置为黑色
alignedMss.SetFloatAt(y, x, 0)
if outY > y {
outY = y
log.Println("Warning: pixel out of range", x, y)
}
}
}
}
// gocv.WarpAffine(cvtMss, &alignedMss, translationMat, image.Pt(cvtMss.Size()[1], cvtMss.Size()[0]))
alignedMss.ConvertTo(&alignedMss, gocv.MatTypeCV16U)
alignedMssData[band] = append(alignedMssData[band], alignedMss.ToBytes()...)
translationMat.Close()
cvtMss.Close()
alignedMss.Close()
}
return alignedMssData, nil
}