I am trying to implement a perspective transform using vips in Go. I am using opencv's GetPerspectiveTransform
method to calculate a transform matrix then computing a map image as follows
func DistortPerspective(ref *vips.ImageRef, tiepoints []float64) {
T := createTransform(tiepoints)
// make an index image where pixels have the value of their (x, y) coordinates
index, err := vips.XYZ(ref.Width(), ref.Height())
if err != nil {
logger.Debug(nil, err)
}
i0, err := index.Copy()
if err != nil {
logger.Debug(nil, err)
}
i1, err := index.Copy()
if err != nil {
logger.Debug(nil, err)
}
err = i0.ExtractBand(0, 1)
if err != nil {
logger.Debug(nil, err)
}
err = i1.ExtractBand(1, 1)
if err != nil {
logger.Debug(nil, err)
}
T00 := float64(T.GetFloatAt(0, 0))
T01 := float64(T.GetFloatAt(0, 1))
T02 := float64(T.GetFloatAt(0, 2))
T10 := float64(T.GetFloatAt(1, 0))
T11 := float64(T.GetFloatAt(1, 1))
T12 := float64(T.GetFloatAt(1, 2))
T20 := float64(T.GetFloatAt(2, 0))
T21 := float64(T.GetFloatAt(2, 1))
T22 := float64(T.GetFloatAt(2, 2))
// i0 * T[0,0]
i0xT00 := linear(i0, T00, 0)
// i1 * T[0,1] + T[0,2]
i1xT01_T02 := linear(i1, T01, T02)
// i0 * T[1,0]
i0xT10 := linear(i0, T10, 0)
// i1 * T[1,1] + T[1,2]
i1xT11_T12 := linear(i1, T11, T12)
//i[0] * T[0,0] + i[1] * T[0,1] + T[0,2]
i0xT00_i1xT01_T02 := add(i0xT00, i1xT01_T02)
//i[0] * T[1,0] + i[1] * T[1,1] + T[1,2]
i0xT10_i1xT11_T12 := add(i0xT10, i1xT11_T12)
//i[0] * T[2,0]
i0xT20 := linear(i0, T20, 0)
//i[1] * T[2,1] + T[2,2]
i1xT21_T22 := linear(i1, T21, T22)
//i[0] * T[2,0] + i[1] * T[2,1] + T[2,2]
i0xT20_i1xT21_T22 := add(i0xT20, i1xT21_T22)
//x = (i[0] * T[0,0] + i[1] * T[0,1] + T[0,2]) / (i[0] * T[2,0] + i[1] * T[2,1] + T[2,2])
x := divide(i0xT00_i1xT01_T02, i0xT20_i1xT21_T22)
//y = (i[0] * T[1,0] + i[1] * T[1,1] + T[1,2]) / (i[0] * T[2,0] + i[1] * T[2,1] + T[2,2])
y := divide(i0xT10_i1xT11_T12, i0xT20_i1xT21_T22)
//# join up x and y as a map image
mapimage := bandjoin(x, y)
//transform the original image
err = ref.Mapim(mapimage)
if err != nil {
logger.Debug(nil, err)
}
}
However the image that comes as a result is wrong. I was using this Stack Overflow answer as a reference How to perform perspective distort transformation in VIPS?
and it appeared to me that opencv WarpPerspective
method does something similar so I thought that using opencv to calculate transform coefficients would work.
The answer was two-fold.
First of all, use
GetDoubleAt(row int, col int)
method that returns proper float64 instead ofGetFloatAt(row int, col int)
, that returns float32. Somehow the conversion was messing up the numbers.Second of all, in the method for calculating the transform matrix, in the
GetPerspectiveTransform
call, source and destination sets should be flipped. That is because opencv'sWarpPerspective
method implicitly inverts the matrix, while this implementation does not.