分景后配准

This commit is contained in:
nuknal
2024-11-01 09:19:42 +08:00
parent e51d07901d
commit 75e4dd6d90
7 changed files with 191 additions and 58 deletions

View File

@@ -3,8 +3,10 @@ package producer
import (
"errors"
"image"
"math/cmplx"
"github.com/duke-git/lancet/v2/slice"
"github.com/mjibson/go-dsp/fft"
log "github.com/sirupsen/logrus"
"gocv.io/x/gocv"
)
@@ -31,9 +33,9 @@ func CV_PhaseCorrelate(panBlock, mssBlock gocv.Mat) (gocv.Point2f, float64) {
mssBlock.ConvertTo(&mss, gocv.MatTypeCV32FC1)
defer mss.Close()
hann := gocv.NewMat()
hann := gocv.NewMatWithSize(pan.Rows(), pan.Cols(), pan.Type())
defer hann.Close()
gocv.CreateHanningWindow(&hann, image.Point{X: pan.Cols(), Y: pan.Rows()}, pan.Type())
shift, response := gocv.PhaseCorrelate(pan, mss, hann)
dx := shift.X
@@ -64,3 +66,77 @@ func (r *ImgProc) fileterPhaseShift(thredholds []float64, greaterThan bool) erro
return nil
}
func PhaseCorrelate(panBlock, mssBlock gocv.Mat) (gocv.Point2f, float64) {
// 计算傅里叶变换
panFreqDomain, _, _, err := toFreqDomain(panBlock)
if err != nil {
log.Error(err)
}
mssFreqDomain, width, height, err := toFreqDomain(mssBlock)
if err != nil {
log.Error(err)
}
// 计算共轭乘积并积累相位信息
crossPowerSpectrum := make([][]complex128, height)
for i := range crossPowerSpectrum {
crossPowerSpectrum[i] = make([]complex128, width)
}
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
if panFreqDomain[y][x] != 0 && mssFreqDomain[y][x] != 0 {
crossPowerSpectrum[y][x] = panFreqDomain[y][x] * cmplx.Conj(mssFreqDomain[y][x])
}
}
}
// 归一化
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
if crossPowerSpectrum[y][x] != 0 {
magnitude := cmplx.Abs(crossPowerSpectrum[y][x])
crossPowerSpectrum[y][x] = crossPowerSpectrum[y][x] / complex(magnitude, 0)
}
}
}
ifftResult := fft.IFFT2(crossPowerSpectrum)
// 查找最大值及其对应的平移参数
maxVal := 0.0
var dx, dy float64
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
val := real(ifftResult[y][x])
if val > maxVal {
maxVal = val
dx = float64(x)
dy = float64(y)
}
}
}
log.Debugf("Block shift: dx = %f, dy = %f. response = %f", dx, dy, 0.0)
return gocv.Point2f{X: float32(dx), Y: float32(dy)}, 0.0
}
func toFreqDomain(input gocv.Mat) ([][]complex128, int, int, error) {
height := input.Rows()
width := input.Cols()
data := make([][]complex128, height)
for y := 0; y < height; y++ {
data[y] = make([]complex128, width)
for x := 0; x < width; x++ {
grayColor := float64(uint16(input.GetShortAt(y, x)))
data[y][x] = complex(grayColor, 0)
}
}
freqDomain := fft.FFT2(data)
return freqDomain, width, height, nil
}