Hemos implementado un OCR standard para proveer a nuestras apps de esta funcionalidad, permitiendo la lectura directa de documentos o matrículas de coches. Básicamente su funcionamiento se basa en el desarrollado de un Plugin, que junto con el Framework y la Aplicación, realizará el proceso de la lectura de una matrícula o documento, utilizando para ello la cámara del dispositivo.

Para una mejor solución y que al usuario le sea más sencillo obtener el valor correcto en la lectura del documento o de la matrícula, se ha desarrollado la funcionalidad como si fuera una cámara de vídeo, de tal forma que la lectura de la misma se va mostrando en la pantalla del dispositivo en tiempo real, y al final el usuario podrá seleccionar la opción correcta, para que resulte aún más sencillo seleccionar la opción “correcta”, se pondrá en azul la opción que tenga una alta probabilidad de ser la correcta y con fondo verde la opción que el sistema haya dado como válida más de cuatro veces durante el escaneo en tiempo real de la matrícula.



Ejemplos de Implementación y Uso

<coll name="MenuEntrada" special="true" notab="true">
    <group name="General" id="1">
        <frame name="todo" width="100%" height="100%" scroll="true">
            <prop type="B" name="MAP_NUEVAFOTO" title="Nueva foto" method="ExecuteNode(nuevafoto)" width="100%" height="10%" labelwidth="10" tmargin="0" />
            <prop type="T" name="MAP_SELECTORIMAGENES" visible="1" labelwidth="10" width="100%" title="Imagen seleccionada" tmargin="0" />
            <prop type="Z" name="MAP_IMAGENES" width="100%" height="50%" tmargin="0" contents="ContentImagenes" />
            <prop type="T" name="MAP_MATRICULA" visible="1" labelwidth="10" width="100%" title="Matrícula" />
            <prop type="TL" name="MAP_TEXTOLABEL" visible="1" labelwidth="10" align="center" labelbox="false" width="100%" title="Texto OCR" />
            <prop type="T" name="MAP_TEXTO" visible="1" labelwidth="0" width="100%" />
            <prop type="B" name="MAP_ESCANEARMATRICULA" title="Escanear matrícula" method="ExecuteNode(escanearMatricula)" width="100%" height="10%" labelwidth="10" />
            <prop type="B" name="MAP_ESCANEARMATRICULACAMARA" title="Escanear matrícula cámara" method="ExecuteNode(escanearMatriculaCamara)" width="100%" height="10%" labelwidth="10" />
            <prop type="B" name="MAP_ESCANEAROCR" title="OCR" method="ExecuteNode(escanearOcr)" width="100%" height="10%" labelwidth="10" />
            <prop type="B" name="MAP_SCAN_WITH_V3" title="scanWithV3" onclick="scanWithV3();" width="100%" height="10%" labelwidth="10" />
            <prop type="B" name="MAP_SCAN_WITH_REGEX" title="scanWithRegex" onclick="scanWithRegex();" width="100%" height="10%" labelwidth="10" />
            <prop type="B" name="MAP_SALIR" title="Salir" method="ExecuteNode(salir)" width="100%" height="10%" labelwidth="10" />
            <prop type="T" name="MAP_HIJO_SELECCIONADO" visible="0" />
        </frame>
        <contents name="ContentImagenes" src="Imagenes" />
    </group>
    <before-edit refresh="false" show-wait-dialog="false">
        <action name="runscript">
            <script language="vbscript">
                Dim contentImagenes, obj, filemanager
                contentImagenes = this.Contents("ContentImagenes")
                filemanager = CreateObject("FileManager")
                lst = filemanager.ListFiles()
                If Not lst Is Nothing Then
                For i = 0 To UBound(lst)
                	obj = contentImagenes.createObject
                	contentImagenes.addItem(obj)
                	obj("MAP_IMAGEN") = lst(i)
                Next
                Else
                    ui.ShowToast "No hay nada..."
                End If
                contentImagenes.lock
                ui.refresh
            </script>
        </action>
    </before-edit>
    <onchange refresh="false" show-wait-dialog="false">
        <field name="MAP_SELECTORIMAGENES">
            <action name="runscript">
                <script>
                    //self.MAP_IMAGEN = self.MAP_SELECTORIMAGENES;
                </script>
            </action>
        </field>
    </onchange>
    <nuevafoto refresh="false" show-wait-dialog="false">
        <action name="runscript">
            <script language="vbscript">
                ui.startCamera "photo", ""
            </script>
        </action>
    </nuevafoto>
    <refrescar refresh="false" show-wait-dialog="false">
        <action name="runscript">
            <script>
                ui.refresh();
            </script>
        </action>
    </refrescar>
    <salir refresh="false" show-wait-dialog="false">
        <action name="runscript">
            <script>
                appData.failWithMessage(-11888, "##EXITAPP##");
            </script>
        </action>
    </salir>
    <escanearMatricula refresh="false">
        <action name="runscript">
            <script>
                let ventana = ui.getView(self);
                let result = escanearMatricula(self.MAP_SELECTORIMAGENES);
                self.MAP_MATRICULA = result;
                self.MAP_HIJO_SELECCIONADO.MAP_MATRICULA = result;
                if (result != "") {
                    self.MAP_HIJO_SELECCIONADO.MAP_RECONOCIDO = 1;
                } else {
                    self.MAP_HIJO_SELECCIONADO.MAP_RECONOCIDO = 0;
                }
                ventana.refreshContentSelectedRow("MAP_IMAGENES");
                ventana.refresh("MAP_MATRICULA");
            </script>
        </action>
    </escanearMatricula>
    <escanearMatriculaCamara refresh="false">
        <action name="runscript">
            <script>
                escanearMatriculaCamara();
            </script>
        </action>
    </escanearMatriculaCamara>
    <escanearOcr refresh="false">
        <action name="runscript">
            <script>
                let result = escanearTexto(self.MAP_SELECTORIMAGENES);
                self.MAP_TEXTO = result;
                ui.refresh("MAP_TEXTO");
            </script>
        </action>
    </escanearOcr>
</coll>
function escanearMatricula(rutaImagen) {
	let ocr = getXOneOCR();
 
	let opciones = {
		//Common
		ocr_img_size_percent : 1.33333333,
		state_id_img_size_percent : 2.0,
		max_plate_width_percent : 100,
		max_plate_height_percent : 100,
		detection_iteration_increase : 1.5,
		detection_strictness : 2,
		max_detection_input_width : 4000,
		max_detection_input_height : 3000,
		opencl_enabled : 1,
		multithreading_cores : 8,
		max_plate_angle_degrees : 15,
		ocr_min_font_point : 6,
		postprocess_min_confidence : 65,
		postprocess_confidence_skip_level : 80,
		postprocess_max_substitutions : 2,
		postprocess_min_characters : 4,
		postprocess_max_characters : 8,
 
		//Debug
		general       : 0,
		timing        : 0,
		state_id      : 0,
		plate_lines   : 0,
		plate_corners : 0,
		char_regions  : 0,
		char_segment  : 0,
		char_analysis : 0,
		color_filter  : 0,
		ocr           : 0,
		postprocess   : 0,
		show_images   : 0,
		pause_on_frame : 0,
 
		//EU
		char_analysis_min_pct : 0.35,
		char_analysis_height_range : 0.15,
		char_analysis_height_step_size : 0.10,
		char_analysis_height_num_steps : 5,
		segmentation_min_box_width_px : 5,
		segmentation_min_charheight_percent : 0.4,
		segmentation_max_segment_width_percent_vs_average : 2.0,
		plate_width_mm : 520,
		plate_height_mm : 110,
		char_height_mm : 80,
		char_width_mm : 53,
		char_whitespace_top_mm : 10,
		char_whitespace_bot_mm : 10,
		template_max_width_px : 184,
		template_max_height_px : 46,
		plateline_sensitivity_vertical : 18,
		plateline_sensitivity_horizontal : 55,
		min_plate_size_width_px : 5,
		min_plate_size_height_px : 5,
		multiline : 1,
		ocr_language : "leu"
	};
	return ocr.scanLicensePlate(rutaImagen, opciones);
	//return ocr.scanLicensePlate(rutaImagen);
}
 
function escanearMatriculaCamara(rutaImagen) {
	let ocr = getXOneOCR();
	let opciones = {
		withCamera : true,
		mode: 1,
		onResult : function(sData) {
			ui.showToast("Result callback: " + sData);
			self.MAP_MATRICULA = sData;
			let ventana = ui.getView(self);
			ventana.refresh("MAP_MATRICULA");
		}
	};
	ocr.scanLicensePlate(rutaImagen, opciones);
}
 
function scanWithV3() {
    let ocr = new XOneOCR();
    let options = {
        mode : 3,
        detections: 5,
        regex:["[a-zA-Z0-9]"],
        onResult : function(sData) {
            ui.showToast("Result callback: " + sData);
			self.MAP_MATRICULA = sData;
			let ventana = ui.getView(self);
			ventana.refresh("MAP_MATRICULA");
        },
    };
    ocr.scanLicensePlate(appData.getFilesPath(), options);
}
 
const REGEX_MATRICULA_MODERNA = "^\\d{4} *[A-Z]{3}";
 
function scanWithRegex() {
    let ocr = new XOneOCR();
    let options = {
        // Pueden ser varias expresiones regulares
        regex    : [REGEX_MATRICULA_MODERNA],
        // Si detectar una matrícula y cerrar, o si continuar hasta que se diga
        oneShot  : false,
        onResult : function(jsResult) {
            self.MAP_MATRICULA = jsResult[REGEX_MATRICULA_MODERNA];
            //Usar jsResult[sLaRegexUsada] si se especificaron varias
			//self.MAP_MATRICULA = jsResult.alltext;
			ui.showToast("Result callback: " + self.MAP_MATRICULA);
        }
    };
    ocr.startScan(options);
}
 
function escanearTexto(rutaImagen) {
	let ocr = getXOneOCR();
	return ocr.scanText(rutaImagen, {
		characterWhitelist: '����������qwertyuiopasdfghjklzxcvbn�mQWERTYUIOPASDFGHJKLZXCVBN�M'
	});
}
 
function getXOneOCR() {
	//return createObject("XOneOCR");
	return new XOneOCR();
}


Desde XOne nos hemos integrado a través de SDK con la tecnología OCR de , empresa desarrolladora de productos y soluciones de reconocimiento óptico de caracteres de alto rendimiento, con un enfoque en el reconocimiento de matrículas en cualquier escenario desde cualquier plataforma.
Esta tecnología es ampliamente reconocida como una de las más avanzadas del mundo por poseer OCR con características y beneficios de Alta precisión,tasa de reconocimiento superior al 99%, Soporte de texto multidireccional y operación de alta velocidad.
Para su integración se genera un plugin XOne para relacionarnos con SDK de VAXTOR.

Para esta integración es necesario poseer licencia de VAXTOR.


Otra de las integraciones de XOne de OCR por SDK se ha realizado con la empresa imenselogogrey.jpg desarrolladora de softwares de visión artificial aplicado a todos los campos relacionados con el reconocimiento de números y letras en imágenes, desde placas de automóviles y vehículos (ANPR / ALPR) hasta aplicaciones de seguridad de tarjetas de identificación y licencias de conducir.

Para su integración se genera un plugin XOne para relacionarnos con SDK de IMENSE.

Para esta integración es necesario poseer licencia de IMENSE.