Реализация преобразования перспективы с помощью vips

Я пытаюсь реализовать перспективное преобразование, используя vips в Go. Я использую метод opencv GetPerspectiveTransform для вычисления матрицы преобразования, а затем вычисляю изображение карты следующим образом.

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)
    }
}

Однако образ, который получается в результате, неверен. Я использовал этот ответ Stack Overflow в качестве справки Как выполнить преобразование искажения перспективы в VIPS? и мне показалось, что метод opencv WarpPerspective делает что-то подобное, поэтому я подумал, что использование opencv для расчета коэффициентов преобразования будет работать.


person axkirillov    schedule 18.12.2020    source источник


Ответы (1)


Ответ был двояким.

Прежде всего, используйте метод GetDoubleAt(row int, col int), который возвращает правильный float64, вместо GetFloatAt(row int, col int), который возвращает float32. Каким-то образом преобразование испортило числа.

Во-вторых, в методе расчета матрицы преобразования при вызове GetPerspectiveTransform исходное и целевое множества должны быть перевернуты. Это связано с тем, что метод opencv WarpPerspective неявно инвертирует матрицу, а эта реализация — нет.

func createTransform(distortion []float64) gocv.Mat {
    srcSet := []image.Point{
        {X: int(distortion[0]), Y: int(distortion[1])},
        {X: int(distortion[4]), Y: int(distortion[5])},
        {X: int(distortion[8]), Y: int(distortion[9])},
        {X: int(distortion[12]), Y: int(distortion[13])},
    }
    dstSet := []image.Point{
        {X: int(distortion[2]), Y: int(distortion[3])},
        {X: int(distortion[6]), Y: int(distortion[7])},
        {X: int(distortion[10]), Y: int(distortion[11])},
        {X: int(distortion[14]), Y: int(distortion[15])},
    }
    return gocv.GetPerspectiveTransform(dstSet, srcSet)
}
person axkirillov    schedule 22.12.2020