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

本文介绍了一款基于Android平台的图像文字识别应用实现过程。利用zxing进行图像处理,结合谷歌OCR实现文字识别,并借助百度翻译API完成翻译功能。文章详细介绍了图像灰度化、去噪、二值化等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文章已经生成可运行项目,

本文是对图像文字识别的简单实现所做,并没有深入研究。本程序所实现的app对楷体字识别最有效。例如要识别在一张白纸上的“中国”二个楷体黑字,使用手机摄像头先进行扫描识别,然后自动翻译为“China”,再将“中国”和“China”显示到屏幕上,本文主要研究如何实现这个系统框架。
本文地址:http://blog.youkuaiyun.com/yang786654260/article/category/5710631
程序源码下载地址:本代码年代久远, 而且学生时代的代码水平很糟糕,就不分享了,大意就是用zxing来拿图识字。

工作流程

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

使用的第三方库

  • zxing
  • 谷歌ocr(tesseract ocr)

界面展示

主界面:
这里写图片描述

扫描界面:
这里写图片描述

说说几个图像处理算法

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

private static Bitmap getGrayImg() {
        int alpha = 0xFF << 24;  //设置透明度
        for (int i = 0; i < imgTheHeight; i++) {
            for (int j = 0; j < imgTheWidth; j++) {
//获得第i行第j个的像素点
                int grey = imgThePixels[imgTheWidth * i + j];               
int red = ((grey & 0x00FF0000) >> 16);  //获取红色灰度值
                int green = ((grey & 0x0000FF00) >> 8); //获取绿色灰度值
                int blue = (grey & 0x000000FF);         //获取蓝色灰度值
//浮点算法获取灰度化色值
        grey = (int) ((float) red * 0.3 + (float) green * 0.59 + (float) blue * 0.11);          grey = alpha | (grey << 16) | (grey << 8) | grey; //添加透明度
        imgThePixels[imgTheWidth * i + j] = grey;   //更改像素色值
        }
Bitmap result = 
Bitmap.createBitmap(imgTheWidth, imgTheHeight, Config.RGB_565);
result.setPixels(imgThePixels, 0, imgTheWidth, 0, 0, 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写入的行数。

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

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

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

二值化处理

大律法
private static int getOtsuHresholdValue(int minOwnGrayValue, int maxOwnGrayValue) {
        int T = 0;
        double U = 0, U0 = 0, U1 = 0;
        double G = 0;
        for (int i = minOwnGrayValue; i <= maxOwnGrayValue; i++) {
            double s = 0, l = 0, cs = 0, cl = 0;
            for (int j = 0; j < imgTheHeight - 1; j++) {
                for (int k = 0; k < imgTheWidth - 1; 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) / 2;   公式(2-5)
maxGrayValue指的是最大灰度值;minGrayValue指的是最小灰度值。
将T视为阈值,大于T的为目标部分,小于T的为背景部分。再分别获取目标和背景的像素色值平均值T1和T2,获取新的阈值(T1+T2)/2;将新的阈值赋值给T重复获取新阈值,直到两个阈值一样而且连续的时候,将该阈值视为最终获取的阈值。实现代码如下:
private static int getIterationHresholdValue(int minGrayValue,
            int maxGrayValue) {
        int T1;
        int T2 = (maxGrayValue + minGrayValue) / 2;
        do {
            T1 = T2;
            double s = 0, l = 0, cs = 0, cl = 0;
            for (int i = 0; i < imgTheHeight; i++) {
                for (int j = 0; 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) / 2;
        } while (T1 != T2);
        return T1;
}

反色处理

nt pixel = 0;
        for (int i = 0; i < imgTheHeight; i++) {
            for (int j = 0; j < imgTheWidth; j++) {
                pixel = 
(imgThePixels[i*imgTheWidth + j] > T) ? (imgThePixels[i*imgTheWidth + j] = 0)
 : (imgThePixels[i*imgTheWidth + j] = 255);
            }
        }
Bitmap result=
Bitmap.createBitmap(imgTheWidth,imgTheHeight, Config.RGB_565);
result.setPixels(imgThePixels, 0, imgTheWidth, 0, 0, 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来拿图识字。

本文章已经生成可运行项目
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值