Skip to content

Instantly share code, notes, and snippets.

@Duologic
Last active April 12, 2019 16:49
Show Gist options
  • Save Duologic/27f9185a565b3f32721850298db1811f to your computer and use it in GitHub Desktop.
Save Duologic/27f9185a565b3f32721850298db1811f to your computer and use it in GitHub Desktop.
Tesseract POC
<!DOCTYPE html>
<html>
<head>
<script src='https://cdn.jsdelivr.net/gh/naptha/[email protected]/dist/tesseract.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/camanjs/4.0.0/caman.full.js'></script>
<script type="text/javascript">
var stopIt = false;
var sleep = function (ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// crop out the required pieces
var captureImage = function(x, y, width, height) {
var video = document.getElementById("videoElement");
var canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
canvas.getContext('2d').drawImage(video, x, y, width, height, 0, 0, width, height);
return canvas;
};
// render the image with Caman with random exposure and contrast
var renderImage = function(canvas, name, callback) {
var output = document.getElementById('output');
var exposure = Math.floor(Math.random() * Math.floor(10))*10
var contrast = Math.floor(Math.random() * Math.floor(10))*10
var img = document.getElementById('image'+name+exposure+contrast);
if(img === null){
img = document.createElement("img");
img.id = 'image'+name+exposure+contrast;
}
img.src = canvas.toDataURL();
output.append(img);
output.append(document.createElement('br'));
console.log(exposure);
console.log(contrast);
Caman(img, function () {
this.greyscale();
this.exposure(exposure);
this.contrast(contrast);
this.render(callback(this.canvas));
});
};
// do the actual OCR with Tesseract doing the heavy lifting
var doOCR = function(image, characters, callback) {
var min_length = 3;
Tesseract
.recognize(image, {tessedit_char_whitelist: characters,
certainty_scale: 80})
.progress(function (p) {
/*console.log('progress', p);*/
})
.then(function (result) {
console.log('result', result);
var confidence = 0;
var best_match;
for(i=0; i<result.words.length; i++){
var word = result.words[i];
if(word.text.length > min_length && word.confidence > confidence){
best_match = word;
}
}
callback(best_match);
});
}
// tie it all together
var getWord = function(canvas, name, characters, callback) {
renderImage(canvas, name, function(canvas){
var img = canvas.getContext('2d');
doOCR(img, characters, function(word){
if(word !== undefined) {
console.log('confidence', word.confidence);
console.log('word', word.text);
}
callback(word);
});
});
};
var setClass = function(element, cls) {
element.classList.remove('doing');
element.classList.remove('complete');
element.classList.add(cls);
}
// get the words and drop the words with confidence into the <input>
var grab = function(canvas, elid, characters, callback) {
var confidence = 0
var best_match = '';
setClass(document.getElementById(elid), 'doing');
getWord(canvas, elid, characters, function(word) {
if(word !== undefined && confidence < word.confidence){
confidence = word.confidence;
best_match = word.text;
}
if(confidence > 80) {
document.getElementById(elid).value = word.text.toUpperCase();
setClass(document.getElementById(elid), 'complete');
return
}
if(confidence > 60) {
document.getElementById(elid).value = best_match.toUpperCase();
setClass(document.getElementById(elid), 'best_match');
}
if(confidence < 80) {
if(stopIt){
return
}
sleep(2);
callback();
}
});
};
var grabLicensePlate = function() {
var canvas = captureImage(415, 145, 120, 25);
var elid = 'licenseplate';
var characters = '-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
grab(canvas, elid, characters, grabLicensePlate)
};
var grabChassisnumber = function() {
var canvas = captureImage(370, 370, 215, 30);
var elid = 'chassisnumber';
var characters = '()ABCDEFGHJKLMNPRSTUVWXYZ0123456789'
grab(canvas, elid, characters, grabChassisnumber)
};
</script>
<style>
.doing {
border-color: red;
}
.doing.best_match {
border-color: orange;
}
.complete {
border-color: green;
}
body {
margin: 0px 0px;
padding: 0px 0px;
}
input {
width: 600px;
font-size: 20px;
}
#videoElement,
.container {
width: 640px;
height: 480px;
}
#output,
.container {
position: relative;
}
#output{
display: none;
}
.block {
border: 1px solid black;
position: absolute;
background-color: white;
opacity: .6;
}
.block.PLATE {
left: 405px;
top: 145px;
width: 140px;
height: 30px;
}
.block.VIN {
left: 365px;
top: 360px;
width: 230px;
height: 40px;
}
#videoElement {
background-color: #666;
}
</style>
</head>
<body>
<div class="container">
<video autoplay="true" controls="true" id="videoElement"></video>
<div class="block PLATE"></div>
<div class="block VIN"></div>
</div>
<div id="output"></div>
<input type="text" id='licenseplate'/>
<input type="text" id='chassisnumber'/>
<script type="text/javascript">
var video = document.querySelector("#videoElement");
var constraints = {
video:
{
width: 640,
height: 480,
facingMode: 'environment'
}
}
if (navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
video.srcObject = stream;
})
.catch(function(err) {
console.log(err.name + ": " + err.message);
alert(err.name + ": " + err.message);
});
}
video.onpause = function() {
stopIt = true;
}
video.onplaying = function() {
stopIt = false;
grabLicensePlate();
grabChassisnumber();
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment