Los Caballeros

"Sobre seguridad, programación, modding, frikismo, etc... "

OCR con OpenCV usando Canny

Twitter icon Twitter icon
Xianur0 reportándose (aja, sigo vivo xD)

Imagen:

Resultado:




Este es un algoritmo mas de OCR que me arme usando OpenCV y el algoritmo Canny (y algunas otras ideas de mi invención).

Como funciona?

Primero se realiza la segmentación con ayuda de canny (bordes encontrados), es decir mediante canny se elimina basura de la imagen y ademas nos permite separar cosas del fondo, en este caso texto, ya que se tienen las letras (o caracteres) en versión de bordes únicamente tenemos que realizar un barrido horizontal y vertical para separar las letras, luego en caso de ser necesario un doble barrido por sector separado, de este modo tendremos las letras específicamente separadas del fondo, las cuales podemos fácilmente copiar y pegar e indicar que es lo que tiene cada cuadro, de este modo mediante comparación de pixeles podemos hacer que el sistema deduzca que es lo que hay en el cuadro... como verán el detalle seria el tamaño, pero únicamente hay que agregar una función para re-dimensionar y poner un tamaño estándar y tendremos un OCR bastante efectivo y fácil de "entrenar". Saludos!

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <stdio.h>
#include <iostream>

// By Xianur0
// http://hackingtelevision.blogspot.com/

using namespace cv;
using namespace std;

void help()
{
cout <<
"\nSegmentacion usando canny\n"
"./espacips [imagen]\n" << endl;

}

int edgeThresh = 100;
Mat image, gray, edge, cedge;

IplImage * cortar(IplImage *in, int x, int y, int w, int h) {
cvSetImageROI(in, cvRect(x, y, w, h));
IplImage *img = cvCreateImage(cvGetSize(in),
in->depth,
in->nChannels);
cvCopy(in, img, NULL);
cvResetImageROI(in);
return img;
}

void procesarcaracteres(IplImage *in, int id) {
int x,y = 0;
IplImage *in2 = cvCreateImage(cvGetSize(in),
in->depth,
in->nChannels);
cvCopy(in,in2, NULL);
char *data = in->imageData;
char *data2 = in2->imageData;
int tmp[2];
tmp[0] = 0;
tmp[1] = 0;
int tlineasv = 0;
int anteriorx=0;
int anteriory=0;
int lineaanterior = 0;
int lineas[in->height];
for(x=0;x<in->width;x++) {
for(y=0;y<in->height;y++) {
if(
data[y*in->widthStep+x*in->nChannels] != 0 ||
data[y*in->widthStep+x*in->nChannels+1] != 0 ||
data[y*in->widthStep+x*in->nChannels+2] != 0
) {
if(tmp[0] != x) {
tmp[0] = x;
tmp[1] = y;
break;
}
}
}
if(abs(tmp[0]-anteriorx) > 1) {
if((abs(tmp[1]-anteriory) < 2 || abs(tmp[0]-anteriorx) > 3 || abs(tmp[1]-anteriory) > 3) && (lineaanterior == 0 || abs(lineaanterior-tmp[0]) > 10)) {
// printf("Trazando linea verticales: (X: %i)\n",x);
lineas[tlineasv] = x;
for(y=(in->height-1);y>=0;y--) {
data2[y*in->widthStep+x*in->nChannels] = 0;
data2[y*in->widthStep+x*in->nChannels+1] = 0;
data2[y*in->widthStep+x*in->nChannels+2] = 255;
}
tlineasv++;
}
lineaanterior = tmp[0];
}
anteriorx = tmp[0];
anteriory = tmp[1];
}
x = tmp[0];
lineas[tlineasv] = x;
for(y=(in->height-1);y>=0;y--) {
data2[y*in->widthStep+x*in->nChannels] = 255;
data2[y*in->widthStep+x*in->nChannels+1] = 255;
data2[y*in->widthStep+x*in->nChannels+2] = 255;
}
tlineasv++;
// printf("Comenzando a recortar...\n");
if(tlineasv >=2)
for(x = 0; x < tlineasv-1; x++){
if(x+1 >= tlineasv) lineas[x+1] = in->width;
char buff[(sizeof(int)*2)+3];
sprintf(buff,"c%i: %i",id,x);
imshow(buff,cortar(in,lineas[x],0,(lineas[x+1]-lineas[x]),in->height));
}
char buff[sizeof(int)];
sprintf(buff,"%i",id);
imshow(buff, in2);
}


void procesarlineas(IplImage *in) {
IplImage* in2 = cvCreateImage(cvGetSize(in),
in->depth,
in->nChannels);
cvCopy(in,in2, NULL);
int x,y = 0;
char *data = in->imageData;
char *data2 = in2->imageData;
int tmp[2];
tmp[0] = 0;
tmp[1] = 0;
int tlineash = 0;
int tlineasv = 0;
int anterior=0;
int lineaanterior = 0;
int lineas[in->height];
for(y=0;y<in->height;y++) {
for(x=0;x<in->width;x++) {
if(
data[y*in->widthStep+x*in->nChannels] != 0 ||
data[y*in->widthStep+x*in->nChannels+1] != 0 ||
data[y*in->widthStep+x*in->nChannels+2] != 0
) {
if(tmp[1] != y) {
tmp[0] = x;
tmp[1] = y;
break;
}
}
}
if(abs(tmp[1]-anterior) > 2) {
if(lineaanterior == 0 || abs(lineaanterior-tmp[1]) > 10) {
lineas[tlineash] = y;
// printf("Dibujando %i...\n",y);
for(x=(in->width-1);x>=0;x--) {
data2[y*in->widthStep+x*in->nChannels] = 255;
data2[y*in->widthStep+x*in->nChannels+1] = 255;
data2[y*in->widthStep+x*in->nChannels+2] = 255;
}
tlineash++;
}
lineaanterior = tmp[1];
}
anterior = tmp[0];
}
y = tmp[1];
lineas[tlineash] = y;
for(x=(in->width-1);x>=0;x--) {
data2[y*in->widthStep+x*in->nChannels] = 255;
data2[y*in->widthStep+x*in->nChannels+1] = 255;
data2[y*in->widthStep+x*in->nChannels+2] = 255;
}
tlineash++;
// printf("Comenzando a recortar...\n");
if(tlineash >=2)
for(x = 0; x < tlineash-1; x++){
// printf("Recortando: (%i,%i,%i)\n",lineas[x],in->width,(lineas[x+1]-lineas[x]));
if(x+1 >= tlineash) lineas[x+1] = in->height;
procesarcaracteres(cortar(in,0,lineas[x],in->width,(lineas[x+1]-lineas[x])),x);
}
// printf("Lineas encontradas: %i\n",tlineash);
}
void onTrackbar(int, void*)
{
blur(gray, edge, Size(3,3));
Canny(edge, edge, edgeThresh, edgeThresh*3, 3);
cedge = Scalar::all(0);
image.copyTo(cedge, edge);
IplImage *in = new IplImage(cedge);
procesarlineas(in);
}

int main( int argc, char** argv )
{
char* filename = argc == 2 ? argv[1] : (char*)"Android.jpg";
image = imread(filename, 1);
if(image.empty())
{
help();
return -1;
}
help();
cedge.create(image.size(), image.type());
cvtColor(image, gray, CV_BGR2GRAY);
namedWindow("Segmentacion con Canny", 1);
createTrackbar("Nivel", "Segmentacion con Canny", &edgeThresh, 100, onTrackbar);
onTrackbar(0, 0);
waitKey(0);

return 0;
}

1 comentario:

walterinho dijo...

Me parece muy bueno su aporte compañeros...

Y les agradezco mucho que lo compartan...

A la vez quería consultarles, yo realice la implementación del código, pero en ningún momento se realiza la identificación de los caracteres, y ademas analizando detalladamente el código no puedo encontrar en que parte la realizan...

No se si me pueden ayudar con este pequeño problema...

Gracias