Corrección de perspectiva automática OpenCV

Estoy tratando de implementar Corrección de perspectiva automática en mi progtwig iOS y cuando uso la imagen de prueba que encontré en el tutorial, todo funciona como se esperaba. Pero cuando tomo una foto, obtengo un resultado extraño.

Estoy usando el código encontrado en este tutorial

Cuando le doy una imagen que se ve así:

enter image description here

Lo entiendo como el resultado:

enter image description here

Esto es lo que dst me puede ayudar.

enter image description here

Estoy usando esto para llamar al método que contiene el código.

quadSegmentation(Img, bw, dst, quad);

¿Alguien puede decirme cuándo obtengo tantas líneas verdes en comparación con el tutorial? ¿Y cómo podría arreglar esto y recortar adecuadamente la imagen para que solo contenga la tarjeta?

Para transformar la perspectiva, necesitas,

puntos fuente-> Coordenadas de vértices cuadrangulares en la imagen de origen.

puntos de destino-> coordenadas de los vértices cuadrangulares correspondientes en la imagen de destino.

Aquí calcularemos estos puntos por proceso de contorno.

Calcular Coordenadas de vértices cuadrangulares en la imagen de origen

  • Obtendrá su tarjeta como contorno con solo desenfoque, umbralización, luego encuentre el contorno, encuentre el contorno más grande, etc.
  • Después de encontrar el contorno más grande solo calcular se aproxima a una curva poligonal , aquí debe obtener 4 puntos que representan las esquinas de su tarjeta. Puede ajustar el parámetro epsilon para hacer 4 coordenadas.

enter image description here

Calcular las coordenadas de los vértices cuadrangulares correspondientes en la imagen de destino

  • Esto se puede averiguar fácilmente calculando el rectángulo delimitador para el contorno más grande.

enter image description here

En la imagen inferior, el rectángulo rojo representa los puntos de origen y verde para los puntos de destino.

enter image description here

Ajuste el orden de las coordenadas y aplique la transformación de Perspective

  • Aquí ajusto manualmente el orden de las coordenadas y puede usar algún algoritmo de clasificación.
  • Luego calcule la matriz de transformación y aplique wrapPrespective

Ver el resultado final

enter image description here

Código

  Mat src=imread("card.jpg"); Mat thr; cvtColor(src,thr,CV_BGR2GRAY); threshold( thr, thr, 70, 255,CV_THRESH_BINARY ); vector< vector  > contours; // Vector for storing contour vector< Vec4i > hierarchy; int largest_contour_index=0; int largest_area=0; Mat dst(src.rows,src.cols,CV_8UC1,Scalar::all(0)); //create destination image findContours( thr.clone(), contours, hierarchy,CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE ); // Find the contours in the image for( int i = 0; i< contours.size(); i++ ){ double a=contourArea( contours[i],false); // Find the area of contour if(a>largest_area){ largest_area=a; largest_contour_index=i; //Store the index of largest contour } } drawContours( dst,contours, largest_contour_index, Scalar(255,255,255),CV_FILLED, 8, hierarchy ); vector > contours_poly(1); approxPolyDP( Mat(contours[largest_contour_index]), contours_poly[0],5, true ); Rect boundRect=boundingRect(contours[largest_contour_index]); if(contours_poly[0].size()==4){ std::vector quad_pts; std::vector squre_pts; quad_pts.push_back(Point2f(contours_poly[0][0].x,contours_poly[0][0].y)); quad_pts.push_back(Point2f(contours_poly[0][1].x,contours_poly[0][1].y)); quad_pts.push_back(Point2f(contours_poly[0][3].x,contours_poly[0][3].y)); quad_pts.push_back(Point2f(contours_poly[0][2].x,contours_poly[0][2].y)); squre_pts.push_back(Point2f(boundRect.x,boundRect.y)); squre_pts.push_back(Point2f(boundRect.x,boundRect.y+boundRect.height)); squre_pts.push_back(Point2f(boundRect.x+boundRect.width,boundRect.y)); squre_pts.push_back(Point2f(boundRect.x+boundRect.width,boundRect.y+boundRect.height)); Mat transmtx = getPerspectiveTransform(quad_pts,squre_pts); Mat transformed = Mat::zeros(src.rows, src.cols, CV_8UC3); warpPerspective(src, transformed, transmtx, src.size()); Point P1=contours_poly[0][0]; Point P2=contours_poly[0][1]; Point P3=contours_poly[0][2]; Point P4=contours_poly[0][3]; line(src,P1,P2, Scalar(0,0,255),1,CV_AA,0); line(src,P2,P3, Scalar(0,0,255),1,CV_AA,0); line(src,P3,P4, Scalar(0,0,255),1,CV_AA,0); line(src,P4,P1, Scalar(0,0,255),1,CV_AA,0); rectangle(src,boundRect,Scalar(0,255,0),1,8,0); rectangle(transformed,boundRect,Scalar(0,255,0),1,8,0); imshow("quadrilateral", transformed); imshow("thr",thr); imshow("dst",dst); imshow("src",src); imwrite("result1.jpg",dst); imwrite("result2.jpg",src); imwrite("result3.jpg",transformed); waitKey(); } else cout< <"Make sure that your are getting 4 corner using approxPolyDP..."< 

Por lo general, esto sucede cuando confías en otro código para resolver tu problema en particular en lugar de adoptar el código. Observe las etapas de procesamiento y también la diferencia entre ellas y su imagen (por cierto, es una buena idea comenzar con su imagen y asegurarse de que el código funcione):

  1. Obtener el mapa de borde. – Probablemente funcionará ya que sus bordes están bien
  2. Detecta líneas con la transformada Hough. – fallar ya que tiene líneas no solo en el contorno sino también dentro de su tarjeta. Así que espera una gran cantidad de líneas de falsa alarma
  3. Obtenga las esquinas al encontrar intersecciones entre líneas. – fallar por el motivo mencionado anteriormente
  4. Verifica si la curva poligonal aproximada tiene 4 vértices. – fallar
  5. Determine la esquina superior izquierda, inferior izquierda, superior derecha e inferior derecha. – fallar
  6. Aplicar la transformación de perspectiva. – falla completamente

Para solucionar su problema, debe asegurarse de que solo se extraigan las líneas de la periferia. Si siempre tiene un fondo oscuro, puede usar este hecho para descartar las líneas con otros contrastes / polaridades. Alternativamente, puede extraer todas las líneas y luego seleccionar las más cercanas al límite de la imagen (si su fondo no tiene líneas).