HTML5 Canvas手写字识别

今天又网友在论坛里问到关于 HTML5 手写字识别功能。这个功能看似有点难度,单独借助HTML5是无法实现的。我这里借助去年百度开发者大赛上的作品来实现它。

Canvas 绘图

我们首先要使用 Canvas 来实现绘图功能。代码如下:

<html> 
 <head> 
  <title>业余草:www.xttblog.com write demo</title> 
  </head> 
 <body> 
 <!-- 业余草:www.xttblog.com -->
<canvas width="800" height="450"></canvas> 
<script> 
 var canvas = document.getElementsByTagName('canvas')[0]; 
 canvas.addEventListener('mousemove', onMouseMove, false); 
 canvas.addEventListener('mousedown', onMouseDown, false); 
 canvas.addEventListener('mouseup', onMouseUp, false); 
   
 var context = canvas.getContext('2d'); 
 var linex = new Array(); 
 var liney = new Array(); 
 var linen = new Array(); 
   
 var lastX = -1; 
 var lastY = -1; 
 var hue = 0; 
 var flag = 0; 
   
 function onMouseMove(evt) { 
    if (flag == 1) { 
       linex.push(evt.layerX); 
       liney.push(evt.layerY); 
       linen.push(1); 
       context.save(); 
       context.translate(context.canvas.width/2, context.canvas.height/2); 
       context.translate(-context.canvas.width/2, -context.canvas.height/2); 
       context.beginPath(); 
       context.lineWidth = 5 + Math.random() * 10; 
   
       for (var i=1;i<linex.length;i++) { 
             lastX = linex[i]; 
             lastY = liney[i]; 
             if (linen[i] == 0) { 
                context.moveTo(lastX,lastY); 
             } else { 
                context.lineTo(lastX,lastY); 
             } 
       } 
   
       hue = hue + 10 * Math.random(); 
       context.strokeStyle = 'hsl(' + hue + ', 50%, 50%)'; 
       context.shadowColor = 'white'; 
       context.shadowBlur = 10; 
       context.stroke(); 
       context.restore(); 
    } 
 } 
 function onMouseDown(evt) { 
    flag = 1; 
    linex.push(evt.layerX); 
    liney.push(evt.layerY); 
    linen.push(0); 
 } 
 function onMouseUp(evt) { 
    flag = 0; 
     linex.push(evt.layerX); 
     liney.push(evt.layerY); 
    linen.push(0); 
 } 
</script> 
</body> 
</html>

html2canvas 网页截屏

上面我们只实现了绘图的功能,还不能实现识别文字的功能。要实现文字识别,我们要借助OCR功能。整体实现流程如下:

Canvas 画图 ——> html2canvas 插件截图 ——> 截图的图片通过百度ocr api 进行文字识别——> 展示识别后的结果。

关于 canvas 截图的功能,请查看我的这篇文章:使用html2canvas实现网页截屏功能

百度 OCR api 调用

百度 OCR 接口目前已不对外提供服务了,大家另外去找OCR 的接口。我这里使用的百度OCR的实例就不在公布了。说下百度OCR文字识别的用法:

接口地址 :http://apis.baidu.com/apistore/idlocr/ocr
请求方法 :POST

import java.io.BufferedReader; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.net.HttpURLConnection; 
import java.net.URL; 
import sun.misc.BASE64Encoder; 
public class Request { 
    public static void main(String[] args){ 
        String httpUrl = "http://apis.baidu.com/apistore/idlocr/ocr"; 
        String imagePath="图片的路径"; 
        String str=encodeImgageToBase64(imagePath); 
        str = str.replace("\r\n", ""); 
        str= URLEncoder.encode(str, "utf-8");//很重要的,刚开始就是因为没有加,所以怎么看结果怎么不合理 
        String httpArg = "fromdevice=pc&clientip=172.0.0.1&detecttype=LocateRecognize&"+ 
        "languagetype=CHN_ENG&imagetype=1"+ 
        "&image="+str; 
        String jsonResult = request(httpUrl, httpArg); 
        System.out.println(jsonResult); 
    } 
    /**
     * @param urlAll:请求接口
     * @param httpArg :参数
     * @return 返回结果
     */ 
    public static String request(String httpUrl, String httpArg) { 
        BufferedReader reader = null; 
        String result = null; 
        StringBuffer sbf = new StringBuffer(); 
        try { 
            URL url = new URL(httpUrl); 
            HttpURLConnection connection = (HttpURLConnection) url 
                    .openConnection(); 
            connection.setRequestMethod("POST"); 
            connection.setRequestProperty("Content-Type", 
                            "application/x-www-form-urlencoded"); 
            // 填入apikey到HTTP header 
            connection.setRequestProperty("apikey",  "你的apikey"); 
            connection.setDoOutput(true); 
            connection.getOutputStream().write(httpArg.getBytes("UTF-8")); 
            connection.connect(); 
            InputStream is = connection.getInputStream(); 
            reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); 
            String strRead = null; 
            while ((strRead = reader.readLine()) != null) { 
                sbf.append(strRead); 
                sbf.append("\r\n"); 
            } 
            reader.close(); 
            result = sbf.toString(); 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } 
        return result; 
    } 
       
    /** 
     * 将本地图片进行Base64位编码 
     * @param imgUrl 图片的url路径,如d:\\中文.jpg 
     * @return 
     */   
    public static String encodeImgageToBase64(String imagePath) {
    // 将图片文件转化为字节数组字符串,并对其进行Base64编码处理   
        // 其进行Base64编码处理   
        byte[] data = null;   
        // 读取图片字节数组   
        try {   
            File imageFile = new File(imagePath); 
            InputStream in = new FileInputStream(imageFile);   
            data = new byte[in.available()];   
            in.read(data);   
            in.close();   
        } catch (IOException e) {   
            e.printStackTrace();   
        }   
         
        // 对字节数组Base64编码   
        BASE64Encoder encoder = new BASE64Encoder();   
        return encoder.encode(data);// 返回Base64编码过的字节数组字符串   
    }  
}

主要代码已贴出。重要的还是思路。

运行效果

image.png