天天看点

Android文字图像识别并翻译的简单实现

本文是对图像文字识别的简单实现所做,并没有深入研究。本程序所实现的app对楷体字识别最有效。例如要识别在一张白纸上的“中国”二个楷体黑字,使用手机摄像头先进行扫描识别,然后自动翻译为“China”,再将“中国”和“China”显示到屏幕上,本文主要研究如何实现这个系统框架。

本文地址:http://blog.csdn.net/yang786654260/article/category/5710631

程序源码下载地址:本代码年代久远, 而且学生时代的代码水平很糟糕,就不分享了,大意就是用zxing来拿图识字。

工作流程

Android文字图像识别并翻译的简单实现

流程描述:

环境光亮的情况下,经过摄像头扫描固定矩形区域图像,这样可以避免让手机对图像做截图处理,通过zxing辅助包在避免内存溢出的情况下获取到文字区域图像,进而对图像进行灰度化、去噪、二值化,如果判断黑色值像素数多于白色值像素度则进行反色处理,最后对图像切分提取特征值,将特征值传入谷歌ocr文字识别辅助包对谷歌识别库进行检索,查出相似值后,再通过辅助包提取识别库中的文字。本文为了减少Android系统的cpu使用度,将翻译交给了百度服务器处理,把提取到的文字上传到百度服务器,之后再服务器上翻译并返回结果。

使用的第三方库

  • zxing
  • 谷歌ocr(tesseract ocr)

界面展示

主界面:

Android文字图像识别并翻译的简单实现

扫描界面:

Android文字图像识别并翻译的简单实现

说说几个图像处理算法

灰度化本文采取的是浮点算法,实现代码如下

private static Bitmap getGrayImg() {
        int alpha =  << ;  //设置透明度
        for (int i = ; i < imgTheHeight; i++) {
            for (int j = ; j < imgTheWidth; j++) {
//获得第i行第j个的像素点
                int grey = imgThePixels[imgTheWidth * i + j];               
int red = ((grey & ) >> );  //获取红色灰度值
                int green = ((grey & ) >> ); //获取绿色灰度值
                int blue = (grey & );         //获取蓝色灰度值
//浮点算法获取灰度化色值
        grey = (int) ((float) red *  + (float) green *  + (float) blue * );          grey = alpha | (grey << ) | (grey << ) | grey; //添加透明度
        imgThePixels[imgTheWidth * i + j] = grey;   //更改像素色值
        }
Bitmap result = 
Bitmap.createBitmap(imgTheWidth, imgTheHeight, Config.RGB_565);
result.setPixels(imgThePixels, , imgTheWidth, , , imgTheWidth, imgTheHeight);
        return result;
    }
方法 setPixels(int[] pixels, int offset, int STiRe, int xxx, int yyy, int theWidth, int theHeight)为设置位图像素点灰度值,参数如下:参数 pixels 写入位图的颜色数组;参数 offset 写入的第一个颜色索引;参数 STiRe 行宽;参数 xxx写入位图的第一个像素的x坐标;参数 yyy写入位图的 第一个像素的y坐标;参数 theWidth一行的像素数量;参数theHeight写入的行数。
           

图像去除噪点本文使用的算法是取区域像素中值的方法进行去噪

Android文字图像识别并翻译的简单实现

本文中采取的是3 乘以 3的表格区域取中值的方法,如上表所示,pix[0~8]是一个一维的像素值序列,中心点为pix[4]。这个算法最简便的方法是把这9个像素进行排序,然后取中间值,再存入pix[4]即中心点。实现代码如下:

private static int getCenterValue(Bitmap img, int x, int y) {
        int[] pix = new int[]; //该点以及周围8个点共9个点
        int h = img.getHeight() - ; //获取高度像素值
        int w = img.getWidth() - ; //获取宽度像素值
        if (x >  && y > ) //如果点不再上边框和左边框,则存在pix[0]
            pix[] = getGray(img.getPixel(x - , y - ));
        if (y > )  //如果点不是上边框,则存在pix[1]
            pix[] = getGray(img.getPixel(x, y - ));
        if (x < h && y > ) //如果点不是右边框和上边框,则存在pix[2]
            pix[] = getGray(img.getPixel(x + , y - ));
        if (x > ) //如果点不是左边框,则存在pix[3]
            pix[] = getGray(img.getPixel(x - , y));
        pix[] = getGray(img.getPixel(x, y)); //pix[4]为要获取中值的点
        if (x < h) //如果没在右边框,则存在pix[5]
            pix[] = getGray(img.getPixel(x + , y));
        if (x >  && y < w) //如果没在上边框和有边框,则存在pix[6]
            pix[] = getGray(img.getPixel(x - , y + ));
        if (y < w) //如果没在右边框,则存在pix[7]
            pix[] = getGray(img.getPixel(x, y + ));
        if (x < h && y < w) //如果没在右边框和下边框,则存在pix[8]
            pix[] = getGray(img.getPixel(x + , y + ));
        int max = , min = ;
        for (int i = ; i < pix.length; i++) {
            if (pix[i] > max)
                max = pix[i];
            if (pix[i] < min)
                min = pix[i];
        }
        int count = ;
        int i = ;
        for (i = ; i < ; i++) {
            if (pix[i] >= min)
                count++;
            if (count == )
                break;
        }
        return pix[i];
    }
           

二值化处理

大律法

private static int getOtsuHresholdValue(int minOwnGrayValue, int maxOwnGrayValue) {
        int T = ;
        double U = , U0 = , U1 = ;
        double G = ;
        for (int i = minOwnGrayValue; i <= maxOwnGrayValue; i++) {
            double s = , l = , cs = , cl = ;
            for (int j = ; j < imgTheHeight - ; j++) {
                for (int k = ; k < imgTheWidth - ; k++) {
                    int gray = imgThePixels[J  *  imgTheWidth + k];
                    if (gray < i) 
                        {s += gray;
                        cs++;}
                    if (gray > i) 
                        {l += gray;
                        cl++;}
                }
            }
            U0 = s / cs;
            U1 = l / cl;
            U = (s + l) / (cs + cl);
            double g = (cs / (cs + cl)) * (U0 - U) * (U0 - U)
                    + (cl / (cl + cs)) * (U1 - U) * (U1 - U);
            if (g > G) {
                T = i;
                G = g;
            }
        }
        return T;   
}
           

迭代法

首先需要获得中值:
T = (maxGrayValue + minGrayValue) / ;   公式(-)
maxGrayValue指的是最大灰度值;minGrayValue指的是最小灰度值。
将T视为阈值,大于T的为目标部分,小于T的为背景部分。再分别获取目标和背景的像素色值平均值T1和T2,获取新的阈值(T1+T2)/;将新的阈值赋值给T重复获取新阈值,直到两个阈值一样而且连续的时候,将该阈值视为最终获取的阈值。实现代码如下:
private static int getIterationHresholdValue(int minGrayValue,
            int maxGrayValue) {
        int T1;
        int T2 = (maxGrayValue + minGrayValue) / ;
        do {
            T1 = T2;
            double s = , l = , cs = , cl = ;
            for (int i = ; i < imgTheHeight; i++) {
                for (int j = ; j < imgTheWidth; j++) {
                    int gray = imgThePixels[I * imgTheWidth + j];
                    if (gray < T1)
                        {s += gray;
                        cs++;}
                    if (gray > T1) 
                        {l += gray;
                        cl++;}
                    }
            }
            T2 = (int) (s / cs + l / cl) / ;
        } while (T1 != T2);
        return T1;
}
           

反色处理

nt pixel = ;
        for (int i = ; i < imgTheHeight; i++) {
            for (int j = ; j < imgTheWidth; j++) {
                pixel = 
(imgThePixels[i*imgTheWidth + j] > T) ? (imgThePixels[i*imgTheWidth + j] = )
 : (imgThePixels[i*imgTheWidth + j] = );
            }
        }
Bitmap result=
Bitmap.createBitmap(imgTheWidth,imgTheHeight, Config.RGB_565);
result.setPixels(imgThePixels, , imgTheWidth, , , imgTheWidth, imgTheHeight);
           

Android端的一些实现

获取联网状态

public boolean isNetworkConnected(Context context) 
{ 
if (context != null) 
{ 
ConnectivityManager mConnectivityManager 
= (ConnectivityManager) context 
.getSystemService(Context.CONNECTIVITY_SERVICE); 
NetworkInfo mNetworkInfo 
= mConnectivityManager.getActiveNetworkInfo(); 
if (mNetworkInfo != null) 
return mNetworkInfo.isAvailable();
} 
return false; 
}
//返回true则正在联网状态中,返回false则处于断网的状态下,这时要提示用户连接网络。
           

使用百度翻译

public static final String BAIDU_LINK 
= "http://openapi.baidu.com/public/2.0/bmt/translate?";
//具体请自行百度
           

总结

本app完全走了捷径,用了前人已有的项目做了些修改并使用,因为对这些并没有透彻的研究,所以,嗯哼,只能这个效果了。以后有研究的话,再探讨。

程序源码下载地址:本代码年代久远, 而且学生时代的代码水平很糟糕,就不分享了,大意就是用zxing来拿图识字。