我正在制作适用于Android的OCR应用,它会截取一些文字,识别它并在Google上搜索关键字。如果你还没有意识到,那我就试图制作一个" Google Now on Tap"克隆
为了使OCR更好地工作,我首先旋转图像,然后过滤图像。首先删除状态栏和导航栏,然后将其转换为灰度,然后进行锐化。
但是过滤图像后的图像质量极其像素化,这极大地影响了OCR的准确性。
以下是图片,之前和之后(仅我收到的IFTTT电子邮件)
正如您所看到的,之前的图像质量远高于过滤和旋转的图像。
以下是我的旋转,过滤和保存图片的代码:
首先截屏,然后保存屏幕截图。
public void getScreenshot()
{
try
{
Process sh = Runtime.getRuntime().exec("su", null, null);
OutputStream os = sh.getOutputStream();
os.write(("/system/bin/screencap -p " + _path).getBytes("ASCII"));
os.flush();
os.close();
sh.waitFor();
onPhotoTaken();
Toast.makeText(this, "Screenshot taken", Toast.LENGTH_SHORT).show();
}
catch (IOException e)
{
System.out.println("IOException");
}
catch (InterruptedException e)
{
System.out.println("InterruptedException");
}
}
然后,旋转图像:
protected void onPhotoTaken() {
_taken = true;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
Bitmap bitmap = BitmapFactory.decodeFile(_path, options);
try {
ExifInterface exif = new ExifInterface(_path);
int exifOrientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
Log.v(TAG, "Orient: " + exifOrientation);
int rotate = 0;
switch (exifOrientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
}
Log.v(TAG, "Rotation: " + rotate);
if (rotate != 0) {
// Getting width & height of the given image.
int w = bitmap.getWidth();
int h = bitmap.getHeight();
// Setting pre rotate
Matrix mtx = new Matrix();
mtx.preRotate(rotate);
// Rotating Bitmap
bitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, false);
}
// Convert to ARGB_8888, required by tess
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
} catch (IOException e) {
Log.e(TAG, "Couldn't correct orientation: " + e.toString());
}
// _image.setImageBitmap( bitmap );
setImageFilters(bitmap);
}

然后,过滤图像:
public void setImageFilters(Bitmap bmpOriginal)
{
//Start by cropping image
Bitmap croppedBitmap = ThumbnailUtils.extractThumbnail(bmpOriginal, 1080, 1420);
//Then convert to grayscale
int width, height;
height = 1420;
width = 1080;
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(croppedBitmap, 0, 0, paint);
//Finally, sharpen the image
double weight = 11;
double[][] sharpConfig = new double[][]
{
{ 0 , -2 , 0 },
{ -2, weight, -2 },
{ 0 , -2 , 0 }
};
ConvolutionMatrix convMatrix = new ConvolutionMatrix(3);
convMatrix.applyConfig(sharpConfig);
convMatrix.Factor = weight - 8;
Bitmap filteredBitmap = ConvolutionMatrix.computeConvolution3x3(bmpGrayscale, convMatrix);
//Start Optical Character Recognition
startOCR(filteredBitmap);
//Save filtered image
saveFiltered(filteredBitmap);
}
然后,保存已过滤和旋转的图像:
public void saveFiltered(Bitmap filteredBmp) {
try {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
filteredBmp.compress(Bitmap.CompressFormat.JPEG, 20, bytes);
//You can create a new file name "test.jpg" in sdcard folder.
File f = new File("/sdcard/SimpleAndroidOCR/ocrgray.jpg");
f.createNewFile();
//Write the bytes in file
FileOutputStream fo = new FileOutputStream(f);
fo.write(bytes.toByteArray());
//Remember close the FileOutput
fo.close();
} catch (Exception e) {
e.printStackTrace();
}
}
感谢大家花时间提供帮助。
答案 0 :(得分:1)
看起来像jpeg压缩正在弄乱图像。尝试使用更适合具有锐边的图像的格式,例如文本。我会推荐png甚至是gif。您还可以存储未压缩的BMP。
Jpeg压缩的工作原理是,在大多数图片(自然,人物,物体)中,锐利的边缘对于人眼来说是不可见的。这使得存储锋利边缘内容(例如文本)非常糟糕。
此外,您的图像滤镜有效地消除了图像的抗锯齿,这进一步降低了感知的图像质量。然而,可能是您想要做的,因为它可能使OCR更容易。
由于您上传的图片在网站上的尺寸相同,我也错过了采样尺寸。来自Android documentation:
如果设置为值> 1,请求解码器对原始进行二次采样 图像,返回较小的图像以节省内存。样本量是 任一维度中对应于单个像素的像素数 解码后的位图中的像素。例如,inSampleSize == 4返回一个 图像是原稿宽度/高度的1/4,和1/16 像素数。任何值< = 1都被视为1.注意: 解码器使用基于2的幂的最终值,任何其他值都将 向下舍入到最接近2的幂。
将options.inSampleSize = 4;
设置为1
会提高质量。