opencv - turnos - Detectando la tarjeta nacional de identidad y obteniendo los detalles.
turno para dni adrogue (3)
Ahora existe la biblioteca PassportEye disponible para este propósito. No es perfecto, pero funciona bastante bien en mi experiencia: https://pypi.python.org/pypi/PassportEye/
Estoy tratando de detectar el ID nacional del siguiente tipo y obtener los detalles del mismo. Por ejemplo, la ubicación de la firma se debe encontrar en la esquina superior derecha de la imagen de la persona, en este caso "BC".
Necesito hacer esta aplicación en iphone. Pensé en usar Opencv para ello, pero ¿cómo puedo lograr los detalles marcados? ¿Necesito entrenar la aplicación con tarjetas similares o el OCR podría ayudar?
¿Hay implementaciones específicas para aplicaciones móviles?
También pasé por card-io, que detecta los detalles de la tarjeta de crédito, ¿Card-io también detecta los otros detalles de la tarjeta?
Actualizar:
He utilizado tesseract para la detección de texto. Tesseract funciona bien si la imagen tiene solo texto. Así que recorté las regiones marcadas en rojo y, dado como entrada a Tesseract, funciona bien con la parte MRZ.
Hay una implementación de IOS para Tesseract, con la que he probado.
¿Lo que necesito hacer?
Ahora estoy tratando de automatizar la parte de detección de texto. Ahora estoy planeando automatizar los siguientes elementos,
1) Recortar la cara (he terminado de usar el detector de caras Viola-jones).
2) Debe tomar la inicial en este ejemplo "BC" de la foto.
3) Extraer / detectar la región MRZ de la tarjeta de identificación.
Estoy tratando de hacer 2 y 3, cualquier idea o fragmento de código sería genial.
Card.io está diseñado específicamente para tarjetas de crédito en relieve. No funcionará para este caso de uso.
Suponiendo que estas ID se preparen de acuerdo con una plantilla estándar que tenga anchos, alturas, compensaciones, espacios, etc. específicos, puede probar un enfoque basado en plantillas.
MRZ sería fácil de detectar. Una vez que lo detecte en la imagen, encuentre la transformación que le asigna la ZLM en su plantilla. Cuando conoce esta transformación, puede asignar cualquier región en su plantilla (por ejemplo, la foto de la persona) a la imagen y extraer esa región.
A continuación se muestra un programa muy simple que sigue un camino feliz. Tendrá que hacer más procesamiento para ubicar la MRZ en general (por ejemplo, si hay distorsiones o rotaciones de perspectiva). Preparé la plantilla solo midiendo la imagen, y no funcionará para su caso. Solo quería transmitir la idea. La imagen fue tomada de wiki
Mat rgb = imread(INPUT_FILE);
Mat gray;
cvtColor(rgb, gray, CV_BGR2GRAY);
Mat grad;
Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
morphologyEx(gray, grad, MORPH_GRADIENT, morphKernel);
Mat bw;
threshold(grad, bw, 0.0, 255.0, THRESH_BINARY | THRESH_OTSU);
// connect horizontally oriented regions
Mat connected;
morphKernel = getStructuringElement(MORPH_RECT, Size(9, 1));
morphologyEx(bw, connected, MORPH_CLOSE, morphKernel);
// find contours
Mat mask = Mat::zeros(bw.size(), CV_8UC1);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(connected, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
vector<Rect> mrz;
double r = 0;
// filter contours
for(int idx = 0; idx >= 0; idx = hierarchy[idx][0])
{
Rect rect = boundingRect(contours[idx]);
r = rect.height ? (double)(rect.width/rect.height) : 0;
if ((rect.width > connected.cols * .7) && /* filter from rect width */
(r > 25) && /* filter from width:hight ratio */
(r < 36) /* filter from width:hight ratio */
)
{
mrz.push_back(rect);
rectangle(rgb, rect, Scalar(0, 255, 0), 1);
}
else
{
rectangle(rgb, rect, Scalar(0, 0, 255), 1);
}
}
if (2 == mrz.size())
{
// just assume we have found the two data strips in MRZ and combine them
CvRect max = cvMaxRect(&(CvRect)mrz[0], &(CvRect)mrz[1]);
rectangle(rgb, max, Scalar(255, 0, 0), 2); // draw the MRZ
vector<Point2f> mrzSrc;
vector<Point2f> mrzDst;
// MRZ region in our image
mrzDst.push_back(Point2f((float)max.x, (float)max.y));
mrzDst.push_back(Point2f((float)(max.x+max.width), (float)max.y));
mrzDst.push_back(Point2f((float)(max.x+max.width), (float)(max.y+max.height)));
mrzDst.push_back(Point2f((float)max.x, (float)(max.y+max.height)));
// MRZ in our template
mrzSrc.push_back(Point2f(0.23f, 9.3f));
mrzSrc.push_back(Point2f(18.0f, 9.3f));
mrzSrc.push_back(Point2f(18.0f, 10.9f));
mrzSrc.push_back(Point2f(0.23f, 10.9f));
// find the transformation
Mat t = getPerspectiveTransform(mrzSrc, mrzDst);
// photo region in our template
vector<Point2f> photoSrc;
photoSrc.push_back(Point2f(0.0f, 0.0f));
photoSrc.push_back(Point2f(5.66f, 0.0f));
photoSrc.push_back(Point2f(5.66f, 7.16f));
photoSrc.push_back(Point2f(0.0f, 7.16f));
// surname region in our template
vector<Point2f> surnameSrc;
surnameSrc.push_back(Point2f(6.4f, 0.7f));
surnameSrc.push_back(Point2f(8.96f, 0.7f));
surnameSrc.push_back(Point2f(8.96f, 1.2f));
surnameSrc.push_back(Point2f(6.4f, 1.2f));
vector<Point2f> photoDst(4);
vector<Point2f> surnameDst(4);
// map the regions from our template to image
perspectiveTransform(photoSrc, photoDst, t);
perspectiveTransform(surnameSrc, surnameDst, t);
// draw the mapped regions
for (int i = 0; i < 4; i++)
{
line(rgb, photoDst[i], photoDst[(i+1)%4], Scalar(0,128,255), 2);
}
for (int i = 0; i < 4; i++)
{
line(rgb, surnameDst[i], surnameDst[(i+1)%4], Scalar(0,128,255), 2);
}
}
Resultado: foto y apellidos regiones en color naranja. MRZ en azul.