Cálculo da proporção da imagem de destino da Transformação de perspectiva

Eu implementei recentementeTransformação de perspectiva noOpenCV para o meu aplicativo emAndroid. Quase tudo funciona sem problemas, mas um aspecto precisa de muito mais trabalho a ser feito.

O problema é que não sei contar a proporção correta da imagem de destino da Transformação de perspectiva (ela não precisa ser definida manualmente), para poder contar a proporção da imagem com o tamanho real coisa / imagemapesar do ângulo de uma câmera. Observe que as coordenadas iniciais não formam trapézio, mas sim um quadrilátero.

Se eu tiver uma fotografia de um livro tirada de aproximadamente 45 graus e desejar que a proporção da imagem de destino seja praticamente a mesma que a proporção deste livro. É difícil ter uma foto em 2D, masCamScanner aplicativo faz isso perfeitamente. Fiz uma maneira muito simples de contar o tamanho da minha imagem de destino (sem expectativas de que ela funcione como eu quero), mas torna a imagem do ângulo de 45 graus cerca de 20% mais curta e, ao diminuir o ângulo, a altura da imagem diminui. significativamente, enquanto o CamScanner faz isso perfeitamente, apesar do ângulo:

Aqui, o CamScanner mantém a proporção da imagem de destino (segunda) igual à do livro, com precisão mesmo em um ângulo de ~ 20 graus.

Enquanto isso, meu código fica assim (enquanto conta os tamanhos da imagem de destino, não tenho a intenção de funcionar como faço nesta pergunta):

public static Mat PerspectiveTransform(Point[] cropCoordinates, float ratioW, float ratioH, Bitmap croppedImage)
{
    if (cropCoordinates.length != 4) return null;

    double width1, width2, height1, height2, avgw, avgh;
    Mat src = new Mat();
    List<Point> startCoords = new ArrayList<>();
    List<Point> resultCoords = new ArrayList<>();

    Utils.bitmapToMat(croppedImage, src);

    for (int i = 0; i < 4; i++)
    {
        if (cropCoordinates[i].y < 0 ) new Point(cropCoordinates[i].x, 0);
        startCoords.add(new Point(cropCoordinates[i].x * ratioW, cropCoordinates[i].y * ratioH));
    }

    width1 = Math.sqrt(Math.pow(startCoords.get(2).x - startCoords.get(3).x,2) + Math.pow(startCoords.get(2).y - startCoords.get(3).y,2));
    width2 = Math.sqrt(Math.pow(startCoords.get(1).x - startCoords.get(0).x,2) + Math.pow(startCoords.get(1).y - startCoords.get(0).y,2));
    height1 = Math.sqrt(Math.pow(startCoords.get(1).x - startCoords.get(2).x, 2) + Math.pow(startCoords.get(1).y - startCoords.get(2).y, 2));
    height2 = Math.sqrt(Math.pow(startCoords.get(0).x - startCoords.get(3).x, 2) + Math.pow(startCoords.get(0).y - startCoords.get(3).y, 2));
    avgw = (width1 + width2) / 2;
    avgh = (height1 + height2) / 2;

    resultCoords.add(new Point(0, 0));
    resultCoords.add(new Point(avgw-1, 0));
    resultCoords.add(new Point(avgw-1, avgh-1));
    resultCoords.add(new Point(0, avgh-1));

    Mat start = Converters.vector_Point2f_to_Mat(startCoords);
    Mat result = Converters.vector_Point2d_to_Mat(resultCoords);
    start.convertTo(start, CvType.CV_32FC2);
    result.convertTo(result,CvType.CV_32FC2);

    Mat mat = new Mat();
    Mat perspective = Imgproc.getPerspectiveTransform(start, result);
    Imgproc.warpPerspective(src, mat, perspective, new Size(avgw, avgh));

    return mat;
}

E, relativamente do mesmo ângulo, meu método produz este resultado:

O que eu quero saber é como é possível fazer? É interessante para mim como eles conseguiram contar o comprimento do objeto apenas tendo coordenadas de 4 cantos. Além disso, se for possível, forneça algumas explicações matemáticas / de código ou artigos de similar / mesma coisa.

Agradeço antecipadamente.

questionAnswers(2)

yourAnswerToTheQuestion