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,
- 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.
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();
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()
Más adelante puedes encontrar las ilustraciones de otros administradores, tú incluso puedes dejar el tuyo si te apetece.