Saltar al contenido

Corrección de perspectiva en OpenCV usando python

La guía o código que verás en este post es la resolución más eficiente y efectiva que hallamos a tu duda o problema.

Solución:

Este es el camino que debe seguir …

Para mayor facilidad, he cambiado el tamaño de la imagen a un tamaño más pequeño,

ingrese la descripción de la imagen aquí

  • Calcule vértices de cuadrángulos para la imagen de origen, aquí lo averiguo manualmente, puede elegir la detección de bordes, la línea recta, etc.
  Q1=manual calculation;
  Q2=manual calculation;
  Q3=manual calculation;
  Q4=manual calculation;
  • Calcule los vértices del cuadrilátero en la imagen de destino manteniendo la relación de aspecto, aquí puede tomar el ancho de la tarjeta de los vértices del cuadrilátero de origen y calcular la altura multiplicando por la relación de aspecto.
   // compute the size of the card by keeping aspect ratio.
    double ratio=1.6;
    double cardH=sqrt((Q3.x-Q2.x)*(Q3.x-Q2.x)+(Q3.y-Q2.y)*(Q3.y-Q2.y)); //Or you can give your own height
    double cardW=ratio*cardH;
    Rect R(Q1.x,Q1.y,cardW,cardH);
  • Ahora tienes vértices cuadrangulares para origen y destino, luego aplica warpPerspective.

ingrese la descripción de la imagen aquí

Puede consultar el código C ++ a continuación,

   //Compute quad point for edge
    Point Q1=Point2f(90,11);
    Point Q2=Point2f(596,135);
    Point Q3=Point2f(632,452);
    Point Q4=Point2f(90,513);

    // compute the size of the card by keeping aspect ratio.
    double ratio=1.6;
    double cardH=sqrt((Q3.x-Q2.x)*(Q3.x-Q2.x)+(Q3.y-Q2.y)*(Q3.y-Q2.y));//Or you can give your own height
    double cardW=ratio*cardH;
    Rect R(Q1.x,Q1.y,cardW,cardH);

    Point R1=Point2f(R.x,R.y);
    Point R2=Point2f(R.x+R.width,R.y);
    Point R3=Point2f(Point2f(R.x+R.width,R.y+R.height));
    Point R4=Point2f(Point2f(R.x,R.y+R.height));

    std::vector quad_pts;
    std::vector squre_pts;

    quad_pts.push_back(Q1);
    quad_pts.push_back(Q2);
    quad_pts.push_back(Q3);
    quad_pts.push_back(Q4);

    squre_pts.push_back(R1);
    squre_pts.push_back(R2);
    squre_pts.push_back(R3);
    squre_pts.push_back(R4);


    Mat transmtx = getPerspectiveTransform(quad_pts,squre_pts);
    int offsetSize=150;
    Mat transformed = Mat::zeros(R.height+offsetSize, R.width+offsetSize, CV_8UC3);
    warpPerspective(src, transformed, transmtx, transformed.size());

    //rectangle(src, R, Scalar(0,255,0),1,8,0);

    line(src,Q1,Q2, Scalar(0,0,255),1,CV_AA,0);
    line(src,Q2,Q3, Scalar(0,0,255),1,CV_AA,0);
    line(src,Q3,Q4, Scalar(0,0,255),1,CV_AA,0);
    line(src,Q4,Q1, Scalar(0,0,255),1,CV_AA,0);

    imshow("quadrilateral", transformed);
    imshow("src",src);
    waitKey();

ingrese la descripción de la imagen aquí
Tengo una mejor solución que es mucho más fácil:

  • El rectángulo rojo en la imagen original y los puntos de las esquinas del rectángulo son puntos de origen.

  • Usamos cv2.getPerspectiveTransform(src, dst) que toma los puntos de origen y de destino como argumentos y devuelve la matriz de transformación que transforma cualquier imagen en una imagen de destino como se muestra en el diagrama

  • Usamos esta matriz de transformación en cv2.warpPerspective()

    – Como puede ver, los resultados son mejores. Obtienes una vista de pájaro muy bonita de la imagen.

    import cv2
    import matplotlib.pyplot as plt
    import numpy as np
    
    
    def unwarp(img, src, dst, testing):
        h, w = img.shape[:2]
        # use cv2.getPerspectiveTransform() to get M, the transform matrix, and Minv, the inverse
        M = cv2.getPerspectiveTransform(src, dst)
        # use cv2.warpPerspective() to warp your image to a top-down view
        warped = cv2.warpPerspective(img, M, (w, h), flags=cv2.INTER_LINEAR)
    
        if testing:
            f, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))
            f.subplots_adjust(hspace=.2, wspace=.05)
            ax1.imshow(img)
            x = [src[0][0], src[2][0], src[3][0], src[1][0], src[0][0]]
            y = [src[0][1], src[2][1], src[3][1], src[1][1], src[0][1]]
            ax1.plot(x, y, color='red', alpha=0.4, linewidth=3, solid_capstyle='round', zorder=2)
            ax1.set_ylim([h, 0])
            ax1.set_xlim([0, w])
            ax1.set_title('Original Image', fontsize=30)
            ax2.imshow(cv2.flip(warped, 1))
            ax2.set_title('Unwarped Image', fontsize=30)
            plt.show()
        else:
            return warped, M
    im = cv2.imread("so.JPG")
    w, h = im.shape[0], im.shape[1]
    # We will first manually select the source points 
    # we will select the destination point which will map the source points in
    # original image to destination points in unwarped image
    src = np.float32([(20,     1),
                      (540,  130),
                      (20,    520),
                      (570,  450)])
    
    dst = np.float32([(600, 0),
                      (0, 0),
                      (600, 531),
                      (0, 531)])
    
    unwarp(im, src, dst, True)
    
    cv2.imshow("so", im)
    cv2.waitKey(0)[![enter image description here][1]][1]
    cv2.destroyAllWindows()
    
    

Estoy escribiendo la respuesta proporcionada por @Haris en Python.

import cv2
import math
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('test.jpg')
rows,cols,ch = img.shape

pts1 = np.float32([[360,50],[2122,470],[2264, 1616],[328,1820]])

ratio=1.6
cardH=math.sqrt((pts1[2][0]-pts1[1][0])*(pts1[2][0]-pts1[1][0])+(pts1[2][1]-pts1[1][1])*(pts1[2][1]-pts1[1][1]))
cardW=ratio*cardH;
pts2 = np.float32([[pts1[0][0],pts1[0][1]], [pts1[0][0]+cardW, pts1[0][1]], [pts1[0][0]+cardW, pts1[0][1]+cardH], [pts1[0][0], pts1[0][1]+cardH]])

M = cv2.getPerspectiveTransform(pts1,pts2)

offsetSize=500
transformed = np.zeros((int(cardW+offsetSize), int(cardH+offsetSize)), dtype=np.uint8);
dst = cv2.warpPerspective(img, M, transformed.shape)

plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()

ingrese la descripción de la imagen aquí

Más adelante puedes encontrar las ilustraciones de otros administradores, tú incluso puedes dejar el tuyo si te apetece.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *