最近工作中遇到身份证上次需要验证问题,在网上搜索了大量信息,大概都是用tess-two库实现,但识别率不是很高,在它基础上,做了点优化,识别率比它高那么点
所做的优化方式就是,对图片进行二值化以及灰度化,然后再获取图片上的信息,至少能获取到身份证号码,其他中文字实在是无法匹配。
编程工具为:eclipse
首先需要做的步骤是:1、有下载tess-two库,当然,需要包括.so文件的,不然你还需要编译一遍,编译步骤需要在网上找,在上篇文章中写了编译过程中出现的问题,可以借鉴下, 现在提供下未做修改的代码下载地址:http://download.csdn.net/detail/a1031359915/9523864
2、将chi_sim.traineddata文件拷贝到/mnt/sdcard/tesseract/目录下。
下面是优化的代码:
import java.io.File;
import com.googlecode.tesseract.android.TessBaseAPI;
import com.googlecode.tesseract.android.test.R;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;
public class TestActivity extends Activity {
private static final String TESSBASE_PATH = "/mnt/sdcard/tesseract/";
private static final String DEFAULT_LANGUAGE = "eng";
private static final String CHINESE_LANGUAGE = "chi_sim"; // chi_tra chi_sim
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
ImageView img = (ImageView) findViewById(R.id.img);
TessBaseAPI baseApi = new TessBaseAPI();
baseApi.init(TESSBASE_PATH, CHINESE_LANGUAGE);
// baseApi.setPageSegMode(TessBaseAPI.PageSegMode.PSM_AUTO);
// File file = new File("/mnt/sdcard/sf.jpg");
// if (file.exists()){
// baseApi.setImage(file);
// }
Bitmap bitmap = BitmapFactory.decodeFile("/mnt/sdcard/sf.jpg");
bitmap = ImageFilter.gray2Binary(bitmap);// 图片二值化
bitmap = ImageFilter.grayScaleImage(bitmap);// 图片灰度化
img.setImageBitmap(bitmap);
baseApi.setImage(bitmap);
// Ensure that the result is correct.
final String outputText = baseApi.getUTF8Text();
TextView view = (TextView) findViewById(R.id.tv_test);
view.setText(outputText);
baseApi.end();
}
}
图片处理类:
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.util.Log;
public class ImageFilter {
// 图像灰度化
public static Bitmap bitmap2Gray(Bitmap bmSrc) {
// 得到图片的长和宽
int width = bmSrc.getWidth();
int height = bmSrc.getHeight();
// 创建目标灰度图像
Bitmap bmpGray = null;
bmpGray = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
// 创建画布
Canvas c = new Canvas(bmpGray);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmSrc, 0, 0, paint);
return bmpGray;
}
// 图像灰度化
public static Bitmap grayScaleImage(Bitmap src) {
// constant factors
final double GS_RED = 0.299;
final double GS_GREEN = 0.587;
final double GS_BLUE = 0.114;
// final double GS_RED = 0.235;
// final double GS_GREEN = 0.589;
// final double GS_BLUE = 0.119;
// create output bitmap
Bitmap bmOut = Bitmap.createBitmap(src.getWidth(), src.getHeight(), src.getConfig());
// pixel information
int A, R, G, B;
int pixel;
// get image size
int width = src.getWidth();
int height = src.getHeight();
// scan through every single pixel
for(int x = 0; x < width; ++x) {
for(int y = 0; y < height; ++y) {
// get one pixel color
pixel = src.getPixel(x, y);
// retrieve color of all channels
A = Color.alpha(pixel);
R = Color.red(pixel);
G = Color.green(pixel);
B = Color.blue(pixel);
// take conversion up to one single value
R = G = B = (int)(GS_RED * R + GS_GREEN * G + GS_BLUE * B);
// set new pixel color to output bitmap
bmOut.setPixel(x, y, Color.argb(A, R, G, B));
}
}
// return final image
return bmOut;
}
// 对图像进行线性灰度变化
public static Bitmap lineGrey(Bitmap image) {
// 得到图像的宽度和长度
int width = image.getWidth();
int height = image.getHeight();
// 创建线性拉升灰度图像
Bitmap linegray = null;
linegray = image.copy(Config.ARGB_8888, true);
// 依次循环对图像的像素进行处理
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
// 得到每点的像素值
int col = image.getPixel(i, j);
int alpha = col & 0xFF000000;
int red = (col & 0x00FF0000) >> 16;
int green = (col & 0x0000FF00) >> 8;
int blue = (col & 0x000000FF);
// 增加了图像的亮度
red = (int) (1.1 * red + 30);
green = (int) (1.1 * green + 30);
blue = (int) (1.1 * blue + 30);
// 对图像像素越界进行处理
if (red >= 255) {
red = 255;
}
if (green >= 255) {
green = 255;
}
if (blue >= 255) {
blue = 255;
}
// 新的ARGB
int newColor = alpha | (red << 16) | (green << 8) | blue;
// 设置新图像的RGB值
linegray.setPixel(i, j, newColor);
}
}
return linegray;
}
// 该函数实现对图像进行二值化处理
public static Bitmap gray2Binary(Bitmap graymap) {
// 得到图形的宽度和长度
int width = graymap.getWidth();
int height = graymap.getHeight();
// 创建二值化图像
Bitmap binarymap = null;
binarymap = graymap.copy(Config.ARGB_8888, true);
// 依次循环,对图像的像素进行处理
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
// 得到当前像素的值
int col = binarymap.getPixel(i, j);
// 得到alpha通道的值
int alpha = col & 0xFF000000;
// 得到图像的像素RGB的值
int red = (col & 0x00FF0000) >> 16;
int green = (col & 0x0000FF00) >> 8;
int blue = (col & 0x000000FF);
// 用公式X = 0.3×R+0.59×G+0.11×B计算出X代替原来的RGB
int gray = (int) ((float) red * 0.3 + (float) green * 0.59 + (float) blue * 0.11);
// 对图像进行二值化处理
if (gray <= 95) {
gray = 0;
} else {
gray = 255;
}
// 新的ARGB
int newColor = alpha | (gray << 16) | (gray << 8) | gray;
// 设置新图像的当前像素值
binarymap.setPixel(i, j, newColor);
}
}
return binarymap;
}
/**
* 将彩色图转换为黑白图
*
* @param 位图
* @return 返回转换好的位图
*/
public static Bitmap convertToBlackWhite(Bitmap bmp) {
int width = bmp.getWidth(); // 获取位图的宽
int height = bmp.getHeight(); // 获取位图的高
int[] pixels = new int[width * height]; // 通过位图的大小创建像素点数组
bmp.getPixels(pixels, 0, width, 0, 0, width, height);
int alpha = 0xFF << 24;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int grey = pixels[width * i + j];
int red = ((grey & 0x00FF0000) >> 16);
int green = ((grey & 0x0000FF00) >> 8);
int blue = (grey & 0x000000FF);
grey = (int) (red * 0.3 + green * 0.59 + blue * 0.11);
grey = alpha | (grey << 16) | (grey << 8) | grey;
pixels[width * i + j] = grey;
}
}
Bitmap newBmp = Bitmap.createBitmap(width, height, Config.ARGB_8888);
newBmp.setPixels(pixels, 0, width, 0, 0, width, height);
return newBmp;
}
/**
* 图片锐化(拉普拉斯变换)
*
* @param bmp
* @return
*/
public static Bitmap sharpenImageAmeliorate(Bitmap bmp) {
// 拉普拉斯矩阵
int[] laplacian = new int[] { -1, -1, -1, -1, 9, -1, -1, -1, -1 };
int width = bmp.getWidth();
int height = bmp.getHeight();
Bitmap bitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
int pixR = 0;
int pixG = 0;
int pixB = 0;
int pixColor = 0;
int newR = 0;
int newG = 0;
int newB = 0;
int idx = 0;
float alpha = 0.3F;
int[] pixels = new int[width * height];
bmp.getPixels(pixels, 0, width, 0, 0, width, height);
for (int i = 1, length = height - 1; i < length; i++) {
for (int k = 1, len = width - 1; k < len; k++) {
idx = 0;
for (int m = -1; m <= 1; m++) {
for (int n = -1; n <= 1; n++) {
pixColor = pixels[(i + n) * width + k + m];
pixR = Color.red(pixColor);
pixG = Color.green(pixColor);
pixB = Color.blue(pixColor);
newR = newR + (int) (pixR * laplacian[idx] * alpha);
newG = newG + (int) (pixG * laplacian[idx] * alpha);
newB = newB + (int) (pixB * laplacian[idx] * alpha);
idx++;
}
}
newR = Math.min(255, Math.max(0, newR));
newG = Math.min(255, Math.max(0, newG));
newB = Math.min(255, Math.max(0, newB));
pixels[i * width + k] = Color.argb(255, newR, newG, newB);
newR = 0;
newG = 0;
newB = 0;
}
}
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
return bitmap;
}
}
xml文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#000000"
android:text="sdfjahk"/>
<ImageView
android:id="@+id/img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/icon"/>
</LinearLayout>
至此,身份证号码应该能获取到,再声明下,识别率不是很好,希望能有大神能够完善下,谢谢!